Compare commits

..

3 Commits

Author SHA1 Message Date
Eelco Dolstra
29fd60131b * Add a primop to return the context of a string. 2010-01-31 20:54:44 +00:00
Eelco Dolstra
6d1abdc6d9 * In string contexts containing derivations
(e.g. "${somePkg}/bin/foo"), store the original derivation
  expression in the context.
2010-01-31 20:08:57 +00:00
Eelco Dolstra
25fc95d56d 2010-01-31 20:06:58 +00:00
329 changed files with 9400 additions and 12029 deletions

149
.gitignore vendored
View File

@@ -1,149 +0,0 @@
Makefile
Makefile.in
# /
/aclocal.m4
/autom4te.cache
/config.*
/configure
/nix.spec
/stamp-h1
/svn-revision
/NEWS
/libtool
# /config/
/config/config.guess
/config/config.sub
/config/depcomp
/config/install-sh
/config/missing
/config/mkinstalldirs
/config/ltmain.sh
/corepkgs/config.nix
# /corepkgs/buildenv/
/corepkgs/buildenv/builder.pl
# /corepkgs/channels/
/corepkgs/channels/unpack.sh
# /corepkgs/nar/
/corepkgs/nar/nar.sh
/corepkgs/nar/unnar.sh
# /doc/manual/
/doc/manual/manual.html
/doc/manual/manual.is-valid
/doc/manual/*.1
/doc/manual/*.8
/doc/manual/images
/doc/manual/version.txt
/doc/manual/NEWS.html
/doc/manual/NEWS.txt
# /scripts/
/scripts/nix-profile.sh
/scripts/nix-pull
/scripts/nix-push
/scripts/nix-switch
/scripts/nix-collect-garbage
/scripts/nix-prefetch-url
/scripts/nix-install-package
/scripts/nix-channel
/scripts/nix-build
/scripts/nix-copy-closure
/scripts/nix-generate-patches
/scripts/NixConfig.pm
/scripts/NixManifest.pm
/scripts/GeneratePatches.pm
/scripts/download-using-manifests.pl
/scripts/copy-from-other-stores.pl
/scripts/find-runtime-roots.pl
/scripts/build-remote.pl
/scripts/nix-reduce-build
/scripts/nix-http-export.cgi
# /src/bin2c/
/src/bin2c/bin2c
# /src/bsdiff-4.3/
/src/bsdiff-4.3/bsdiff
/src/bsdiff-4.3/bspatch
# /src/libexpr/
/src/libexpr/lexer-tab.cc
/src/libexpr/lexer-tab.hh
/src/libexpr/parser-tab.cc
/src/libexpr/parser-tab.hh
/src/libexpr/parser-tab.output
/src/libexpr/nixexpr-ast.hh
/src/libexpr/nixexpr-ast.cc
/src/libexpr/nix.tbl
# /src/libstore/
/src/libstore/derivations-ast.cc
/src/libstore/derivations-ast.hh
/src/libstore/schema.sql.hh
# /src/nix-env/
/src/nix-env/nix-env
/src/nix-env/help.txt.hh
# /src/nix-hash/
/src/nix-hash/nix-hash
/src/nix-hash/help.txt.hh
# /src/nix-instantiate/
/src/nix-instantiate/nix-instantiate
/src/nix-instantiate/help.txt.hh
# /src/nix-log2xml/
/src/nix-log2xml/nix-log2xml
/src/nix-log2xml/test*.*
/src/nix-log2xml/*.log
/src/nix-log2xml/*.xml
/src/nix-log2xml/*.html
# /src/nix-setuid-helper/
/src/nix-setuid-helper/nix-setuid-helper
/src/nix-setuid-helper/help.txt.hh
# /src/nix-store/
/src/nix-store/help.txt.hh
/src/nix-store/nix-store
# /src/nix-worker/
/src/nix-worker/nix-worker
/src/nix-worker/help.txt.hh
# /tests/
/tests/test-tmp
/tests/config.nix
/tests/common.sh
/tests/dummy
/tests/result*
# /tests/lang/
/tests/lang/*.out
/tests/lang/*.out.xml
/tests/lang/*.ast
/perl/lib/Nix/Config.pm
/perl/lib/Nix/Store.cc
.deps
.libs
*.a
*.lo
*.la
*.o
*.so
*~
# GNU Global
GPATH
GRTAGS
GSYMS
GTAGS

0
ChangeLog Normal file
View File

View File

@@ -1,9 +1,7 @@
SUBDIRS = src perl scripts corepkgs doc misc tests
SUBDIRS = externals src scripts corepkgs doc misc tests
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
nix.conf.example NEWS version
pkginclude_HEADERS = config.h
include ./substitute.mk
nix.spec: nix.spec.in
@@ -33,7 +31,7 @@ init-state:
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/temproots
ln -sfn $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/userpool
-$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(storedir)
-$(INSTALL) $(INIT_FLAGS) -m 1777 -d $(DESTDIR)$(storedir)
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests

117
aterm-gc.supp Normal file
View File

@@ -0,0 +1,117 @@
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr4
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr8
fun:*
fun:AT_collect_minor
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr4
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Addr8
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value4
fun:*
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Value8
fun:*
fun:*
fun:AT_collect
}
{
ATerm library conservatively scans for GC roots
Memcheck:Cond
fun:*
fun:*
fun:AT_collect
}

252
blacklisting/check-env.pl Executable file
View File

@@ -0,0 +1,252 @@
#! /usr/bin/perl -w -I /home/eelco/.nix-profile/lib/site_perl
use strict;
use XML::LibXML;
#use XML::Simple;
my $blacklistFN = shift @ARGV;
die unless defined $blacklistFN;
my $userEnv = shift @ARGV;
die unless defined $userEnv;
# Read the blacklist.
my $parser = XML::LibXML->new();
my $blacklist = $parser->parse_file($blacklistFN)->getDocumentElement;
#print $blacklist->toString() , "\n";
# Get all the elements of the user environment.
my $userEnvElems = `nix-store --query --references '$userEnv'`;
die "cannot query user environment elements" if $? != 0;
my @userEnvElems = split ' ', $userEnvElems;
my %storePathHashes;
sub getElemNodes {
my $node = shift;
my @elems = ();
foreach my $node ($node->getChildNodes) {
push @elems, $node if $node->nodeType == XML_ELEMENT_NODE;
}
return @elems;
}
my %referencesCache;
sub getReferences {
my $path = shift;
return $referencesCache{$path} if defined $referencesCache{$path};
my $references = `nix-store --query --references '$path'`;
die "cannot query references" if $? != 0;
$referencesCache{$path} = [split ' ', $references];
return $referencesCache{$path};
}
my %attrsCache;
sub getAttr {
my $path = shift;
my $name = shift;
my $key = "$path/$name";
return $referencesCache{$key} if defined $referencesCache{$key};
my $value = `nix-store --query --binding '$name' '$path' 2> /dev/null`;
$value = "" if $? != 0; # !!!
chomp $value;
$referencesCache{$key} = $value;
return $value;
}
sub evalCondition;
sub traverse {
my $done = shift;
my $set = shift;
my $path = shift;
my $stopCondition = shift;
return if defined $done->{$path};
$done->{$path} = 1;
$set->{$path} = 1;
# print " in $path\n";
if (!evalCondition({$path => 1}, $stopCondition)) {
# print " STOPPING in $path\n";
return;
}
# Get the requisites of the deriver.
foreach my $reference (@{getReferences $path}) {
traverse($done, $set, $reference, $stopCondition);
}
}
sub evalSet {
my $inSet = shift;
my $expr = shift;
my $name = $expr->getName;
if ($name eq "traverse") {
my $stopCondition = (getElemNodes $expr)[0];
my $done = { };
my $set = { };
foreach my $path (keys %{$inSet}) {
traverse($done, $set, $path, $stopCondition);
}
return $set;
}
else {
die "unknown element `$name'";
}
}
# Function for evaluating conditions.
sub evalCondition {
my $storePaths = shift;
my $condition = shift;
my $elemName = $condition->getName;
if ($elemName eq "containsSource") {
my $hash = $condition->attributes->getNamedItem("hash")->getValue;
foreach my $path (keys %{$storePathHashes{$hash}}) {
return 1 if defined $storePaths->{$path};
}
return 0;
}
elsif ($elemName eq "hasName") {
my $nameRE = $condition->attributes->getNamedItem("name")->getValue;
foreach my $path (keys %{$storePaths}) {
return 1 if $path =~ /$nameRE/;
}
return 0;
}
elsif ($elemName eq "hasAttr") {
my $name = $condition->attributes->getNamedItem("name")->getValue;
my $valueRE = $condition->attributes->getNamedItem("value")->getValue;
foreach my $path (keys %{$storePaths}) {
if ($path =~ /\.drv$/) {
my $value = getAttr($path, $name);
# print " $path $name $value\n";
return 1 if $value =~ /$valueRE/;
}
}
return 0;
}
elsif ($elemName eq "and") {
my $result = 1;
foreach my $node (getElemNodes $condition) {
$result &= evalCondition($storePaths, $node);
}
return $result;
}
elsif ($elemName eq "not") {
return !evalCondition($storePaths, (getElemNodes $condition)[0]);
}
elsif ($elemName eq "within") {
my @elems = getElemNodes $condition;
my $set = evalSet($storePaths, $elems[0]);
return evalCondition($set, $elems[1]);
}
elsif ($elemName eq "true") {
return 1;
}
elsif ($elemName eq "false") {
return 0;
}
else {
die "unknown element `$elemName'";
}
}
sub evalOr {
my $storePaths = shift;
my $nodes = shift;
my $result = 0;
foreach my $node (@{$nodes}) {
$result |= evalCondition($storePaths, $node);
}
return $result;
}
# Iterate over all elements, check them.
foreach my $userEnvElem (@userEnvElems) {
# Get the deriver of this path.
my $deriver = `nix-store --query --deriver '$userEnvElem'`;
die "cannot query deriver" if $? != 0;
chomp $deriver;
if ($deriver eq "unknown-deriver") {
# print " deriver unknown, cannot check sources\n";
next;
}
print "CHECKING $userEnvElem\n";
# Get the requisites of the deriver.
# my $requisites = `nix-store --query --requisites --include-outputs '$deriver'`;
# die "cannot query requisites" if $? != 0;
# my @requisites = split ' ', $requisites;
# Get the hashes of the requisites.
# my $hashes = `nix-store --query --hash @requisites`;
# die "cannot query hashes" if $? != 0;
# my @hashes = split ' ', $hashes;
# for (my $i = 0; $i < scalar @requisites; $i++) {
# die unless $i < scalar @hashes;
# my $hash = $hashes[$i];
# $storePathHashes{$hash} = {} unless defined $storePathHashes{$hash};
# my $r = $storePathHashes{$hash}; # !!! fix
# $$r{$requisites[$i]} = 1;
# }
# Evaluate each blacklist item.
foreach my $item ($blacklist->getChildrenByTagName("item")) {
my $itemId = $item->getAttributeNode("id")->getValue;
# print " CHECKING FOR $itemId\n";
my $condition = ($item->getChildrenByTagName("condition"))[0];
die unless $condition;
# Evaluate the condition.
my @elems = getElemNodes $condition;
if (evalOr({$deriver => 1}, \@elems)) {
# Oops, condition triggered.
my $reason = ($item->getChildrenByTagName("reason"))[0]->getChildNodes->to_literal;
$reason =~ s/\s+/ /g;
$reason =~ s/^\s+//g;
print " VULNERABLE TO `$itemId': $reason\n";
}
}
}

View File

@@ -1,4 +1,7 @@
#! /bin/sh -e
rm -f aclocal.m4
mkdir -p config
exec autoreconf -vfi
libtoolize --copy
aclocal
autoheader
automake --add-missing --copy
autoconf

View File

@@ -5,33 +5,30 @@ AM_INIT_AUTOMAKE([dist-bzip2 foreign])
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [Nix version.])
AC_PROG_SED
AC_CANONICAL_HOST
# Construct a Nix system name (like "i686-linux").
AC_CANONICAL_HOST
AC_MSG_CHECKING([for the canonical Nix system name])
cpu_name=$(uname -p | tr 'A-Z ' 'a-z_')
machine_name=$(uname -m | tr 'A-Z ' 'a-z_')
AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
[Platform identifier (e.g., `i686-linux').]),
[system=$withval],
[case "$host_cpu" in
i*86)
machine_name="i686";;
amd64)
machine_name="x86_64";;
*)
machine_name="$host_cpu";;
esac
case "$host_os" in
linux-gnu*)
# For backward compatibility, strip the `-gnu' part.
system="$machine_name-linux";;
*)
# Strip the version number from names such as `gnu0.3',
# `darwin10.2.0', etc.
system="$machine_name-`echo $host_os | "$SED" -e's/@<:@0-9.@:>@*$//g'`";;
esac])
case $machine_name in
i*86)
machine_name=i686
;;
x86_64)
machine_name=x86_64
;;
ppc)
machine_name=powerpc
;;
*)
if test "$cpu_name" != "unknown"; then
machine_name=$cpu_name
fi
;;
esac
sys_name=$(uname -s | tr 'A-Z ' 'a-z_')
@@ -40,7 +37,10 @@ case $sys_name in
sys_name=cygwin
;;
esac
AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
[Platform identifier (e.g., `i686-linux').]),
system=$withval, system="${machine_name}-${sys_name}")
AC_MSG_RESULT($system)
AC_SUBST(system)
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
@@ -50,36 +50,42 @@ AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
test "$localstatedir" = '${prefix}/var' && localstatedir=/nix/var
# Windows-specific stuff. On Cygwin, dynamically linking against the
# ATerm DLL works, except that it requires the ATerm "lib" directory
# to be in $PATH, as Windows doesn't have anything like an RPATH
# embedded in executable. Since this is kind of annoying, we use
# static libraries for now.
if test "$sys_name" = "cygwin"; then
# Whether to produce a statically linked binary. On Cygwin, this is
# the default: dynamically linking against the ATerm DLL does work,
# except that it requires the ATerm "lib" directory to be in $PATH, as
# Windows doesn't have anything like an RPATH embedded in executable.
# Since this is kind of annoying, we use static libraries for now.
AC_ARG_ENABLE(static-nix, AC_HELP_STRING([--enable-static-nix],
[produce statically linked binaries]),
static_nix=$enableval, static_nix=no)
if test "$sys_name" = cygwin; then
static_nix=yes
fi
if test "$static_nix" = yes; then
AC_DISABLE_SHARED
AC_ENABLE_STATIC
fi
# Solaris-specific stuff.
if test "$sys_name" = sunos; then
# Solaris requires -lsocket -lnsl for network functions
LIBS="-lsocket -lnsl $LIBS"
# Windows-specific stuff.
if test "$sys_name" = "cygwin"; then
# We cannot delete open files.
AC_DEFINE(CANNOT_DELETE_OPEN_FILES, 1, [Whether it is impossible to delete open files.])
fi
# Solaris-specific stuff.
if test "$sys_name" = "sunos"; then
# Solaris requires -lsocket -lnsl for network functions
ADDITIONAL_NETWORK_LIBS="-lsocket -lnsl"
AC_SUBST(ADDITIONAL_NETWORK_LIBS)
fi
AC_PROG_CC
AC_PROG_CXX
# To build programs to be run in the build machine.
if test "$CC_FOR_BUILD" = ""; then
if test "$cross_compiling" = "yes"; then
AC_CHECK_PROGS(CC_FOR_BUILD, gcc cc)
else
CC_FOR_BUILD="$CC"
fi
fi
AC_SUBST([CC_FOR_BUILD])
# We are going to use libtool.
AC_DISABLE_STATIC
@@ -106,8 +112,8 @@ AC_LANG_POP(C++)
# Check for chroot support (requires chroot() and bind mounts).
AC_CHECK_FUNCS([chroot])
AC_CHECK_FUNCS([unshare])
AC_CHECK_HEADERS([sched.h])
AC_CHECK_HEADERS([sys/param.h])
AC_CHECK_HEADERS([sched.h], [], [], [])
AC_CHECK_HEADERS([sys/param.h], [], [], [])
AC_CHECK_HEADERS([sys/mount.h], [], [],
[#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
@@ -117,30 +123,15 @@ AC_CHECK_HEADERS([sys/mount.h], [], [],
# Check for <locale>.
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS([locale])
AC_CHECK_HEADERS([locale], [], [], [])
AC_LANG_POP(C++)
# Check for <err.h>.
AC_CHECK_HEADER([err.h], [], [bsddiff_compat_include="-Icompat-include"])
AC_SUBST([bsddiff_compat_include])
# Check whether we have the personality() syscall, which allows us to
# do i686-linux builds on x86_64-linux machines.
AC_CHECK_HEADERS([sys/personality.h])
# Check for <linux/fs.h> (for immutable file support).
AC_CHECK_HEADERS([linux/fs.h])
# Check for tr1/unordered_set.
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS([tr1/unordered_set])
AC_LANG_POP(C++)
AC_DEFUN([NEED_PROG],
[
AC_PATH_PROG($1, $2)
@@ -158,14 +149,14 @@ AC_PATH_PROG(w3m, w3m, false)
AC_PATH_PROG(flex, flex, false)
AC_PATH_PROG(bison, bison, false)
NEED_PROG(perl, perl)
NEED_PROG(sed, sed)
NEED_PROG(tar, tar)
NEED_PROG(bzip2, bzip2)
AC_PATH_PROG(dot, dot)
AC_PATH_PROG(dblatex, dblatex)
AC_PATH_PROG(gzip, gzip)
AC_PATH_PROG(pv, pv, pv)
AC_PATH_PROG(openssl_prog, openssl, openssl) # if not found, call openssl in $PATH
AC_SUBST(openssl_prog)
AC_DEFINE_UNQUOTED(OPENSSL_PATH, ["$openssl_prog"], [Path of the OpenSSL binary])
# Test that Perl has the open/fork feature (Perl 5.8.0 and beyond).
AC_MSG_CHECKING([whether Perl is recent enough])
@@ -175,15 +166,6 @@ if ! $perl -e 'open(FOO, "-|", "true"); while (<FOO>) { print; }; close FOO or d
fi
AC_MSG_RESULT(yes)
# Figure out where to install Perl modules.
AC_MSG_CHECKING([for the Perl installation prefix])
perlversion=$($perl -e 'use Config; print $Config{version};')
perlarchname=$($perl -e 'use Config; print $Config{archname};')
AC_SUBST(perllibdir, [$\(libdir\)/perl5/site_perl/$perlversion/$perlarchname])
AC_MSG_RESULT($perllibdir)
NEED_PROG(cat, cat)
NEED_PROG(tr, tr)
AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],
@@ -191,7 +173,6 @@ AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],
coreutils=$withval, coreutils=$(dirname $cat))
AC_SUBST(coreutils)
AC_ARG_WITH(docbook-rng, AC_HELP_STRING([--with-docbook-rng=PATH],
[path of the DocBook RelaxNG schema]),
docbookrng=$withval, docbookrng=/docbook-rng-missing)
@@ -202,86 +183,70 @@ AC_ARG_WITH(docbook-xsl, AC_HELP_STRING([--with-docbook-xsl=PATH],
docbookxsl=$withval, docbookxsl=/docbook-xsl-missing)
AC_SUBST(docbookxsl)
AC_ARG_WITH(xml-flags, AC_HELP_STRING([--with-xml-flags=FLAGS],
[extra flags to be passed to xmllint and xsltproc]),
xmlflags=$withval, xmlflags=)
AC_SUBST(xmlflags)
AC_ARG_WITH(store-dir, AC_HELP_STRING([--with-store-dir=PATH],
[path of the Nix store (defaults to /nix/store)]),
[path of the Nix store]),
storedir=$withval, storedir='/nix/store')
AC_SUBST(storedir)
AC_ARG_WITH(aterm, AC_HELP_STRING([--with-aterm=PATH],
[prefix of CWI ATerm library]),
aterm=$withval, aterm=)
AM_CONDITIONAL(HAVE_ATERM, test -n "$aterm")
if test -z "$aterm"; then
aterm_lib='-L${top_builddir}/externals/inst-aterm/lib -lATerm'
aterm_include='-I${top_builddir}/externals/inst-aterm/include'
aterm_bin='${top_builddir}/externals/inst-aterm/bin'
else
aterm_lib="-L$aterm/lib -lATerm"
aterm_include="-I$aterm/include"
aterm_bin="$aterm/bin"
fi
AC_SUBST(aterm_lib)
AC_SUBST(aterm_include)
AC_SUBST(aterm_bin)
# Look for OpenSSL, an optional dependency.
AC_PATH_PROG(openssl_prog, openssl, openssl) # if not found, call openssl in $PATH
AC_SUBST(openssl_prog)
AC_DEFINE_UNQUOTED(OPENSSL_PATH, ["$openssl_prog"], [Path of the OpenSSL binary])
PKG_CHECK_MODULES([OPENSSL], [libcrypto],
[AC_DEFINE([HAVE_OPENSSL], [1], [Whether to use OpenSSL.])
CXXFLAGS="$OPENSSL_CFLAGS $CXXFLAGS"
have_openssl=1], [true])
AM_CONDITIONAL(HAVE_OPENSSL, test "$have_openssl" = 1)
# Look for libbz2, a required dependency.
AC_CHECK_LIB([bz2], [BZ2_bzWriteOpen], [true],
[AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2. See http://www.bzip.org/.])])
AC_CHECK_HEADERS([bzlib.h], [true],
[AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2. See http://www.bzip.org/.])])
# Look for SQLite, a required dependency.
PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19], [CXXFLAGS="$SQLITE3_CFLAGS $CXXFLAGS"])
# Whether to use the Boehm garbage collector.
AC_ARG_ENABLE(gc, AC_HELP_STRING([--enable-gc],
[enable garbage collection in the Nix expression evaluator (requires Boehm GC) [default=no]]),
gc=$enableval, gc=no)
if test "$gc" = yes; then
PKG_CHECK_MODULES([BDW_GC], [bdw-gc])
CXXFLAGS="$BDW_GC_CFLAGS $CXXFLAGS"
AC_DEFINE(HAVE_BOEHMGC, 1, [Whether to use the Boehm garbage collector.])
AC_ARG_WITH(openssl, AC_HELP_STRING([--with-openssl=PATH],
[prefix of the OpenSSL library]),
openssl=$withval, openssl=)
AM_CONDITIONAL(HAVE_OPENSSL, test -n "$openssl")
if test -n "$openssl"; then
LDFLAGS="-L$openssl/lib -lcrypto $LDFLAGS"
CFLAGS="-I$openssl/include $CFLAGS"
CXXFLAGS="-I$openssl/include $CXXFLAGS"
AC_DEFINE(HAVE_OPENSSL, 1, [Whether to use OpenSSL.])
fi
# Check for the required Perl dependencies (DBI and DBD::SQLite).
perlFlags="-I$perllibdir"
AC_ARG_WITH(dbi, AC_HELP_STRING([--with-dbi=PATH],
[prefix of the Perl DBI library]),
perlFlags="$perlFlags -I$withval")
AC_ARG_WITH(dbd-sqlite, AC_HELP_STRING([--with-dbd-sqlite=PATH],
[prefix of the Perl DBD::SQLite library]),
perlFlags="$perlFlags -I$withval")
AC_MSG_CHECKING([whether DBD::SQLite works])
if ! $perl $perlFlags -e 'use DBI; use DBD::SQLite;' 2>&5; then
AC_MSG_RESULT(no)
AC_MSG_FAILURE([The Perl modules DBI and/or DBD::SQLite are missing.])
AC_ARG_WITH(bzip2, AC_HELP_STRING([--with-bzip2=PATH],
[prefix of bzip2]),
bzip2=$withval, bzip2=)
AM_CONDITIONAL(HAVE_BZIP2, test -n "$bzip2")
if test -z "$bzip2"; then
# Headers and libraries will be used from the temporary installation
# in externals/inst-bzip2.
bzip2_lib='-L${top_builddir}/externals/inst-bzip2/lib -lbz2'
bzip2_include='-I${top_builddir}/externals/inst-bzip2/include'
# The binary will be copied to $libexecdir.
bzip2_bin='${libexecdir}/nix'
# But for testing, we have to use the temporary copy :-(
bzip2_bin_test='${top_builddir}/externals/inst-bzip2/bin'
else
bzip2_lib="-L$bzip2/lib -lbz2"
bzip2_include="-I$bzip2/include"
bzip2_bin="$bzip2/bin"
bzip2_bin_test="$bzip2/bin"
fi
AC_MSG_RESULT(yes)
AC_SUBST(perlFlags)
AC_SUBST(bzip2_lib)
AC_SUBST(bzip2_include)
AC_SUBST(bzip2_bin)
AC_SUBST(bzip2_bin_test)
# Whether to build the Perl bindings
AC_MSG_CHECKING([whether to build the Perl bindings])
AC_ARG_ENABLE(perl-bindings, AC_HELP_STRING([--enable-perl-bindings],
[whether to build the Perl bindings (recommended) [default=yes]]),
perlbindings=$enableval, perlbindings=yes)
if test "$enable_shared" = no; then
# Perl bindings require shared libraries.
perlbindings=no
fi
AM_CONDITIONAL(PERL_BINDINGS, test "$perlbindings" = "yes")
AC_SUBST(perlbindings)
AC_MSG_RESULT($perlbindings)
AC_CHECK_LIB(pthread, pthread_mutex_init)
AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state],
@@ -295,23 +260,28 @@ AC_CHECK_FUNCS([setresuid setreuid lchown])
# Nice to have, but not essential.
AC_CHECK_FUNCS([strsignal posix_fallocate nanosleep sysconf])
AC_CHECK_FUNCS([strsignal])
AC_CHECK_FUNCS([posix_fallocate])
# This is needed if bzip2 is a static library, and the Nix libraries
# are dynamic.
# This is needed if ATerm or bzip2 are static libraries,
# and the Nix libraries are dynamic.
if test "$(uname)" = "Darwin"; then
LDFLAGS="-all_load $LDFLAGS"
fi
# Figure out the extension of dynamic libraries.
eval dynlib_suffix=$shrext_cmds
AC_SUBST(dynlib_suffix)
if test "$static_nix" = yes; then
# `-all-static' has to be added at the end of configure, because
# the C compiler doesn't know about -all-static (it's filtered out
# by libtool, but configure doesn't use libtool).
LDFLAGS="-all-static $LDFLAGS"
fi
AM_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile
externals/Makefile
src/Makefile
src/bin2c/Makefile
src/boost/Makefile
@@ -328,9 +298,11 @@ AC_CONFIG_FILES([Makefile
src/nix-setuid-helper/Makefile
src/nix-log2xml/Makefile
src/bsdiff-4.3/Makefile
perl/Makefile
scripts/Makefile
corepkgs/Makefile
corepkgs/nar/Makefile
corepkgs/buildenv/Makefile
corepkgs/channels/Makefile
doc/Makefile
doc/manual/Makefile
misc/Makefile

View File

@@ -1,11 +1 @@
all-local: config.nix
files = nar.nix buildenv.nix buildenv.pl unpack-channel.nix unpack-channel.sh derivation.nix
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL_DATA) config.nix $(files) $(DESTDIR)$(datadir)/nix/corepkgs
include ../substitute.mk
EXTRA_DIST = config.nix.in $(files)
SUBDIRS = nar buildenv channels

View File

@@ -1,24 +0,0 @@
with import <nix/config.nix>;
{ derivations, manifest }:
derivation {
name = "user-environment";
system = builtins.currentSystem;
builder = perl;
args = [ "-w" ./buildenv.pl ];
manifest = manifest;
# !!! grmbl, need structured data for passing this in a clean way.
paths = derivations;
active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations;
priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations;
# Building user environments remotely just causes huge amounts of
# network traffic, so don't do that.
preferLocalBuild = true;
# Don't build in a chroot because Nix's dependencies may not be there.
__noChroot = true;
}

View File

@@ -0,0 +1,11 @@
all-local: builder.pl
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs/buildenv
$(INSTALL_DATA) $(srcdir)/default.nix $(DESTDIR)$(datadir)/nix/corepkgs/buildenv
$(INSTALL_PROGRAM) builder.pl $(DESTDIR)$(datadir)/nix/corepkgs/buildenv
include ../../substitute.mk
EXTRA_DIST = default.nix builder.pl.in

View File

@@ -1,3 +1,5 @@
#! @perl@ -w
use strict;
use Cwd;
use IO::Handle;
@@ -27,18 +29,10 @@ sub createLinks {
$baseName =~ s/^.*\///g; # strip directory
my $dstFile = "$dstDir/$baseName";
# The files below are special-cased so that they don't show up
# in user profiles, either because they are useless, or
# because they would cause pointless collisions (e.g., each
# Python package brings its own
# `$out/lib/pythonX.Y/site-packages/easy-install.pth'.)
# Urgh, hacky...
if ($srcFile =~ /\/propagated-build-inputs$/ ||
if ($srcFile =~ /\/propagated-build-inputs$/ ||
$srcFile =~ /\/nix-support$/ ||
$srcFile =~ /\/perllocal.pod$/ ||
$srcFile =~ /\/easy-install.pth$/ ||
$srcFile =~ /\/site.py$/ ||
$srcFile =~ /\/site.pyc$/ ||
$srcFile =~ /\/info\/dir$/ ||
$srcFile =~ /\/log$/)
{
@@ -166,4 +160,4 @@ while (scalar(keys %postponed) > 0) {
print STDERR "created $symlinks symlinks in user environment\n";
symlink($ENV{"manifest"}, "$out/manifest.nix") or die "cannot create manifest";
symlink($ENV{"manifest"}, "$out/manifest") or die "cannot create manifest";

View File

@@ -0,0 +1,14 @@
{system, derivations, manifest}:
derivation {
name = "user-environment";
system = system;
builder = ./builder.pl;
manifest = manifest;
# !!! grmbl, need structured data for passing this in a clean way.
paths = derivations;
active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations;
priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations;
}

View File

@@ -0,0 +1,11 @@
all-local: unpack.sh
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs/channels
$(INSTALL_DATA) $(srcdir)/unpack.nix $(DESTDIR)$(datadir)/nix/corepkgs/channels
$(INSTALL_PROGRAM) unpack.sh $(DESTDIR)$(datadir)/nix/corepkgs/channels
include ../../substitute.mk
EXTRA_DIST = unpack.nix unpack.sh.in

View File

@@ -0,0 +1,7 @@
{system, inputs}:
derivation {
name = "channels";
builder = ./unpack.sh;
inherit system inputs;
}

View File

@@ -0,0 +1,32 @@
#! @shell@ -e
@coreutils@/mkdir $out
@coreutils@/mkdir $out/tmp
cd $out/tmp
inputs=($inputs)
for ((n = 0; n < ${#inputs[*]}; n += 2)); do
channelName=${inputs[n]}
channelTarball=${inputs[n+1]}
echo "unpacking channel $channelName"
@bunzip2@ < $channelTarball | @tar@ xf -
if test -e */channel-name; then
channelName="$(@coreutils@/cat */channel-name)"
fi
nr=1
attrName=$(echo $channelName | @tr@ -- '- ' '__')
dirName=$attrName
while test -e ../$dirName; do
nr=$((nr+1))
dirName=$attrName-$nr
done
@coreutils@/mv * ../$dirName # !!! hacky
done
cd ..
@coreutils@/rmdir tmp

View File

@@ -1,13 +0,0 @@
let
fromEnv = var: def:
let val = builtins.getEnv var; in
if val != "" then val else def;
in {
perl = "@perl@";
shell = "@shell@";
coreutils = "@coreutils@";
bzip2 = fromEnv "NIX_BZIP2" "@bzip2@";
tar = "@tar@";
tr = "@tr@";
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
}

View File

@@ -1,27 +0,0 @@
/* This is the implementation of the derivation builtin function.
It's actually a wrapper around the derivationStrict primop. */
drvAttrs @ { outputs ? [ "out" ], ... }:
let
strict = derivationStrict drvAttrs;
commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) //
{ all = map (x: x.value) outputsList;
inherit drvAttrs;
};
outputToAttrListElement = outputName:
{ name = outputName;
value = commonAttrs // {
outPath = builtins.getAttr outputName strict;
drvPath = strict.drvPath;
type = "derivation";
inherit outputName;
};
};
outputsList = map outputToAttrListElement outputs;
in (builtins.head outputsList).value

View File

@@ -1,34 +0,0 @@
with import <nix/config.nix>;
let
builder = builtins.toFile "nar.sh"
''
export PATH=${nixBinDir}:${coreutils}
echo "packing $storePath..."
mkdir $out
dst=$out/tmp.nar.bz2
set -o pipefail
nix-store --dump "$storePath" | ${bzip2} > $dst
nix-hash --flat --type $hashAlgo --base32 $dst > $out/narbz2-hash
mv $out/tmp.nar.bz2 $out/$(cat $out/narbz2-hash).nar.bz2
'';
in
{ storePath, hashAlgo }:
derivation {
name = "nar";
system = builtins.currentSystem;
builder = shell;
args = [ "-e" builder ];
inherit storePath hashAlgo;
# Don't build in a chroot because Nix's dependencies may not be there.
__noChroot = true;
}

11
corepkgs/nar/Makefile.am Normal file
View File

@@ -0,0 +1,11 @@
all-local: nar.sh
install-exec-local:
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs/nar
$(INSTALL_DATA) $(srcdir)/nar.nix $(DESTDIR)$(datadir)/nix/corepkgs/nar
$(INSTALL_PROGRAM) nar.sh $(DESTDIR)$(datadir)/nix/corepkgs/nar
include ../../substitute.mk
EXTRA_DIST = nar.nix nar.sh.in

7
corepkgs/nar/nar.nix Normal file
View File

@@ -0,0 +1,7 @@
{system, storePath, hashAlgo}:
derivation {
name = "nar";
builder = ./nar.sh;
inherit system storePath hashAlgo;
}

14
corepkgs/nar/nar.sh.in Normal file
View File

@@ -0,0 +1,14 @@
#! @shell@ -e
echo "packing $storePath into $out..."
@coreutils@/mkdir $out
dst=$out/tmp.nar.bz2
@bindir@/nix-store --dump "$storePath" > tmp
@bzip2@ < tmp > $dst
@bindir@/nix-hash -vvvvv --flat --type $hashAlgo --base32 tmp > $out/nar-hash
@bindir@/nix-hash --flat --type $hashAlgo --base32 $dst > $out/narbz2-hash
@coreutils@/mv $out/tmp.nar.bz2 $out/$(@coreutils@/cat $out/narbz2-hash).nar.bz2

View File

@@ -1,17 +0,0 @@
with import <nix/config.nix>;
{ name, channelName, src }:
derivation {
system = builtins.currentSystem;
builder = shell;
args = [ "-e" ./unpack-channel.sh ];
inherit name channelName src bzip2 tar tr;
PATH = "${nixBinDir}:${coreutils}";
# No point in doing this remotely.
preferLocalBuild = true;
# Don't build in a chroot because Nix's dependencies may not be there.
__noChroot = true;
}

View File

@@ -1,4 +0,0 @@
mkdir $out
cd $out
$bzip2 -d < $src | $tar xf -
mv * $out/$channelName

View File

@@ -1,5 +1,5 @@
XMLLINT = $(xmllint) --nonet $(xmlflags)
XSLTPROC = $(xsltproc) --nonet $(xmlflags) \
XMLLINT = $(xmllint) $(xmlflags)
XSLTPROC = $(xsltproc) $(xmlflags) \
--param section.autolabel 1 \
--param section.label.includes.component.label 1 \
--param html.stylesheet \'style.css\' \
@@ -29,41 +29,29 @@ MANUAL_SRCS = manual.xml introduction.xml installation.xml \
package-management.xml writing-nix-expressions.xml builtins.xml \
build-farm.xml \
$(man1_MANS:.1=.xml) $(man8_MANS:.8=.xml) \
troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml opt-inst-syn.xml \
troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml \
env-common.xml quick-start.xml nix-lang-ref.xml glossary.xml \
conf-file.xml release-notes.xml \
style.css images
# Do XInclude processing.
manual.xmli: $(MANUAL_SRCS) version.txt
$(XMLLINT) --xinclude $< -o $@.tmp
mv $@.tmp $@
# Note: RelaxNG validation requires xmllint >= 2.7.4.
manual.is-valid: manual.xmli
$(XSLTPROC) --novalid --stringparam profile.condition manual \
$(docbookxsl)/profiling/profile.xsl $< 2> /dev/null | \
$(XMLLINT) --noout --relaxng $(docbookrng)/docbook.rng -
manual.is-valid: $(MANUAL_SRCS) version.txt
$(XMLLINT) --noout --nonet --xinclude --noxincludenode --relaxng $(docbookrng)/docbook.rng $<
touch $@
version.txt:
echo -n $(VERSION) > version.txt
man $(MANS): manual.is-valid
$(XSLTPROC) --stringparam profile.condition manpage \
$(docbookxsl)/profiling/profile.xsl manual.xmli 2> /dev/null | \
$(XSLTPROC) $(docbookxsl)/manpages/docbook.xsl -
man $(MANS): $(MANUAL_SRCS) manual.is-valid
$(XSLTPROC) --nonet --xinclude $(docbookxsl)/manpages/docbook.xsl manual.xml
manual.html: $(MANUAL_SRCS) manual.is-valid images
$(XSLTPROC) --xinclude --stringparam profile.condition manual \
$(docbookxsl)/profiling/profile.xsl manual.xml | \
$(XSLTPROC) --output manual.html $(docbookxsl)/html/docbook.xsl -
$(XSLTPROC) --nonet --xinclude --output manual.html \
$(docbookxsl)/html/docbook.xsl manual.xml
manual.pdf: $(MANUAL_SRCS) manual.is-valid images
if test "$(dblatex)" != ""; then \
$(XSLTPROC) --xinclude --stringparam profile.condition manual \
$(docbookxsl)/profiling/profile.xsl manual.xml | \
$(dblatex) -o manual.pdf $(dblatex_opts) -; \
$(dblatex) $(dblatex_opts) manual.xml; \
else \
echo "Please install dblatex and rerun configure."; \
exit 1; \
@@ -76,12 +64,12 @@ NEWS_OPTS = \
--stringparam header.rule 0
NEWS.html: release-notes.xml
$(XSLTPROC) --xinclude --output $@ $(NEWS_OPTS) \
$(XSLTPROC) --nonet --xinclude --output $@ $(NEWS_OPTS) \
$(docbookxsl)/html/docbook.xsl release-notes.xml
NEWS.txt: release-notes.xml
$(XSLTPROC) --xinclude quote-literals.xsl release-notes.xml | \
$(XSLTPROC) --output $@.tmp.html $(NEWS_OPTS) \
$(XSLTPROC) --nonet --xinclude quote-literals.xsl release-notes.xml | \
$(XSLTPROC) --nonet --output $@.tmp.html $(NEWS_OPTS) \
$(docbookxsl)/html/docbook.xsl -
LANG=en_US $(w3m) -dump $@.tmp.html > $@
rm $@.tmp.html
@@ -108,7 +96,7 @@ images:
cp $(docbookxsl)/images/callouts/*.gif images/callouts
chmod -R +w images
KEEP = manual.html manual.xmli manual.is-valid version.txt $(MANS) NEWS.html NEWS.txt
KEEP = manual.html manual.is-valid version.txt $(MANS) NEWS.html NEWS.txt
EXTRA_DIST = $(MANUAL_SRCS) $(FIGURES) $(KEEP)

View File

@@ -1,17 +1,67 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id='chap-distributed-builds'>
xml:id='chap-build-farm'>
<title>Setting Up Distributed Builds</title>
<title>Setting up a Build Farm</title>
<para>Nix supports distributed builds: a local Nix installation can
forward Nix builds to other machines over the network. This allows
multiple builds to be performed in parallel (thus improving
performance) and allows Nix to perform multi-platform builds in a
semi-transparent way. For instance, if you perform a build for a
<literal>powerpc-darwin</literal> on an <literal>i686-linux</literal>
machine, Nix can automatically forward the build to a
<literal>powerpc-darwin</literal> machine, if available.</para>
<para>This chapter provides some sketchy information on how to set up
a Nix-based build farm. Nix is particularly suited as a basis for a
build farm, since:
<itemizedlist>
<listitem><para>Nix supports distributed builds: a local Nix
installation can forward Nix builds to other machines over the
network. This allows multiple builds to be performed in parallel
(thus improving performance), but more in importantly, it allows Nix
to perform multi-platform builds in a semi-transparent way. For
instance, if you perform a build for a
<literal>powerpc-darwin</literal> on an
<literal>i686-linux</literal> machine, Nix can automatically forward
the build to a <literal>powerpc-darwin</literal> machine, if
available.</para></listitem>
<listitem><para>The Nix expression language is ideal for describing
build jobs, plus all their dependencies. For instance, if your
package has some dependency, you don't have to manually install it
on all the machines in the build farm; they will be built
automatically.</para></listitem>
<listitem><para>Proper release management requires that builds (if
deployed) are traceable: it should be possible to figure out from
exactly what sources they were built, in what configuration, etc.;
and it should be possible to reproduce the build, if necessary. Nix
makes this possible since Nix's hashing scheme uniquely identifies
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 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
available through a channel, so successful builds can be deployed to
users immediately.</para></listitem>
</itemizedlist>
</para>
<section><title>Overview</title>
<para>TODO</para>
<para>The sources of the Nix build farm are at <link
xlink:href='https://svn.nixos.org/repos/nix/release/trunk'/>.</para>
</section>
<section xml:id='sec-distributed-builds'><title>Setting up distributed builds</title>
<para>You can enable distributed builds by setting the environment
variable <envar>NIX_BUILD_HOOK</envar> to point to a program that Nix
@@ -29,23 +79,22 @@ variable</link>.</para>
<filename>remote-systems.conf</filename></title>
<programlisting>
nix@mcflurry.labs.cs.uu.nl powerpc-darwin /home/nix/.ssh/id_quarterpounder_auto 2
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 1 kvm
nix@itchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 2
nix@poochie.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 2 kvm perf
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 1
</programlisting>
</example>
<para>Nix ships with a build hook that should be suitable for most
purposes. It uses <command>ssh</command> and
<command>nix-copy-closure</command> to copy the build inputs and
outputs and perform the remote build. To use it, you should set
<envar>NIX_BUILD_HOOK</envar> to
<filename><replaceable>prefix</replaceable>/libexec/nix/build-remote.pl</filename>.
You should also define a list of available build machines and point
the environment variable <envar>NIX_REMOTE_SYSTEMS</envar> to it. An
example configuration is shown in <xref linkend='ex-remote-systems'
/>. Each line in the file specifies a machine, with the following
bits of information:
<para>An example build hook can be found in the Nix build farm
sources: <link
xlink:href='https://svn.nixos.org/repos/nix/release/trunk/common/distributed/build-remote.pl'
/>. It should be suitable for most purposes, with maybe some minor
adjustments. It uses <command>ssh</command> and
<command>rsync</command> to copy the build inputs and outputs and
perform the remote build. You should define a list of available build
machines and set the environment variable
<envar>REMOTE_SYSTEMS</envar> to point to it. An example
configuration is shown in <xref linkend='ex-remote-systems' />. Each
line in the file specifies a machine, with the following bits of
information:
<orderedlist>
@@ -55,59 +104,34 @@ bits of information:
be an alias defined in your
<filename>~/.ssh/config</filename>.</para></listitem>
<listitem><para>A comma-separated list of Nix platform type
identifiers, such as <literal>powerpc-darwin</literal>. It is
possible for a machine to support multiple platform types, e.g.,
<literal>i686-linux,x86_64-linux</literal>.</para></listitem>
<listitem><para>The Nix platform type identifier, such as
<literal>powerpc-darwin</literal>.</para></listitem>
<listitem><para>The SSH private key to be used to log in to the
remote machine. Since builds should be non-interactive, this key
should not have a passphrase!</para></listitem>
<listitem><para>The maximum number of builds that
<listitem><para>The maximum <quote>load</quote> of the remote
machine. This is just the maximum number of jobs that
<filename>build-remote.pl</filename> will execute in parallel on the
machine. Typically this should be equal to the number of CPU cores.
For instance, the machine <literal>itchy</literal> in the example
will execute up to 8 builds in parallel.</para></listitem>
<listitem><para>The “speed factor”, indicating the relative speed of
the machine. If there are multiple machines of the right type, Nix
will prefer the fastest, taking load into account.</para></listitem>
<listitem><para>A comma-separated list of <emphasis>supported
features</emphasis>. If a derivation has the
<varname>requiredSystemFeatures</varname> attribute, then
<filename>build-remote.pl</filename> will only perform the
derivation on a machine that has the specified features. For
instance, the attribute
<programlisting>
requiredSystemFeatures = [ "kvm" ];
</programlisting>
will cause the build to be performed on a machine that has the
<literal>kvm</literal> feature (i.e., <literal>scratchy</literal> in
the example above).</para></listitem>
<listitem><para>A comma-separated list of <emphasis>mandatory
features</emphasis>. A machine will only be used to build a
derivation if all of the machines mandatory features appear in the
derivations <varname>requiredSystemFeatures</varname> attribute.
Thus, in the example, the machine <literal>poochie</literal> will
only do derivations that have
<varname>requiredSystemFeatures</varname> set to <literal>["kvm"
"perf"]</literal> or <literal>["perf"]</literal>.</para></listitem>
machine. Typically this should be equal to the number of
CPUs.</para></listitem>
</orderedlist>
You should also set up the environment variable
<envar>NIX_CURRENT_LOAD</envar> to point at a directory (e.g.,
<filename>/var/run/nix/current-load</filename>) that
<filename>build-remote.pl</filename> uses to remember how many builds
it is currently executing remotely. It doesn't look at the actual
load on the remote machine, so if you have multiple instances of Nix
running, they should use the same <envar>NIX_CURRENT_LOAD</envar>
file. Maybe in the future <filename>build-remote.pl</filename> will
look at the actual remote load.</para>
<envar>CURRENT_LOAD</envar> to point at a file that
<filename>build-remote.pl</filename> uses to remember how many jobs it
is currently executing remotely. It doesn't look at the actual load
on the remote machine, so if you have multiple instances of Nix
running, they should use the same <envar>CURRENT_LOAD</envar>
file<footnote><para>Although there are probably some race conditions
in the script right now.</para></footnote>. Maybe in the future
<filename>build-remote.pl</filename> will look at the actual remote
load. The load file should exist, so you should just create it as an
empty file initially.</para>
</section>
</chapter>

View File

@@ -43,10 +43,10 @@ is also available as <function>builtins.derivation</function>.</para>
<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:
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>
@@ -442,10 +442,10 @@ x: x + 456</programlisting>
Example:
<programlisting>
builtins.listToAttrs
[ { name = "foo"; value = 123; }
{ name = "bar"; value = 456; }
]
builtins.listToAttrs [
{name = "foo"; value = 123;}
{name = "bar"; value = 456;}
]
</programlisting>
evaluates to
@@ -466,10 +466,10 @@ builtins.listToAttrs
example,
<programlisting>
map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
map (x: "foo" + x) ["bar" "bla" "abc"]</programlisting>
evaluates to <literal>[ "foobar" "foobla" "fooabc"
]</literal>.</para></listitem>
evaluates to <literal>["foobar" "foobla"
"fooabc"]</literal>.</para></listitem>
</varlistentry>
@@ -491,10 +491,10 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
a package name and version. The package name is everything up to
but not including the first dash followed by a digit, and the
version is everything following that dash. The result is returned
in an attribute set <literal>{ name, version }</literal>. Thus,
in an attribute set <literal>{name, version}</literal>. Thus,
<literal>builtins.parseDrvName "nix-0.12pre12876"</literal>
returns <literal>{ name = "nix"; version = "0.12pre12876";
}</literal>.</para></listitem>
returns <literal>{name = "nix"; version =
"0.12pre12876";}</literal>.</para></listitem>
</varlistentry>
@@ -550,9 +550,9 @@ in config.someSetting</programlisting>
exist in <replaceable>attrs</replaceable>. For instance,
<screen>
removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
removeAttrs { x = 1; y = 2; z = 3; } ["a" "x" "z"]</screen>
evaluates to <literal>{ y = 2; }</literal>.</para></listitem>
evaluates to <literal>{y = 2;}</literal>.</para></listitem>
</varlistentry>
@@ -632,7 +632,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
linkend='ex-hello-builder' /> into one file:
<programlisting>
{ stdenv, fetchurl, perl }:
{stdenv, fetchurl, perl}:
stdenv.mkDerivation {
name = "hello-2.1.1";
@@ -765,12 +765,12 @@ in foo</programlisting>
using <function>toXML</function></title>
<programlisting><![CDATA[
{ stdenv, fetchurl, libxslt, jira, uberwiki }:
{stdenv, fetchurl, libxslt, jira, uberwiki}:
stdenv.mkDerivation (rec {
name = "web-server";
buildInputs = [ libxslt ];
buildInputs = [libxslt];
builder = builtins.toFile "builder.sh" "
source $stdenv/setup

View File

@@ -6,7 +6,7 @@
<para>A number of persistent settings of Nix are stored in the file
<filename><replaceable>sysconfdir</replaceable>/nix/nix.conf</filename>.
<filename><replaceable>prefix</replaceable>/etc/nix/nix.conf</filename>.
This file is a list of <literal><replaceable>name</replaceable> =
<replaceable>value</replaceable></literal> pairs, one per line.
Comments start with a <literal>#</literal> character. An example
@@ -97,25 +97,6 @@ env-keep-derivations = false
</varlistentry>
<varlistentry xml:id="conf-build-cores"><term><literal>build-cores</literal></term>
<listitem><para>Sets the value of the
<envar>NIX_BUILD_CORES</envar> environment variable in the
invocation of builders. Builders can use this variable at their
discretion to control the maximum amount of parallelism. For
instance, in Nixpkgs, if the derivation attribute
<varname>enableParallelBuilding</varname> is set to
<literal>true</literal>, the builder passes the
<option>-j<replaceable>N</replaceable></option> flag to GNU Make.
It can be overriden using the <option
linkend='opt-cores'>--cores</option> command line switch and
defaults to <literal>1</literal>. The value <literal>0</literal>
means that the builder should use all available CPU cores in the
system.</para></listitem>
</varlistentry>
<varlistentry xml:id="conf-build-max-silent-time"><term><literal>build-max-silent-time</literal></term>
<listitem>
@@ -136,25 +117,6 @@ env-keep-derivations = false
</varlistentry>
<varlistentry xml:id="conf-build-timeout"><term><literal>build-timeout</literal></term>
<listitem>
<para>This option defines the maximum number of seconds that a
builder can run. This is useful (for instance in a automated
build system) to catch builds that are stuck in an infinite loop
but keep writing to their standard output or standard error. It
can be overriden using the <option
linkend="opt-timeout">--timeout</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>
@@ -225,15 +187,6 @@ env-keep-derivations = false
</varlistentry>
<varlistentry><term><literal>build-use-substitutes</literal></term>
<listitem><para>If set to <literal>true</literal> (default), Nix
will use binary substitutes if available. This option can be
disabled to force building from source.</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,
@@ -261,21 +214,6 @@ build-use-chroot = /dev /proc /bin</programlisting>
</varlistentry>
<varlistentry><term><literal>build-cache-failures</literal></term>
<listitem><para>If set to <literal>true</literal>, Nix will
“cache” build failures, meaning that it will remember (in its
database) that a derivation previously failed. If you then try to
build the derivation again, Nix will immediately fail rather than
perform the build again. Failures in fixed-output derivations
(such as <function>fetchurl</function> calls) are never cached.
The “failed” status of a derivation can be cleared using
<command>nix-store --clear-failed-paths</command>. By default,
failure caching is disabled.</para></listitem>
</varlistentry>
<varlistentry><term><literal>system</literal></term>
<listitem><para>This option specifies the canonical Nix system
@@ -303,7 +241,7 @@ build-use-chroot = /dev /proc /bin</programlisting>
Nix store metadata (in <filename>/nix/var/nix/db</filename>) are
synchronously flushed to disk. This improves robustness in case
of system crashes, but reduces performance. The default is
<literal>true</literal>.</para></listitem>
<literal>false</literal>.</para></listitem>
</varlistentry>

View File

@@ -7,43 +7,9 @@
<para>Most Nix commands interpret the following environment variables:</para>
<variablelist xml:id="env-common">
<variablelist>
<varlistentry><term><envar>NIX_PATH</envar></term>
<listitem>
<para>A colon-separated list of directories used to look up Nix
expressions enclosed in angle brackets (i.e.,
<literal>&lt;<replaceable>path</replaceable>></literal>). For
instance, the value
<screen>
/home/eelco/Dev:/etc/nixos</screen>
will cause Nix to look for paths relative to
<filename>/home/eelco/Dev</filename> and
<filename>/etc/nixos</filename>, in that order. It is also
possible to match paths against a prefix. For example, the value
<screen>
nixpkgs=/home/eelco/Dev/nixpkgs-branch:/etc/nixos</screen>
will cause Nix to search for
<literal>&lt;nixpkgs/<replaceable>path</replaceable>></literal> in
<filename>/home/eelco/Dev/nixpkgs-branch/<replaceable>path</replaceable></filename>
and
<filename>/etc/nixos/nixpkgs/<replaceable>path</replaceable></filename>.
</para>
<para>The search path can be extended using the
<option>-I</option> option, which takes precedence over
<envar>NIX_PATH</envar>.</para></listitem>
</varlistentry>
<varlistentry><term><envar>NIX_IGNORE_SYMLINK_STORE</envar></term>
<listitem>
@@ -153,13 +119,9 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<para>Specifies the location of the <emphasis>build hook</emphasis>,
which is a program (typically some script) that Nix will call
whenever it wants to build a derivation. This is used to implement
distributed builds<phrase condition="manual"> (see <xref
linkend="chap-distributed-builds" />)</phrase>.</para>
<!--
The protocol by
which the calling Nix process and the build hook communicate is as
follows.
distributed builds (see <xref linkend="sec-distributed-builds"
/>). The protocol by which the calling Nix process and the build
hook communicate is as follows.</para>
<para>The build hook is called with the following command-line
arguments:
@@ -169,7 +131,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<listitem><para>A boolean value <literal>0</literal> or
<literal>1</literal> specifying whether Nix can locally execute
more builds, as per the <link
linkend="opt-max-jobs"><option>- -max-jobs</option> option</link>.
linkend="opt-max-jobs"><option>--max-jobs</option> option</link>.
The purpose of this argument is to allow the hook to not have to
maintain bookkeeping for the local machine.</para></listitem>
@@ -254,7 +216,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<listitem><para>The reference graph of the inputs, in the format
accepted by the command <command>nix-store
- -register-validity</command>. It is necessary to run this
--register-validity</command>. It is necessary to run this
command on the remote machine after copying the inputs to inform
Nix on the remote machine that the inputs are valid
paths.</para></listitem>
@@ -271,7 +233,6 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<literal>0</literal> indicates that the hook has failed. An exit
code equal to 100 means that the remote build failed (as opposed to,
e.g., a network error).</para>
-->
</listitem>
@@ -294,13 +255,12 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<listitem><para>This variable contains the paths of remote Nix
installations from whichs paths can be copied, separated by colons.
<phrase condition="manual">See <xref linkend="sec-sharing-packages"
/> for details.</phrase> Each path should be the
<filename>/nix</filename> directory of a remote Nix installation
(i.e., not the <filename>/nix/store</filename> directory). The
paths are subject to globbing, so you can set it so something like
<literal>/var/run/nix/remote-stores/*/nix</literal> and mount
multiple remote filesystems in
See <xref linkend="sec-sharing-packages" /> for details. Each path
should be the <filename>/nix</filename> directory of a remote Nix
installation (i.e., not the <filename>/nix/store</filename>
directory). The paths are subject to globbing, so you can set it so
something like <literal>/var/run/nix/remote-stores/*/nix</literal>
and mount multiple remote filesystems in
<literal>/var/run/nix/remote-stores</literal>.</para>
<para>Note that if youre building through the <link
@@ -311,17 +271,6 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
</varlistentry>
<varlistentry><term><envar>GC_INITIAL_HEAP_SIZE</envar></term>
<listitem><para>If Nix has been configured to use the Boehm garbage
collector, this variable sets the initial size of the heap in bytes.
It defaults to 384 MiB. Setting it to a low value reduces memory
consumption, but will increase runtime due to the overhead of
garbage collection.</para></listitem>
</varlistentry>
</variablelist>

View File

@@ -15,11 +15,11 @@
<listitem><para>Linux (particularly on x86, x86_64, and
PowerPC).</para></listitem>
<listitem><para>Mac OS X.</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>
@@ -28,7 +28,6 @@
partition.</para></warning>
</listitem>
-->
</itemizedlist>
@@ -48,17 +47,17 @@ for Red Hat, SuSE, and Fedora Core are also available.</para>
<para>Alternatively, the most recent sources of Nix can be obtained
from its <link
xlink:href="https://github.com/NixOS/nix">Git
xlink:href="https://svn.nixos.org/repos/nix/nix/trunk">Subversion
repository</link>. For example, the following command will check out
the latest revision into a directory called
<filename>nix</filename>:</para>
<screen>
$ git clone https://github.com/NixOS/nix</screen>
$ svn checkout https://svn.nixos.org/repos/nix/nix/trunk nix</screen>
<para>Likewise, specific releases can be obtained from the <link
xlink:href="https://github.com/NixOS/nix/tags">tags</link> of the
repository.</para>
xlink:href="https://svn.nixos.org/repos/nix/nix/tags">tags
directory</link> of the repository.</para>
</section>
@@ -70,36 +69,7 @@ from source</emphasis>. Binary releases (e.g., RPMs) have no
prerequisites.</para>
<para>A fairly recent version of GCC/G++ is required. Version 2.95
and higher should work. Clang will also work.</para>
<para>Nix requires Perl, version 5.8 or higher.</para>
<para>Nix requires <command>pkg-config</command> to locate its
dependencies. If your distribution does not provide it, you can get
it from <link
xlink:href="http://www.freedesktop.org/wiki/Software/pkg-config"
/>.</para>
<para>Nix requires the bzip2 compressor program and the
<literal>libbz2</literal> library. Thus you must have bzip2
installed, including development headers and libraries. If your
distribution does not provide these, you can obtain bzip2 from <link
xlink:href="http://www.bzip.org/"/>.</para>
<para>Nix requires the SQLite embedded database library, version
3.6.19 or higher. If your distribution does not provide it, please
install it from <link xlink:href="http://www.sqlite.org/" />.</para>
<para>Nix requires the Perl DBI and DBD::SQLite libraries, which are
available from <link xlink:href="http://search.cpan.org/">CPAN</link>
if your distribution does not provide them.</para>
<para>Nix can optionally use the <link
xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/">Boehm
garbage collector</link> to reduce the evaluators memory consumption.
To enable it, install <literal>pkgconfig</literal> and the Boehm
garbage collector, and pass the flag <option>--enable-gc</option> to
<command>configure</command>.</para>
and higher should work.</para>
<para>To build this manual and the man-pages you need the
<command>xmllint</command> and <command>xsltproc</command> programs,
@@ -110,20 +80,32 @@ xlink:href="http://docbook.sourceforge.net/projects/xsl/">DocBook XSL
stylesheets</link> and optionally the <link
xlink:href="http://www.docbook.org/schemas/5x"> DocBook 5.0 RELAX NG
schemas</link>. Note that these are only required if you modify the
manual sources or when you are building from the Git
manual sources or when you are building from the Subversion
repository.</para>
<para>To build the parser, very <emphasis>recent</emphasis> versions
of Bison and Flex are required. (This is because Nix needs GLR
support in Bison and reentrancy support in Flex.) For Bison, you need
version 2.3 or higher (1.875 does <emphasis>not</emphasis> work),
which can be obtained from the <link
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP server</link>.
For Flex, you need version 2.5.33, which is available on <link
xlink:href="http://lex.sourceforge.net/">SourceForge</link>. Slightly
older versions may also work, but ancient versions like the ubiquitous
2.5.4a won't. Note that these are only required if you modify the
parser or when you are building from the Git repository.</para>
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 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-aterm</option> and <option>--with-bzip2</option>
options to point to their respective locations.</para>
</section>
@@ -140,11 +122,11 @@ $ make install</screen>
</para>
<para>When building from the Git repository, these should be preceded
by the command:
<para>When building from the Subversion repository, these should be
preceded by the command:
<screen>
$ ./bootstrap.sh</screen>
$ ./bootstrap</screen>
</para>
@@ -327,7 +309,7 @@ bit turned on (like <filename>/tmp</filename>):
<screen>
$ chgrp nixbld /nix/store
$ chmod 1775 /nix/store
$ chmod 1777 /nix/store
</screen>
</para>
@@ -336,7 +318,7 @@ $ chmod 1775 /nix/store
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> (usually <literal>/etc/nix/nix.conf</literal>):
file</link> (<literal>/nix/etc/nix/nix.conf</literal>):
<programlisting>
build-users-group = nixbld
@@ -393,7 +375,7 @@ 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 nix /nix/store /nix/var/nix</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.,

View File

@@ -17,10 +17,10 @@ store</emphasis>, usually the directory
subdirectory such as
<programlisting>
/nix/store/nlc4z5y1hm8w9s8vm6m1f5hy962xjmp5-firefox-12.0
/nix/store/r8vvq9kq18pz08v249h8my6r9vs7s0n3-firefox-2.0.0.1/
</programlisting>
where <literal>nlc4z5</literal> is a unique identifier for the
where <literal>r8vvq9kq</literal> is a unique identifier for the
package that captures all its dependencies (its a cryptographic hash
of the packages build dependency graph). This enables many powerful
features.</para>
@@ -72,14 +72,15 @@ sounds risky, but it works extremely well.</para>
<simplesect><title>Multi-user support</title>
<para>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 users <envar>PATH</envar>. If a user installs a
package that another user has already installed previously, the
package wont 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>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 users
<envar>PATH</envar>. If a user installs a package that another user
has already installed previously, the package wont 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
@@ -112,7 +113,7 @@ $ nix-env --rollback
<simplesect><title>Garbage collection</title>
<para>When you uninstall a package like this…
<para>When you install a package like this…
<screen>
$ nix-env --uninstall firefox
@@ -263,10 +264,8 @@ xlink:href="http://www.cs.uu.nl/wiki/Trace/WebHome">TraCE
project</link> (2003-2008). The project was funded by the Software
Engineering Research Program <link
xlink:href="http://www.jacquard.nl/">Jacquard</link> to improve the
support for variability in software systems. Further funding was
provided by the NIRICT LaQuSo Build Farm project. Development is
currently supported by <link
xlink:href="http://www.logicblox.com/">LogicBlox</link>.</para>
support for variability in software systems. Further funding is now
provided by the NIRICT LaQuSo Build Farm project.</para>
</section>
@@ -276,7 +275,7 @@ xlink:href="http://www.logicblox.com/">LogicBlox</link>.</para>
<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 distributed multi-platform building.</para>
up a Nix-based build farm.</para>
</section>
@@ -316,12 +315,13 @@ Upgrading in a Purely Functional Component Deployment Model
paper <citetitle
xlink:href='http://www.st.ewi.tudelft.nl/~dolstra/pubs/servicecm-scm12-final.pdf'>
Service Configuration Management</citetitle> shows how services (e.g.,
web servers) can be deployed and managed through Nix. An overview of
NixOS is given in the JFP article <citetitle
xlink:href="http://www.st.ewi.tudelft.nl/~dolstra/pubs/nixos-jfp-final.pdf">NixOS:
A Purely Functional Linux Distribution</citetitle>. The Nix homepage
has <link xlink:href="http://nixos.org/docs/papers.html">an up-to-date
list of Nix-related papers</link>.</para>
web servers) can be deployed and managed through Nix. A short
overview of NixOS is given in the HotOS XI paper <citetitle
xlink:href="http://www.st.ewi.tudelft.nl/~dolstra/pubs/hotos-final.pdf">Purely
Functional System Configuration Management</citetitle>. The Nix
homepage has <link
xlink:href="http://nixos.org/docs/papers.html">an up-to-date list
of Nix-related papers</link>.</para>
<para>Nix is the subject of Eelco Dolstras PhD thesis <citetitle
xlink:href="http://igitur-archive.library.uu.nl/dissertations/2006-0118-200031/index.htm">The

View File

@@ -5,7 +5,8 @@
<title>Nix User's Guide</title>
<edition>Version <xi:include href="version.txt" parse="text" /></edition>
<subtitle>Draft (Version <xi:include href="version.txt"
parse="text" />)</subtitle>
<author>
<personname>
@@ -13,17 +14,23 @@
<surname>Dolstra</surname>
</personname>
<affiliation>
<orgname>LogicBlox</orgname>
<orgname>Delft University of Technology</orgname>
<orgdiv>Department of Software Technology</orgdiv>
</affiliation>
<contrib>Author</contrib>
</author>
<copyright>
<year>2004-2012</year>
<year>2004</year>
<year>2005</year>
<year>2006</year>
<year>2007</year>
<year>2008</year>
<year>2009</year>
<holder>Eelco Dolstra</holder>
</copyright>
<date>May 2012</date>
<date>September 2009</date>
</info>

View File

@@ -28,8 +28,8 @@
</group>
<replaceable>attrPath</replaceable>
</arg>
<arg><option>--drv-link</option> <replaceable>drvlink</replaceable></arg>
<arg><option>--add-drv-link</option></arg>
<arg><option>--drv-link </option><replaceable>drvlink</replaceable></arg>
<arg><option>--no-out-link</option></arg>
<arg>
<group choice='req'>
@@ -38,11 +38,6 @@
</group>
<replaceable>outlink</replaceable>
</arg>
<arg>
<option>--run-env</option>
<arg><option>--command</option> <replaceable>cmd</replaceable></arg>
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
</arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -75,45 +70,39 @@ a root of the Nix garbage collector. This root disappears
automatically when the <filename>result</filename> symlink is deleted
or renamed. So dont rename the symlink.</para></warning>
<para>The subcommand <command>nix-build --run-env</command> will build
the dependencies of the derivation, but not the derivation itself. It
will then start an interactive shell in which all environment
variables defined by the derivation have been set to their
corresponding values. This is useful for reproducing the environment
of a derivation for development.</para>
</refsection>
<refsection><title>Options</title>
<para>All options not listed here are passed to <command>nix-store
--realise</command>, except for <option>--arg</option> and
<option>--attr</option> / <option>-A</option> which are passed to
<command>nix-instantiate</command>. <phrase condition="manual">See
also <xref linkend="sec-common-options" />.</phrase></para>
<para>See also <xref linkend="sec-common-options" />. All options not
listed here are passed to <command>nix-store --realise</command>,
except for <option>--arg</option> and <option>--attr</option> /
<option>-A</option> which are passed to
<command>nix-instantiate</command>.</para>
<variablelist>
<varlistentry><term><option>--drv-link</option> <replaceable>drvlink</replaceable></term>
<listitem><para>Add a symlink named
<replaceable>drvlink</replaceable> to the store derivation
produced by <command>nix-instantiate</command>. The derivation is
a root of the garbage collector until the symlink is deleted or
renamed. If there are multiple derivations, numbers are suffixed
to <replaceable>drvlink</replaceable> to distinguish between
them.</para></listitem>
</varlistentry>
<varlistentry><term><option>--add-drv-link</option></term>
<listitem><para>Shorthand for <option>--drv-link</option>
<filename>./derivation</filename>.</para></listitem>
<listitem><para>Add a symlink in the current directory to the
store derivation produced by <command>nix-instantiate</command>.
The symlink is called <filename>derivation</filename> (which is
numbered in the case of multiple derivations). The derivation is
a root of the garbage collector until the symlink is deleted or
renamed.</para></listitem>
</varlistentry>
<varlistentry><term><option>--drv-link</option> <replaceable>drvlink</replaceable></term>
<listitem><para>Change the name of the symlink to the derivation
created when <option>--add-drv-link</option> is used from
<filename>derivation</filename> to
<replaceable>drvlink</replaceable>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--no-out-link</option></term>
<listitem><para>Do not create a symlink to the output path. Note
@@ -127,46 +116,21 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<option>-o</option> <replaceable>outlink</replaceable></term>
<listitem><para>Change the name of the symlink to the output path
created from <filename>result</filename> to
created unless <option>--no-out-link</option> is used from
<filename>result</filename> to
<replaceable>outlink</replaceable>.</para></listitem>
</varlistentry>
</variablelist>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
<para>The following options apply to <command>nix-build --run-env</command>.</para>
<variablelist>
<varlistentry><term><option>--command</option> <replaceable>cmd</replaceable></term>
<listitem><para>In the environment of the derivation, executeq the
command <replaceable>cmd</replaceable> instead of the default
interactive shell.</para></listitem>
</varlistentry>
<varlistentry><term><option>--exclude</option> <replaceable>regexp</replaceable></term>
<listitem><para>Do not build any dependencies whose store path
matches the regular expression <replaceable>regexp</replaceable>.
This option may be specified multiple times.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection><title>Examples</title>
<screen>
$ nix-build '&lt;nixpkgs>' -A firefox
$ nix-build pkgs/top-level/all-packages.nix -A firefox
store derivation is /nix/store/qybprl8sz2lc...-firefox-1.5.0.7.drv
/nix/store/d18hyl92g30l...-firefox-1.5.0.7
@@ -176,31 +140,7 @@ lrwxrwxrwx <replaceable>...</replaceable> result -> /nix/store/d18hyl92g30l...
$ ls ./result/bin/
firefox firefox-config</screen>
<para>To build the dependencies of the package Pan, and start an
interactive shell in which to build it:
<screen>
$ nix-build '&lt;nixpkgs>' --run-env -A pan
$ tar xf $src
$ cd pan-*
$ ./configure
$ make
$ ./pan/gui/pan
</screen>
</para>
</refsection>
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
</variablelist>
</refsection>
</refentry>

View File

@@ -19,10 +19,10 @@
<cmdsynopsis>
<command>nix-channel</command>
<group choice='req'>
<arg choice='plain'><option>--add</option> <replaceable>url</replaceable> <arg choice='opt'><replaceable>name</replaceable></arg></arg>
<arg choice='plain'><option>--add</option> <replaceable>url</replaceable></arg>
<arg choice='plain'><option>--remove</option> <replaceable>url</replaceable></arg>
<arg choice='plain'><option>--list</option></arg>
<arg choice='plain'><option>--update</option> <arg rep='repeat'><replaceable>names</replaceable></arg></arg>
<arg choice='plain'><option>--update</option></arg>
</group>
</cmdsynopsis>
</refsynopsisdiv>
@@ -31,51 +31,43 @@
<para>A Nix channel is mechanism that allows you to automatically stay
up-to-date with a set of pre-built Nix expressions. A Nix channel is
just a URL that points to a place containing a set of Nix expressions
and a <command>nix-push</command> manifest. <phrase
condition="manual">See also <xref linkend="sec-channels"
/>.</phrase></para>
just a URL that points to a place that contains a set of Nix
expressions, as well as a <command>nix-push</command> manifest. See
also <xref linkend="sec-channels" />.</para>
<para>This command has the following operations:
<variablelist>
<varlistentry><term><option>--add</option> <replaceable>url</replaceable> [<replaceable>name</replaceable>]</term>
<varlistentry><term><option>--add</option> <replaceable>url</replaceable></term>
<listitem><para>Adds a channel named
<replaceable>name</replaceable> with URL
<replaceable>url</replaceable> to the list of subscribed channels.
If <replaceable>name</replaceable> is omitted, it defaults to the
last component of <replaceable>url</replaceable>, with the
suffixes <literal>-stable</literal> or
<literal>-unstable</literal> removed.</para></listitem>
<listitem><para>Adds <replaceable>url</replaceable> to the list of
subscribed channels.</para></listitem>
</varlistentry>
<varlistentry><term><option>--remove</option> <replaceable>name</replaceable></term>
<varlistentry><term><option>--remove</option> <replaceable>url</replaceable></term>
<listitem><para>Removes the channel named
<replaceable>name</replaceable> from the list of subscribed
channels.</para></listitem>
<listitem><para>Removes <replaceable>url</replaceable> from the
list of subscribed channels.</para></listitem>
</varlistentry>
<varlistentry><term><option>--list</option></term>
<listitem><para>Prints the names and URLs of all subscribed
channels on standard output.</para></listitem>
<listitem><para>Prints the URLs of all subscribed channels on
standard output.</para></listitem>
</varlistentry>
<varlistentry><term><option>--update</option> [<replaceable>names</replaceable>…]</term>
<varlistentry><term><option>--update</option></term>
<listitem><para>Downloads the Nix expressions of all subscribed
channels (or only those included in
<replaceable>names</replaceable> if specified), makes them the
default for <command>nix-env</command> operations (by symlinking
them from 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>
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>
@@ -83,8 +75,8 @@ condition="manual">See also <xref linkend="sec-channels"
</para>
<para>Note that <option>--add</option> does not automatically perform
an update.</para>
<para>Note that <option>--add</option> and <option>--remove</option>
do not automatically perform an update.</para>
<para>The list of subscribed channels is stored in
<filename>~/.nix-channels</filename>.</para>
@@ -98,15 +90,4 @@ respectively.</para>
</refsection>
<refsection><title>Examples</title>
<para>To subscribe to the Nixpkgs channel and install the GNU Hello package:</para>
<screen>
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable
$ nix-channel --update
$ nix-env -iA nixpkgs.hello</screen>
</refsection>
</refentry>

View File

@@ -24,12 +24,8 @@
</group>
<arg><option>--sign</option></arg>
<arg><option>--gzip</option></arg>
<arg><option>--bzip2</option></arg>
<arg><option>--xz</option></arg>
<arg><option>--show-progress</option></arg>
<arg><option>--include-outputs</option></arg>
<arg choice='plain'>
<replaceable>user@</replaceable><replaceable>machine</replaceable>
<arg><replaceable>user@</replaceable></arg><replaceable>machine</replaceable>
</arg>
<arg choice='plain'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
@@ -88,43 +84,25 @@ those paths. If this bothers you, use
<listitem><para>Let the sending machine cryptographically sign the
dump of each path with the key in
<filename><replaceable>sysconfdir</replaceable>/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><replaceable>sysconfdir</replaceable>/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>
<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> / <option>--bzip2</option> / <option>--xz</option></term>
<varlistentry><term><option>--gzip</option></term>
<listitem><para>Compress the dump of each path with respectively
<command>gzip</command>, <command>bzip2</command> or
<command>xz</command> before sending it. The corresponding
decompression program must be installed on the target
machine.</para></listitem>
<listitem><para>Compress the dump of each path with
<command>gzip</command> before sending it.</para></listitem>
</varlistentry>
<varlistentry><term><option>--show-progress</option></term>
<listitem><para>Show the progress of each path's transfer as it's made.
This requires the <command>pv</command> utility to be in <envar>PATH</envar>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--include-outputs</option></term>
<listitem><para>Also copy the outputs of store derivations included
in the closure.</para></listitem>
</varlistentry>
</variablelist>
</refsection>

View File

@@ -2,7 +2,7 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-nix-env">
<refmeta>
<refentrytitle>nix-env</refentrytitle>
<manvolnum>1</manvolnum>
@@ -18,7 +18,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-env</command>
<xi:include href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg>
@@ -60,7 +60,7 @@ environments.</para>
<para><command>nix-env</command> takes exactly one
<emphasis>operation</emphasis> flag which indicates the subcommand to
be performed. These are documented below.</para>
</refsection>
@@ -71,26 +71,26 @@ be performed. These are documented below.</para>
<para>This section lists the options that are common to all
operations. These options are allowed for every subcommand, though
they may not always have an effect. <phrase condition="manual">See
also <xref linkend="sec-common-options" />.</phrase></para>
they may not always have an effect. See also <xref
linkend="sec-common-options" />.</para>
<variablelist>
<varlistentry><term><option>--file</option></term>
<term><option>-f</option></term>
<listitem><para>Specifies the Nix expression (designated below as
the <emphasis>active Nix expression</emphasis>) used by the
<option>--install</option>, <option>--upgrade</option>, and
<option>--query --available</option> operations to obtain
derivations. The default is
<filename>~/.nix-defexpr</filename>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--profile</option></term>
<term><option>-p</option></term>
<listitem><para>Specifies the profile to be used by those
operations that operate on a profile (designated below as the
<emphasis>active profile</emphasis>). A profile is sequence of
@@ -98,11 +98,11 @@ also <xref linkend="sec-common-options" />.</phrase></para>
which is the <emphasis>current generation</emphasis>. The default
profile is the target of the symbolic link
<filename>~/.nix-profile</filename> (see below).</para></listitem>
</varlistentry>
<varlistentry><term><option>--dry-run</option></term>
<listitem><para>For the <option>--install</option>,
<option>--upgrade</option>, <option>--uninstall</option>,
<option>--switch-generation</option> and
@@ -117,25 +117,23 @@ also <xref linkend="sec-common-options" />.</phrase></para>
substitute is available).</para></listitem>
</varlistentry>
<varlistentry><term><option>--system-filter</option> <replaceable>system</replaceable></term>
<listitem><para>By default, operations such as <option>--query
--available</option> show derivations matching any platform. This
option allows you to use derivations for the specified platform
<replaceable>system</replaceable>.</para></listitem>
--available</option> only include derivations matching the current
platform. This option allows you to use derivations for the
specified platform <replaceable>system</replaceable>. The special
value <literal>*</literal> causes derivations for any platform to
be included.</para></listitem>
</varlistentry>
</variablelist>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
</refsection>
<!--######################################################################-->
@@ -172,25 +170,25 @@ also <xref linkend="sec-common-options" />.</phrase></para>
this directory.</para>
</listitem>
</varlistentry>
<varlistentry><term><filename>~/.nix-profile</filename></term>
<listitem><para>A symbolic link to the user's current profile. By
default, this symlink points to
<filename><replaceable>prefix</replaceable>/var/nix/profiles/default</filename>.
The <envar>PATH</envar> environment variable should include
<filename>~/.nix-profile/bin</filename> for the user environment
to be visible to the user.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<!--######################################################################-->
@@ -216,7 +214,7 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<refsection><title>Description</title>
<para>The install operation creates a new user environment, based on
the current generation of the active profile, to which a set of store
paths described by <replaceable>args</replaceable> is added. The
@@ -258,7 +256,7 @@ number of possible ways:
<emphasis>attribute paths</emphasis> that select attributes from the
top-level Nix expression. This is faster than using derivation
names and unambiguous. To find out the attribute paths of available
packages, use <literal>nix-env -qaP '*'</literal>.</para></listitem>
packages, use <literal>nix-env -qaA '*'</literal>.</para></listitem>
<listitem><para>If <option>--from-profile</option>
<replaceable>path</replaceable> is given,
@@ -308,20 +306,20 @@ number of possible ways:
<varlistentry><term><option>--preserve-installed</option></term>
<term><option>-P</option></term>
<listitem><para>Do not remove derivations with a name matching one
of the derivations being installed. Usually, trying to have two
versions of the same package installed in the same generation of a
profile will lead to an error in building the generation, due to
file name clashes between the two versions. However, this is not
the case for all packages.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection xml:id='refsec-nix-env-install-examples'><title>Examples</title>
@@ -329,7 +327,7 @@ number of possible ways:
active Nix expression:
<screen>
$ nix-env --install gcc-3.3.2
$ nix-env --install gcc-3.3.2
installing `gcc-3.3.2'
uninstalling `gcc-3.1'</screen>
@@ -410,15 +408,15 @@ the following paths will be substituted:
/nix/store/8zbipvm4gp9jfqh9nnk1n3bary1a37gs-perl-XML-Parser-2.34
/nix/store/b8a2bg7gnyvvvjjibp4axg9x1hzkw36c-mono-1.1.4
<replaceable>...</replaceable></screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id="rsec-nix-env-upgrade"><title>Operation <option>--upgrade</option></title>
@@ -444,7 +442,7 @@ the following paths will be substituted:
</refsection>
<refsection><title>Description</title>
<para>The upgrade operation creates a new user environment, based on
the current generation of the active profile, in which all store paths
are replaced for which there are newer versions in the set of paths
@@ -461,47 +459,47 @@ the same symbolic name, only the one with the highest version is
installed.</para>
</refsection>
<refsection><title>Flags</title>
<variablelist>
<varlistentry><term><option>--lt</option></term>
<listitem><para>Only upgrade a derivation to newer versions. This
is the default.</para></listitem>
</varlistentry>
<varlistentry><term><option>--leq</option></term>
<listitem><para>In addition to upgrading to newer versions, also
“upgrade” to derivations that have the same version. Version are
not a unique identification of a derivation, so there may be many
derivations that have the same version. This flag may be useful
to force “synchronisation” between the installed and available
derivations.</para></listitem>
</varlistentry>
<varlistentry><term><option>--eq</option></term>
<listitem><para><emphasis>Only</emphasis> “upgrade” to derivations
that have the same version. This may not seem very useful, but it
actually is, e.g., when there is a new release of Nixpkgs and you
want to replace installed applications with the same versions
built against newer dependencies (to reduce the number of
dependencies floating around on your system).</para></listitem>
</varlistentry>
<varlistentry><term><option>--always</option></term>
<listitem><para>In addition to upgrading to newer versions, also
“upgrade” to derivations that have the same or a lower version.
I.e., derivations may actually be downgraded depending on what is
available in the active Nix expression.</para></listitem>
</varlistentry>
</variablelist>
@@ -525,10 +523,10 @@ $ nix-env --upgrade pan
$ nix-env -u '*' <lineannotation>(try to upgrade everything)</lineannotation>
upgrading `hello-2.1.2' to `hello-2.1.3'
upgrading `mozilla-1.2' to `mozilla-1.4'</screen>
upgrading `mozilla-1.2' to `mozilla-1.4'</screen>
</refsection>
<refsection xml:id="ssec-version-comparisons"><title>Versions</title>
<para>The upgrade operation determines whether a derivation
@@ -572,14 +570,14 @@ lexicographically (i.e., using case-sensitive string comparison).</para>
2.3a &lt; 2.3c
2.3pre1 &lt; 2.3c
2.3pre1 &lt; 2.3q</screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
@@ -598,14 +596,14 @@ lexicographically (i.e., using case-sensitive string comparison).</para>
</refsection>
<refsection><title>Description</title>
<para>The uninstall operation creates a new user environment, based on
the current generation of the active profile, from which the store
paths designated by the symbolic names
<replaceable>names</replaceable> are removed.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
@@ -613,11 +611,11 @@ $ nix-env --uninstall gcc
$ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id="rsec-nix-env-set-flag"><title>Operation <option>--set-flag</option></title>
@@ -634,7 +632,7 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
</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
@@ -672,7 +670,7 @@ script:
</para>
</refsection>
<refsection><title>Examples</title>
<para>To prevent the currently installed Firefox from being upgraded:
@@ -718,13 +716,13 @@ $ nix-env --set-flag priority 10 gcc</screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--query</option></title>
<refsection><title>Synopsis</title>
@@ -740,9 +738,9 @@ $ nix-env --set-flag priority 10 gcc</screen>
<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>
@@ -787,7 +785,7 @@ $ nix-env --set-flag priority 10 gcc</screen>
</arg>
<sbr />
<arg choice='plain' rep='repeat'><replaceable>names</replaceable></arg>
</cmdsynopsis>
@@ -795,7 +793,7 @@ $ nix-env --set-flag priority 10 gcc</screen>
<refsection><title>Description</title>
<para>The query operation displays information about either the store
paths that are installed in the current generation of the active
profile (<option>--installed</option>), or the derivations that are
@@ -819,23 +817,23 @@ operates.</para>
<variablelist>
<varlistentry><term><option>--installed</option></term>
<listitem><para>The query operates on the store paths that are
installed in the current generation of the active profile. This
is the default.</para></listitem>
</varlistentry>
<varlistentry><term><option>--available</option></term>
<term><option>-a</option></term>
<listitem><para>The query operates on the derivations that are
available in the active Nix expression.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -876,7 +874,7 @@ user environment elements, etc. -->
<varlistentry><term><option>--status</option></term>
<term><option>-s</option></term>
<listitem><para>Print the <emphasis>status</emphasis> of the
derivation. The status consists of three characters. The first
is <literal>I</literal> or <literal>-</literal>, indicating
@@ -890,7 +888,7 @@ user environment elements, etc. -->
third is <literal>S</literal> or <literal>-</literal>, indicating
whether a substitute is available for the
derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--attr-path</option></term>
@@ -903,17 +901,17 @@ user environment elements, etc. -->
<literal>nix-env --install</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--no-name</option></term>
<listitem><para>Suppress printing of the <literal>name</literal>
attribute of each derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--compare-versions</option> /
<option>-c</option></term>
<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
@@ -928,21 +926,21 @@ user environment elements, etc. -->
or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>=</literal> <replaceable>version</replaceable></term>
<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 package are
available or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>- ?</literal></term>
<listitem><para>No version of the package is available or
@@ -953,45 +951,45 @@ user environment elements, etc. -->
</variablelist>
</para></listitem>
</varlistentry>
<varlistentry><term><option>--system</option></term>
<listitem><para>Print the <literal>system</literal> attribute of
the derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--drv-path</option></term>
<listitem><para>Print the path of the store
derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--out-path</option></term>
<listitem><para>Print the output path of the
derivation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--description</option></term>
<listitem><para>Print a short (one-line) description of the
derivation, if available. The description is taken from the
<literal>meta.description</literal> attribute of the
derivation.</para></listitem>
</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>
@@ -1025,7 +1023,7 @@ IP- ORBit2-2.8.3 <lineannotation>(installed and by definition present)</linea
...
<lineannotation>(show available derivations in the Nix expression <!-- !!! <filename>-->foo.nix<!-- </filename> -->)</lineannotation>
$ nix-env -f ./foo.nix -qa '*'
$ nix-env -f ./foo.nix -qa '*'
foo-1.2.3
$ nix-env -qc '*' <lineannotation>(compare installed versions to whats available)</lineannotation>
@@ -1036,7 +1034,7 @@ firefox-1.0.4 &lt; 1.0.7 <lineannotation>(a more recent version is availab
<replaceable>...</replaceable>
<lineannotation>(show info about a specific package, in XML)</lineannotation>
$ nix-env -qa --xml --description firefox
$ nix-env -qa --xml --description firefox
<![CDATA[<?xml version='1.0' encoding='utf-8'?>
<items>
<item attrPath="0.0.firefoxWrapper"
@@ -1047,8 +1045,8 @@ $ nix-env -qa --xml --description firefox
</refsection>
</refsection>
<!--######################################################################-->
@@ -1069,25 +1067,25 @@ $ nix-env -qa --xml --description firefox
<refsection><title>Description</title>
<para>This operation makes <replaceable>path</replaceable> the current
profile for the user. That is, the symlink
<filename>~/.nix-profile</filename> is made to point to
<replaceable>path</replaceable>.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
$ nix-env -S ~/my-profile</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--list-generations</option></title>
@@ -1103,7 +1101,7 @@ $ nix-env -S ~/my-profile</screen>
<refsection><title>Description</title>
<para>This operation print a list of all the currently existing
generations for the active profile. These may be switched to using
the <option>--switch-generation</option> operation. It also prints
@@ -1123,11 +1121,11 @@ $ nix-env --list-generations
98 2004-02-06 16:24:33 (current)</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--delete-generations</option></title>
@@ -1144,7 +1142,7 @@ $ nix-env --list-generations
<refsection><title>Description</title>
<para>This operation deletes the specified generations of the current
profile. The generations can be a list of generation numbers, or the
special value <literal>old</literal> to delete all non-current
@@ -1152,7 +1150,7 @@ generations. Periodically deleting old generations is important to
make garbage collection effective.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
@@ -1161,11 +1159,11 @@ $ nix-env --delete-generations 3 4 8
$ nix-env -p other_profile --delete-generations old</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--switch-generation</option></title>
@@ -1185,7 +1183,7 @@ $ nix-env -p other_profile --delete-generations old</screen>
<refsection><title>Description</title>
<para>This operation makes generation number
<replaceable>generation</replaceable> the current generation of the
active profile. That is, if the
@@ -1209,11 +1207,11 @@ $ nix-env -G 42
switching from generation 50 to 42</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--rollback</option></title>
@@ -1228,7 +1226,7 @@ switching from generation 50 to 42</screen>
</refsection>
<refsection><title>Description</title>
<para>This operation switches to the “previous” generation of the
active profile, that is, the highest numbered generation lower than
the current generation, if it exists. It is just a convenience
@@ -1248,17 +1246,9 @@ $ nix-env --rolback
error: no generation older than the current (91) exists</screen>
</refsection>
</refsection>
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
</variablelist>
</refsection>
</refentry>

View File

@@ -36,7 +36,6 @@
<option>--eval-only</option>
<arg><option>--strict</option></arg>
</arg>
<arg choice='plain'><option>--find-file</option></arg>
</group>
<arg><option>--xml</option></arg>
</arg>
@@ -50,9 +49,8 @@
<para>The command <command>nix-instantiate</command> generates <link
linkend="gloss-derivation">store derivations</link> from (high-level)
Nix expressions. It loads and evaluates the Nix expressions in each
of <replaceable>files</replaceable> (which defaults to
<replaceable>./default.nix</replaceable>). Each top-level expression
should evaluate to a derivation, a list of derivations, or a set of
of <replaceable>files</replaceable>. Each top-level expression should
evaluate to a derivation, a list of derivations, or a set of
derivations. The paths of the resulting store derivations are printed
on standard output.</para>
@@ -66,8 +64,8 @@ store derivation instantiation from Nix expressions automatically).
It is most commonly used for implementing new deployment
policies.</para>
<para condition="manual">See also <xref linkend="sec-common-options"
/> for a list of common options.</para>
<para>See also <xref linkend="sec-common-options" /> for a list of
common options.</para>
</refsection>
@@ -102,19 +100,6 @@ policies.</para>
</varlistentry>
<varlistentry><term><option>--find-file</option></term>
<listitem><para>Look up the given files in Nixs search path (as
specified by the <envar>NIX_PATH</envar> environment variable).
If found, print the corresponding absolute paths on standard
output. For instance, if <envar>NIX_PATH</envar> is
<literal>nixpkgs=/home/alice/nixpkgs</literal>, then
<literal>nix-instantiate --find-file nixpkgs/default.nix</literal>
will print
<literal>/home/alice/nixpkgs/default.nix</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><option>--xml</option></term>
<listitem><para>When used with <option>--parse-only</option> and
@@ -142,10 +127,6 @@ policies.</para>
</variablelist>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
</refsection>
@@ -217,13 +198,4 @@ $ echo 'rec { x = "foo"; y = x; }' | nix-instantiate --eval-only --xml --strict
</refsection>
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
</variablelist>
</refsection>
</refentry>

View File

@@ -12,7 +12,7 @@
<refnamediv>
<refname>nix-prefetch-url</refname>
<refpurpose>copy a file from a URL into the store and print its hash</refpurpose>
<refpurpose>copy a file from a URL into the store and print its MD5 hash</refpurpose>
</refnamediv>
<refsynopsisdiv>

View File

@@ -120,7 +120,7 @@ dependencies used in the build, such as compilers).</para>
dependencies, we can do:
<screen>
$ nix-push <replaceable>urls</replaceable> $(nix-store -r $(nix-instantiate foo.nix))</screen>
$ nix-push <replaceable>urls</replaceable> $(nix-instantiate $(nix-store -r foo.nix))</screen>
</para>

View File

@@ -48,9 +48,8 @@ be performed. These are documented below.</para>
<para>This section lists the options that are common to all
operations. These options are allowed for every subcommand, though
they may not always have an effect. <phrase condition="manual">See
also <xref linkend="sec-common-options" /> for a list of common
options.</phrase></para>
they may not always have an effect. See also <xref
linkend="sec-common-options" /> for a list of common options.</para>
<variablelist>
@@ -58,9 +57,8 @@ options.</phrase></para>
<listitem><para>Causes the result of a realisation
(<option>--realise</option> and <option>--force-realise</option>)
to be registered as a root of the garbage collector<phrase
condition="manual"> (see <xref linkend="ssec-gc-roots"
/>)</phrase>. The root is stored in
to be registered as a root of the garbage collector (see <xref
linkend="ssec-gc-roots" />). The root is stored in
<replaceable>path</replaceable>, which must be inside a directory
that is scanned for roots by the garbage collector (i.e.,
typically in a subdirectory of
@@ -114,10 +112,6 @@ lrwxrwxrwx 1 ... 2005-03-13 21:10 /home/eelco/bla/result -> /nix/store/1r1134
</variablelist>
<variablelist condition="manpage">
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
</variablelist>
</refsection>
@@ -218,6 +212,7 @@ linkend="sec-nix-build"><command>nix-build</command></link> does.</para>
<arg choice='plain'><option>--delete</option></arg>
</group>
<arg><option>--max-freed</option> <replaceable>bytes</replaceable></arg>
<arg><option>--max-links</option> <replaceable>nrlinks</replaceable></arg>
</cmdsynopsis>
</refsection>
@@ -285,6 +280,16 @@ options control what gets deleted and in what order:
</varlistentry>
<varlistentry><term><option>--max-links</option> <replaceable>nrlinks</replaceable></term>
<listitem><para>Keep deleting paths until the hard link count on
<filename>/nix/store</filename> is less than
<replaceable>nrlinks</replaceable>, then stop. This is useful for
very large Nix stores on filesystems with a 32000 subdirectories
limit (like <literal>ext3</literal>).</para></listitem>
</varlistentry>
</variablelist>
</para>
@@ -337,7 +342,7 @@ $ nix-store --gc --max-freed $((100 * 1024 * 1024))</screen>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--delete</option></arg>
<arg choice='plain'><option>--gc</option></arg>
<arg><option>--ignore-liveness</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
@@ -399,7 +404,6 @@ error: cannot delete path `/nix/store/zq0h41l75vlb4z45kzgjjmsjxvcv1qk7-mesa-6.4'
<arg choice='plain'><option>--tree</option></arg>
<arg choice='plain'><option>--binding</option> <replaceable>name</replaceable></arg>
<arg choice='plain'><option>--hash</option></arg>
<arg choice='plain'><option>--size</option></arg>
<arg choice='plain'><option>--roots</option></arg>
</group>
<arg><option>--use-output</option></arg>
@@ -583,21 +587,9 @@ query is applied to the target of the symlink.</para>
<varlistentry><term><option>--hash</option></term>
<listitem><para>Prints the SHA-256 hash of the contents of the
store paths <replaceable>paths</replaceable> (that is, the hash of
the output of <command>nix-store --dump</command> on the given
paths). Since the hash is stored in the Nix database, this is a
fast operation.</para></listitem>
</varlistentry>
<varlistentry><term><option>--size</option></term>
<listitem><para>Prints the size in bytes of the contents of the
store paths <replaceable>paths</replaceable> — to be precise, the
size of the output of <command>nix-store --dump</command> on the
given paths. Note that the actual disk space required by the
store paths may be higher, especially on filesystems with large
cluster sizes.</para></listitem>
store paths <replaceable>paths</replaceable>. Since the hash is
stored in the Nix database, this is a fast
operation.</para></listitem>
</varlistentry>
@@ -729,40 +721,6 @@ $ nix-store -q --roots $(which svn)
<!--######################################################################-->
<refsection><title>Operation <option>--add</option></title>
<refsection><title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--add</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--add</option> adds the specified paths to
the Nix store. It prints the resulting paths in the Nix store on
standard output.</para>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store --add ./foo.c
/nix/store/m7lrha58ph6rcnv109yzx1nk1cj7k7zf-foo.c</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id='refsec-nix-store-verify'><title>Operation <option>--verify</option></title>
@@ -810,44 +768,6 @@ in Nix itself.</para>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--verify-path</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--verify-path</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--verify-paths</option> compares the
contents of the given store paths to their cryptographic hashes stored
in Nixs database. For every changed path, it prints a warning
message. The exit status is 0 if no path has changed, and 1
otherwise.</para>
</refsection>
<refsection><title>Example</title>
<para>To verify the integrity of the <command>svn</command> command and all its dependencies:
<screen>
$ nix-store --verify-path $(nix-store -qR $(which svn))
</screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id='refsec-nix-store-dump'><title>Operation <option>--dump</option></title>
@@ -1120,7 +1040,7 @@ backups and when migrating to different database schemas.</para>
<!--######################################################################-->
<refsection><title>Operation <option>--load-db</option></title>
<refsection><title>Operation <option>--dump-db</option></title>
<refsection>
<title>Synopsis</title>
@@ -1141,129 +1061,4 @@ loads it into the Nix database.</para>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--print-env</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--print-env</option></arg>
<arg choice='plain'><replaceable>drvpath</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--print-env</option> prints out the
environment of a derivation in a format that can be evaluated by a
shell. The command line arguments of the builder are placed in the
variable <envar>_args</envar>.</para>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store --print-env $(nix-instantiate '&lt;nixpkgs>' -A firefox)
<replaceable></replaceable>
export src; src='/nix/store/plpj7qrwcz94z2psh6fchsi7s8yihc7k-firefox-12.0.source.tar.bz2'
export stdenv; stdenv='/nix/store/7c8asx3yfrg5dg1gzhzyq2236zfgibnm-stdenv'
export system; system='x86_64-linux'
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh'
</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--query-failed-paths</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--query-failed-paths</option></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>If build failure caching is enabled through the
<literal>build-cache-failures</literal> configuration option, the
operation <option>--query-failed-paths</option> will print out all
store paths that have failed to build.</para>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store --query-failed-paths
/nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
/nix/store/0011iy7sfwbc1qj5a1f6ifjnbcdail8a-haskell-gitit-ghc7.0.4-0.8.1
/nix/store/001c0yn1hkh86gprvrb46cxnz3pki7q3-gamin-0.1.10
<replaceable></replaceable>
</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--clear-failed-paths</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--clear-failed-paths</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>If build failure caching is enabled through the
<literal>build-cache-failures</literal> configuration option, the
operation <option>--clear-failed-paths</option> clears the “failed”
state of the given store paths, allowing them to be built again. This
is useful if the failure was actually transient (e.g. because the disk
was full).</para>
<para>If a path denotes a derivation, its output paths are cleared.
You can provide the argument <literal>*</literal> to clear all store
paths.</para>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store --clear-failed-path /nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
$ nix-store --clear-failed-path *
</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection condition="manpage"><title>Environment variables</title>
<variablelist>
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
</variablelist>
</refsection>
</refentry>

View File

@@ -14,15 +14,7 @@
<replaceable>number</replaceable>
</arg>
<arg>
<option>--cores</option>
<replaceable>number</replaceable>
</arg>
<arg>
<option>--max-silent-time</option>
<replaceable>number</replaceable>
</arg>
<arg>
<option>--timeout</option>
<arg><option>--max-silent-time</option></arg>
<replaceable>number</replaceable>
</arg>
<arg><option>--keep-going</option></arg>
@@ -33,10 +25,6 @@
<arg><option>--readonly-mode</option></arg>
<arg><option>--log-type</option> <replaceable>type</replaceable></arg>
<arg><option>--show-trace</option></arg>
<arg>
<option>-I</option>
<replaceable>path</replaceable>
</arg>
<sbr />
</nop>

View File

@@ -5,7 +5,7 @@
<para>Most Nix commands accept the following command-line options:</para>
<variablelist xml:id="opt-common">
<variablelist>
<varlistentry><term><option>--help</option></term>
@@ -98,25 +98,7 @@
linkend='conf-build-max-jobs'><literal>build-max-jobs</literal></link>
configuration setting, which itself defaults to
<literal>1</literal>. A higher value is useful on SMP systems or to
exploit I/O latency.</para></listitem>
</varlistentry>
<varlistentry xml:id="opt-cores"><term><option>--cores</option></term>
<listitem><para>Sets the value of the <envar>NIX_BUILD_CORES</envar>
environment variable in the invocation of builders. Builders can
use this variable at their discretion to control the maximum amount
of parallelism. For instance, in Nixpkgs, if the derivation
attribute <varname>enableParallelBuilding</varname> is set to
<literal>true</literal>, the builder passes the
<option>-j<replaceable>N</replaceable></option> flag to GNU Make.
It defaults to the value of the <link
linkend='conf-build-cores'><literal>build-cores</literal></link>
configuration setting, if set, or <literal>1</literal> otherwise.
The value <literal>0</literal> means that the builder should use all
available CPU cores in the system.</para></listitem>
exploit I/O latency. </para></listitem>
</varlistentry>
@@ -132,16 +114,6 @@
</varlistentry>
<varlistentry xml:id="opt-timeout"><term><option>--timeout</option></term>
<listitem><para>Sets the maximum number of seconds that a builder
can run. The default is specified by the <link
linkend='conf-build-timeout'><literal>build-timeout</literal></link>
configuration setting. <literal>0</literal> means no
timeout.</para></listitem>
</varlistentry>
<varlistentry><term><option>--keep-going</option></term>
<term><option>-k</option></term>
@@ -264,8 +236,8 @@
expression evaluator will automatically try to call functions that
it encounters. It can automatically call functions for which every
argument has a <link linkend='ss-functions'>default value</link>
(e.g., <literal>{ <replaceable>argName</replaceable> ?
<replaceable>defaultValue</replaceable> }:
(e.g., <literal>{<replaceable>argName</replaceable> ?
<replaceable>defaultValue</replaceable>}:
<replaceable>...</replaceable></literal>). With
<option>--arg</option>, you can also call functions that have
arguments without a default value (or override a default value).
@@ -341,16 +313,6 @@
</varlistentry>
<varlistentry><term><option>-I</option> <replaceable>path</replaceable></term>
<listitem><para>Add a path to the Nix expression search path. See
the <envar>NIX_PATH</envar> environment variable for details. Paths
added through <option>-I</option> take precedence over
<envar>NIX_PATH</envar>.</para></listitem>
</varlistentry>
</variablelist>

View File

@@ -38,7 +38,7 @@ to end-user applications like Mozilla Firefox. (Nix is however not
tied to the Nix Package collection; you could write your own Nix
expressions based on it, or completely new ones.) You can download
the latest version from <link
xlink:href='http://nixos.org/nixpkgs/download.html' />.</para>
xlink:href='http://nixos.org/releases/full-index-nixpkgs.html' />.</para>
<para>Assuming that you have downloaded and unpacked a release of Nix
Packages, you can view the set of available packages in the release:
@@ -496,7 +496,7 @@ available in the subscribed channels.</para>
<para>Often, when you want to install a specific package (e.g., from
the <link
xlink:href="http://nixos.org/nixpkgs/">Nix
xlink:href="http://nixos.org/releases/nixpkgs/nixpkgs-unstable/">Nix
Packages collection</link>), subscribing to a channel is a bit
cumbersome. And channels dont help you at all if you want to install
an older version of a package than the one provided by the current

View File

@@ -11,9 +11,9 @@ to the following chapters.</para>
<orderedlist>
<listitem><para>Download a source tarball or RPM or Debian/Ubuntu
package from <link xlink:href='http://nixos.org/'/>. Build source
distributions using the regular sequence:
<listitem><para>Download a source tarball, RPM or Deb from <link
xlink:href='http://nixos.org/'/>. Build source distributions using
the regular sequence:
<screen>
$ tar xvfj nix-<replaceable>version</replaceable>.tar.bz2
@@ -41,7 +41,8 @@ file).</para></listitem>
<listitem><para>Subscribe to the Nix Packages channel.
<screen>
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
$ nix-channel --add \
http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
</para></listitem>
@@ -59,7 +60,7 @@ available remotely.</para></listitem>
in the channel:
<screen>
$ nix-env -qa \*
$ nix-env -qa * <lineannotation>(mind the quotes!)</lineannotation>
docbook-xml-4.2
firefox-1.0pre-PR-0.10.1
hello-2.1.1
@@ -107,10 +108,10 @@ numbers).</para></listitem>
<listitem><para>You can also install specific packages directly from
your web browser. For instance, you can go to <link
xlink:href="http://hydra.nixos.org/jobset/nixpkgs/trunk/channel/latest"
/> and click on any link for the individual packages for your
platform. Associate <literal>application/nix-package</literal> with
the program <command>nix-install-package</command>. A window should
xlink:href="http://hydra.nixos.org/jobset/nixpkgs/trunk/channel/latest" />
and click on any link for the individual packages for your platform.
Associate <literal>application/nix-package</literal> with the program
<filename>/nix/bin/nix-install-package</filename>. A window should
appear asking you whether its okay to install the package. Say
<literal>Y</literal>. The package and all its dependencies will be
installed.</para></listitem>

View File

@@ -8,189 +8,7 @@
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.0"><title>Release 1.0 (May 11, 2012)</title>
<para>There have been numerous improvements and bug fixes since the
previous release. Here are the most significant:</para>
<itemizedlist>
<listitem>
<para>Nix can now optionally use the Boehm garbage collector.
This significantly reduces the Nix evaluators memory footprint,
especially when evaluating large NixOS system configurations. It
can be enabled using the <option>--enable-gc</option> configure
option.</para>
</listitem>
<listitem>
<para>Nix now uses SQLite for its database. This is faster and
more flexible than the old <emphasis>ad hoc</emphasis> format.
SQLite is also used to cache the manifests in
<filename>/nix/var/nix/manifests</filename>, resulting in a
significant speedup.</para>
</listitem>
<listitem>
<para>Nix now has an search path for expressions. The search path
is set using the environment variable <envar>NIX_PATH</envar> and
the <option>-I</option> command line option. In Nix expressions,
paths between angle brackets are used to specify files that must
be looked up in the search path. For instance, the expression
<literal>&lt;nixpkgs/default.nix></literal> looks for a file
<filename>nixpkgs/default.nix</filename> relative to every element
in the search path.</para>
</listitem>
<listitem>
<para>The new command <command>nix-build --run-env</command>
builds all dependencies of a derivation, then starts a shell in an
environment containing all variables from the derivation. This is
useful for reproducing the environment of a derivation for
development.</para>
</listitem>
<listitem>
<para>The new command <command>nix-store --verify-path</command>
verifies that the contents of a store path have not
changed.</para>
</listitem>
<listitem>
<para>The new command <command>nix-store --print-env</command>
prints out the environment of a derivation in a format that can be
evaluated by a shell.</para>
</listitem>
<listitem>
<para>Attribute names can now be arbitrary strings. For instance,
you can write <literal>{ "foo-1.2" = …; "bla bla" = …; }."bla
bla"</literal>.</para>
</listitem>
<listitem>
<para>Attribute selection can now provide a default value using
the <literal>or</literal> operator. For instance, the expression
<literal>x.y.z or e</literal> evaluates to the attribute
<literal>x.y.z</literal> if it exists, and <literal>e</literal>
otherwise.</para>
</listitem>
<listitem>
<para>The right-hand side of the <literal>?</literal> operator can
now be an attribute path, e.g., <literal>attrs ?
a.b.c</literal>.</para>
</listitem>
<listitem>
<para>On Linux, Nix will now make files in the Nix store immutable
on filesystems that support it. This prevents accidental
modification of files in the store by the root user.</para>
</listitem>
<listitem>
<para>Nix has preliminary support for derivations with multiple
outputs. This is useful because it allows parts of a package to
be deployed and garbage-collected separately. For instance,
development parts of a package such as header files or static
libraries would typically not be part of the closure of an
application, resulting in reduced disk usage and installation
time.</para>
</listitem>
<listitem>
<para>The Nix store garbage collector is faster and holds the
global lock for a shorter amount of time.</para>
</listitem>
<listitem>
<para>The option <option>--timeout</option> (corresponding to the
configuration setting <literal>build-timeout</literal>) allows you
to set an absolute timeout on builds — if a build runs for more than
the given number of seconds, it is terminated. This is useful for
recovering automatically from builds that are stuck in an infinite
loop but keep producing output, and for which
<literal>--max-silent-time</literal> is ineffective.</para>
</listitem>
<listitem>
<para>Nix development has moved to GitHub (<link
xlink:href="https://github.com/NixOS/nix" />).</para>
</listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-0.16"><title>Release 0.16 (August 17, 2010)</title>
<para>This release has the following improvements:</para>
<itemizedlist>
<listitem>
<para>The Nix expression evaluator is now much faster in most
cases: typically, <link
xlink:href="http://www.mail-archive.com/nix-dev@cs.uu.nl/msg04113.html">3
to 8 times compared to the old implementation</link>. It also
uses less memory. It no longer depends on the ATerm
library.</para>
</listitem>
<listitem>
<para>
Support for configurable parallelism inside builders. Build
scripts have always had the ability to perform multiple build
actions in parallel (for instance, by running <command>make -j
2</command>), but this was not desirable because the number of
actions to be performed in parallel was not configurable. Nix
now has an option <option>--cores
<replaceable>N</replaceable></option> as well as a configuration
setting <varname>build-cores =
<replaceable>N</replaceable></varname> that causes the
environment variable <envar>NIX_BUILD_CORES</envar> to be set to
<replaceable>N</replaceable> when the builder is invoked. The
builder can use this at its discretion to perform a parallel
build, e.g., by calling <command>make -j
<replaceable>N</replaceable></command>. In Nixpkgs, this can be
enabled on a per-package basis by setting the derivation
attribute <varname>enableParallelBuilding</varname> to
<literal>true</literal>.
</para>
</listitem>
<listitem>
<para><command>nix-store -q</command> now supports XML output
through the <option>--xml</option> flag.</para>
</listitem>
<listitem>
<para>Several bug fixes.</para>
</listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-0.15"><title>Release 0.15 (March 17, 2010)</title>
<para>This is a bug-fix release. Among other things, it fixes
building on Mac OS X (Snow Leopard), and improves the contents of
<filename>/etc/passwd</filename> and <filename>/etc/group</filename>
in <literal>chroot</literal> builds.</para>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-0.14"><title>Release 0.14 (February 4, 2010)</title>
<section xml:id="ssec-relnotes-0.14"><title>Release 0.14 (TBA)</title>
<para>This release has the following improvements:</para>
@@ -219,10 +37,6 @@ in <literal>chroot</literal> builds.</para>
not very useful in practice.</para>
</listitem>
<listitem>
<para>On Windows, Nix now requires Cygwin 1.7.x.</para>
</listitem>
<listitem>
<para>A few bug fixes.</para>
</listitem>

View File

@@ -8,14 +8,15 @@
body
{
font-family: "Nimbus Sans L", sans-serif;
font-family: sans-serif;
background: white;
margin: 2em 1em 2em 1em;
}
h1, h2, h3, h4
h1,h2,h3
{
color: #005aa0;
text-align: left;
}
h1 /* title */
@@ -74,13 +75,11 @@ div.refsection h3
div.example
{
border: 1px solid #b0b0b0;
border: 1px solid #6185a0;
padding: 6px 6px;
margin-left: 1.5em;
margin-right: 1.5em;
background: #f4f4f8;
border-radius: 0.4em;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
}
div.example p.title
@@ -88,11 +87,6 @@ div.example p.title
margin-top: 0em;
}
div.example pre
{
box-shadow: none;
}
/***************************************************************************
Screen dumps:
@@ -100,15 +94,14 @@ div.example pre
pre.screen, pre.programlisting
{
border: 1px solid #b0b0b0;
border: 1px solid #6185a0;
padding: 3px 3px;
margin-left: 1.5em;
margin-right: 1.5em;
color: #600000;
background: #f4f4f8;
font-family: monospace;
border-radius: 0.4em;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
/* font-size: 90%; */
}
div.example pre.programlisting
@@ -125,15 +118,13 @@ div.example pre.programlisting
.note, .warning
{
border: 1px solid #b0b0b0;
border: 1px solid #6185a0;
padding: 3px 3px;
margin-left: 1.5em;
margin-right: 1.5em;
margin-bottom: 1em;
padding: 0.3em 0.3em 0.3em 0.3em;
background: #fffff5;
border-radius: 0.4em;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
}
div.note, div.warning
@@ -145,6 +136,7 @@ div.note h3, div.warning h3
{
color: red;
font-size: 100%;
// margin: 0 0 0 0;
padding-right: 0.5em;
display: inline;
}
@@ -175,26 +167,20 @@ div.navfooter *
Links colors and highlighting:
***************************************************************************/
a { text-decoration: none; }
a:hover { text-decoration: underline; }
a:link { color: #0048b3; }
a:visited { color: #002a6a; }
a:hover { background: #ffffcd; }
/***************************************************************************
Table of contents:
***************************************************************************/
div.toc
.toc
{
font-size: 90%;
}
div.toc dl
{
margin-top: 0em;
margin-bottom: 0em;
}
/***************************************************************************
@@ -227,29 +213,76 @@ div.glosslist dt
font-style: italic;
}
.default
{
font-style: italic;
}
.availability
{
font-style: italic;
}
.varname
{
color: #400000;
}
span.command strong
div.informaltable table
{
font-weight: normal;
border: 1px solid #6185a0;
width: 100%;
}
div.informaltable td
{
border: 0;
padding: 5px;
}
div.informaltable td.default
{
text-align: right;
}
div.informaltable th
{
text-align: left;
color: #005aa0;
border: 0;
padding: 5px;
background: #fffff5;
font-weight: normal;
font-style: italic;
}
td.varname, td.tagname, td.paramname
{
font-weight: bold;
vertical-align: top;
}
div.epigraph
{
font-style: italic;
text-align: right;
}
table.productionset table.productionset
{
font-family: monospace;
}
strong.command
{
// font-family: monospace;
// font-style: italic;
// font-weight: normal;
color: #400000;
}
div.calloutlist table
div.calloutlist td
{
box-shadow: none;
padding-bottom: 1em;
}
table
{
border-collapse: collapse;
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
}
div.affiliation
{
font-style: italic;
}

View File

@@ -11,13 +11,6 @@ the things that tell Nix how to build packages. It starts with a
simple example (a Nix expression for GNU Hello), and then moves
on to a more in-depth look at the Nix expression language.</para>
<note><para>This chapter is mostly about the Nix expression language.
For more extensive information on adding packages to the Nix Packages
collection (such as functions in the standard environment and coding
conventions), please consult <link
xlink:href="http://hydra.nixos.org/job/nixpkgs/trunk/tarball/latest/download-by-type/doc/manual">its
manual</link>.</para></note>
<section><title>A simple Nix expression</title>
@@ -59,7 +52,7 @@ need to do three things:
<example xml:id='ex-hello-nix'><title>Nix expression for GNU Hello
(<filename>default.nix</filename>)</title>
<programlisting>
{ stdenv, fetchurl, perl }: <co xml:id='ex-hello-nix-co-1' />
{stdenv, fetchurl, perl}: <co xml:id='ex-hello-nix-co-1' />
stdenv.mkDerivation { <co xml:id='ex-hello-nix-co-2' />
name = "hello-2.1.1"; <co xml:id='ex-hello-nix-co-3' />
@@ -99,8 +92,8 @@ the single Nix expression in that directory
function that downloads files. <varname>perl</varname> is the
Perl interpreter.</para>
<para>Nix functions generally have the form <literal>{ x, y, ...,
z }: e</literal> where <varname>x</varname>, <varname>y</varname>,
<para>Nix functions generally have the form <literal>{x, y, ...,
z}: e</literal> where <varname>x</varname>, <varname>y</varname>,
etc. are the names of the expected arguments, and where
<replaceable>e</replaceable> is the body of the function. So
here, the entire remainder of the file is the body of the
@@ -121,10 +114,10 @@ the single Nix expression in that directory
<emphasis>attributes</emphasis>. An attribute set is just a list
of key/value pairs where each value is an arbitrary Nix
expression. They take the general form
<literal>{ <replaceable>name1</replaceable> =
<literal>{<replaceable>name1</replaceable> =
<replaceable>expr1</replaceable>; <replaceable>...</replaceable>
<replaceable>nameN</replaceable> =
<replaceable>exprN</replaceable>; }</literal>.</para>
<replaceable>exprN</replaceable>;}</literal>.</para>
</callout>
@@ -322,15 +315,15 @@ error check.</para>
rec { <co xml:id='ex-hello-composition-co-1' />
hello = import ../applications/misc/hello/ex-1 <co xml:id='ex-hello-composition-co-2' /> { <co xml:id='ex-hello-composition-co-3' />
hello = (import ../applications/misc/hello/ex-1 <co xml:id='ex-hello-composition-co-2' />) { <co xml:id='ex-hello-composition-co-3' />
inherit fetchurl stdenv perl;
};
perl = import ../development/interpreters/perl { <co xml:id='ex-hello-composition-co-4' />
perl = (import ../development/interpreters/perl) { <co xml:id='ex-hello-composition-co-4' />
inherit fetchurl stdenv;
};
fetchurl = import ../build-support/fetchurl {
fetchurl = (import ../build-support/fetchurl) {
inherit stdenv; ...
};
@@ -397,23 +390,6 @@ some fragments of
<varname>stdenv.mkDerivation</varname> in <xref
linkend='ex-hello-nix' />).</para>
<note><para>Nixpkgs has a convenience function
<function>callPackage</function> that imports and calls a
function, filling in any missing arguments by passing the
corresponding attribute from the Nixpkgs set, like this:
<programlisting>
hello = callPackage ../applications/misc/hello/ex-1 { };
</programlisting>
If necessary, you can set or override arguments:
<programlisting>
hello = callPackage ../applications/misc/hello/ex-1 { stdenv = myStdenv; };
</programlisting>
</para></note>
</callout>
<callout arearefs='ex-hello-composition-co-4'>
@@ -588,7 +564,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
expression, like this:
<programlisting>
buildInputs = [ perl ];</programlisting>
buildInputs = [perl];</programlisting>
The <varname>perl</varname> attribute can then be removed, and the
builder becomes even shorter:
@@ -795,14 +771,14 @@ stdenv.mkDerivation {
values between square brackets. For example,
<programlisting>
[ 123 ./foo.nix "abc" (f { x = y; }) ]</programlisting>
[ 123 ./foo.nix "abc" (f {x=y;}) ]</programlisting>
defines a list of four elements, the last being the result of a call
to the function <varname>f</varname>. Note that function calls have
to be enclosed in parentheses. If they had been omitted, e.g.,
<programlisting>
[ 123 ./foo.nix "abc" f { x = y; } ]</programlisting>
[ 123 ./foo.nix "abc" f {x=y;} ]</programlisting>
the result would be a list of five elements, the fourth one being a
function and the fifth being an attribute set.</para>
@@ -837,23 +813,7 @@ occur once.</para>
<programlisting>
{ a = "Foo"; b = "Bar"; }.a</programlisting>
evaluates to <literal>"Foo"</literal>. It is possible to provide a
default value in an attribute selection using the
<literal>or</literal> keyword. For example,
<programlisting>
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"</programlisting>
will evaluate to <literal>"Xyzzy"</literal> because there is no
<varname>c</varname> attribute in the set.</para>
<para>You can use arbitrary string constants as attribute names by
enclosing them in quotes:
<programlisting>
{ "foo bar" = 123; "nix-1.0" = 456; }."foo bar" </programlisting>
This will evaluate to <literal>123</literal>.</para>
evaluates to <literal>"Foo"</literal>.</para>
</simplesect>
@@ -931,12 +891,15 @@ propagate attributes). This can be shortened using the
<literal>inherit</literal> keyword. For instance,
<programlisting>
let x = 123; in
{ inherit x;
y = 456;
}</programlisting>
let
x = 123;
in
{
inherit x;
y = 456;
}</programlisting>
evaluates to <literal>{ x = 123; y = 456; }</literal>. (Note that this
evaluates to <literal>{x = 123; y = 456;}</literal>. (Note that this
works because <varname>x</varname> is added to the lexical scope by
the <literal>let</literal> construct.) It is also possible to inherit
attributes from another attribute set. For instance, in this fragment
@@ -997,20 +960,20 @@ in if negate true then concat "foo" "bar" else ""</programlisting>
arguments of a function); e.g.,
<programlisting>
map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
map (concat "foo") ["bar" "bla" "abc"]</programlisting>
evaluates to <literal>[ "foobar" "foobla"
"fooabc" ]</literal>.</para></listitem>
evaluates to <literal>["foobar" "foobla"
"fooabc"]</literal>.</para></listitem>
<listitem><para>An <emphasis>attribute set pattern</emphasis> of the
form <literal>{ name1, name2, …, nameN }</literal>
form <literal>{name1, name2, …, nameN}</literal>
matches an attribute set containing the listed attributes, and binds
the values of those attributes to variables in the function body.
For example, the function
<programlisting>
{ x, y, z }: z + y + x</programlisting>
{x, y, z}: z + y + x</programlisting>
can only be called with a set containing exactly the attributes
<varname>x</varname>, <varname>y</varname> and
@@ -1019,7 +982,7 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
(<literal>...</literal>):
<programlisting>
{ x, y, z, ... }: z + y + x</programlisting>
{x, y, z, ....}: z + y + x</programlisting>
This works on any set that contains at least the three named
attributes.</para>
@@ -1032,7 +995,7 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
<replaceable>e</replaceable> is an arbitrary expression. For example,
<programlisting>
{ x, y ? "foo", z ? "bar" }: z + y + x</programlisting>
{x, y ? "foo", z ? "bar"}: z + y + x</programlisting>
specifies a function that only requires an attribute named
<varname>x</varname>, but optionally accepts <varname>y</varname>
@@ -1044,11 +1007,11 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
of the <literal>@</literal>-sign. For example:
<programlisting>
args@{ x, y, z, ... }: z + y + x + args.a</programlisting>
args@{x, y, z, ...}: z + y + x + args.a</programlisting>
Here <varname>args</varname> is bound to the entire argument, which
is further matches against the pattern <literal>{ x, y, z,
... }</literal>.</para></listitem>
is further matches against the pattern <literal>{x, y, z,
...}</literal>.</para></listitem>
</itemizedlist>
@@ -1057,8 +1020,8 @@ args@{ x, y, z, ... }: z + y + x + args.a</programlisting>
a name, you can bind them to an attribute, e.g.,
<programlisting>
let concat = { x, y }: x + y;
in concat { x = "foo"; y = "bar"; }</programlisting>
let concat = {x, y}: x + y;
in concat {x = "foo"; y = "bar";}</programlisting>
</para>
@@ -1179,7 +1142,7 @@ lexical scope of the expression <replaceable>e2</replaceable>. For
instance,
<programlisting>
let as = { x = "foo"; y = "bar"; };
let as = {x = "foo"; y = "bar";};
in with as; x + y</programlisting>
evaluates to <literal>"foobar"</literal> since the
@@ -1229,17 +1192,12 @@ weakest binding).</para>
</thead>
<tbody>
<row>
<entry><replaceable>e</replaceable> <literal>.</literal>
<replaceable>attrpath</replaceable>
[ <literal>or</literal> <replaceable>def</replaceable> ]
</entry>
<entry><replaceable>e</replaceable> .
<replaceable>id</replaceable></entry>
<entry>none</entry>
<entry>Select attribute denoted by the attribute path
<replaceable>attrpath</replaceable> from attribute set
<replaceable>e</replaceable>. (An attribute path is a
dot-separated list of attribute names.) If the attribute
doesnt exist, return <replaceable>def</replaceable> if
provided, otherwise abort evaluation.</entry>
<entry>Select attribute named <replaceable>id</replaceable>
from attribute set <replaceable>e</replaceable>. Abort
evaluation if the attribute doesnt exist.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <replaceable>e2</replaceable></entry>
@@ -1248,31 +1206,31 @@ weakest binding).</para>
argument <replaceable>e2</replaceable>.</entry>
</row>
<row>
<entry><replaceable>e</replaceable> <literal>?</literal>
<replaceable>attrpath</replaceable></entry>
<entry><replaceable>e</replaceable> ?
<replaceable>id</replaceable></entry>
<entry>none</entry>
<entry>Test whether attribute set <replaceable>e</replaceable>
contains the attribute denoted by <replaceable>attrpath</replaceable>;
contains an attribute named <replaceable>id</replaceable>;
return <literal>true</literal> or
<literal>false</literal>.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>++</literal> <replaceable>e2</replaceable></entry>
<entry><replaceable>e1</replaceable> ++ <replaceable>e2</replaceable></entry>
<entry>right</entry>
<entry>List concatenation.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>+</literal> <replaceable>e2</replaceable></entry>
<entry><replaceable>e1</replaceable> + <replaceable>e2</replaceable></entry>
<entry>left</entry>
<entry>String or path concatenation.</entry>
</row>
<row>
<entry><literal>!</literal> <replaceable>e</replaceable></entry>
<entry>! <replaceable>e</replaceable></entry>
<entry>left</entry>
<entry>Boolean negation.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>//</literal>
<entry><replaceable>e1</replaceable> //
<replaceable>e2</replaceable></entry>
<entry>right</entry>
<entry>Return an attribute set consisting of the attributes in
@@ -1281,31 +1239,31 @@ weakest binding).</para>
precedence over the former in case of equally named attributes).</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>==</literal>
<entry><replaceable>e1</replaceable> ==
<replaceable>e2</replaceable></entry>
<entry>none</entry>
<entry>Equality.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>!=</literal>
<entry><replaceable>e1</replaceable> !=
<replaceable>e2</replaceable></entry>
<entry>none</entry>
<entry>Inequality.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>&amp;&amp;</literal>
<entry><replaceable>e1</replaceable> &amp;&amp;
<replaceable>e2</replaceable></entry>
<entry>left</entry>
<entry>Logical AND.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>||</literal>
<entry><replaceable>e1</replaceable> ||
<replaceable>e2</replaceable></entry>
<entry>left</entry>
<entry>Logical OR.</entry>
</row>
<row>
<entry><replaceable>e1</replaceable> <literal>-></literal>
<entry><replaceable>e1</replaceable> ->
<replaceable>e2</replaceable></entry>
<entry>none</entry>
<entry>Logical implication (equivalent to
@@ -1338,7 +1296,7 @@ set, the attributes of which specify the inputs of the build.</para>
can only be performed on a machine and operating system matching the
platform identifier. (Nix can automatically forward builds for
other platforms by forwarding them to other machines; see <xref
linkend='chap-distributed-builds' />.)</para></listitem>
linkend='sec-distributed-builds' />.)</para></listitem>
<listitem><para>There must be an attribute named
<varname>name</varname> whose value must be a string. This is used
@@ -1522,20 +1480,21 @@ allowedReferences = [];
references graph of their inputs. The attribute is a list of
inputs in the Nix store whose references graph the builder needs
to know. The value of this attribute should be a list of pairs
<literal>[ <replaceable>name1</replaceable>
<literal>[<replaceable>name1</replaceable>
<replaceable>path1</replaceable> <replaceable>name2</replaceable>
<replaceable>path2</replaceable> <replaceable>...</replaceable>
]</literal>. The references graph of each
<replaceable>pathN</replaceable> will be stored in a text file
<replaceable>nameN</replaceable> in the temporary build directory.
The text files have the format used by <command>nix-store
--register-validity</command> (with the deriver fields left
empty). For example, when the following derivation is built:
<replaceable>path2</replaceable>
<replaceable>...</replaceable>]</literal>. The references graph
of each <replaceable>pathN</replaceable> will be stored in a text
file <replaceable>nameN</replaceable> in the temporary build
directory. The text files have the format used by
<command>nix-store --register-validity</command> (with the deriver
fields left empty). For example, when the following derivation is
built:
<programlisting>
derivation {
...
exportReferencesGraph = [ "libfoo-graph" libfoo ];
exportReferencesGraph = ["libfoo-graph" libfoo];
};
</programlisting>
@@ -1612,14 +1571,14 @@ fetchurl {
<varname>fetchurl</varname>:
<programlisting>
{ stdenv, curl }: # The <command>curl</command> program is used for downloading.
{stdenv, curl}: # The <command>curl</command> program is used for downloading.
{ url, md5 }:
{url, md5}:
stdenv.mkDerivation {
name = baseNameOf (toString url);
builder = ./builder.sh;
buildInputs = [ curl ];
buildInputs = [curl];
# This is a fixed-output derivation; the output must be a regular
# file with MD5 hash <varname>md5</varname>.
@@ -1691,7 +1650,7 @@ stdenv.mkDerivation {
Nixpkgs has the line
<programlisting>
impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
impureEnvVars = ["http_proxy" "https_proxy" <replaceable>...</replaceable>];
</programlisting>
to make it use the proxy server configuration specified by the
@@ -1707,17 +1666,7 @@ impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
</varlistentry>
<varlistentry><term><varname>preferLocalBuild</varname></term>
<listitem><para>If this attribute is set to
<literal>true</literal> and <link
linkend="chap-distributed-builds">distributed building is
enabled</link>, then, if possible, perform this build locally
instead of forwarding it to a remote machine. This is appropriate
for trivial builders where the cost of doing a remote build would
exceed the cost of building locally.</para></listitem>
</varlistentry>
</variablelist>

73
externals/Makefile.am vendored Normal file
View File

@@ -0,0 +1,73 @@
# CWI ATerm
ATERM = aterm-2.4.2-fixes-r2
$(ATERM).tar.bz2:
@echo "Nix requires the CWI ATerm library to build."
@echo "Please download version 2.4.2-fixes-r2 from"
@echo " http://nixos.org/tarballs/aterm-2.4.2-fixes-r2.tar.bz2"
@echo "and place it in the externals/ directory."
false
$(ATERM): $(ATERM).tar.bz2
bunzip2 < $(srcdir)/$(ATERM).tar.bz2 | tar xvf -
have-aterm:
$(MAKE) $(ATERM)
touch have-aterm
if HAVE_ATERM
build-aterm:
else
build-aterm: have-aterm
(pfx=`pwd` && \
cd $(ATERM) && \
CC="$(CC)" ./configure --prefix=$$pfx/inst-aterm \
--disable-shared --enable-static && \
$(MAKE) && \
$(MAKE) install)
touch build-aterm
endif
# bzip2
BZIP2 = bzip2-1.0.5
$(BZIP2).tar.gz:
@echo "Nix requires bzip2 to build."
@echo "Please download version 1.0.5 from"
@echo " http://www.bzip.org/1.0.5/bzip2-1.0.5.tar.gz"
@echo "and place it in the externals/ directory."
false
$(BZIP2): $(BZIP2).tar.gz
gunzip < $(srcdir)/$(BZIP2).tar.gz | tar xvf -
have-bzip2:
$(MAKE) $(BZIP2)
touch have-bzip2
if HAVE_BZIP2
build-bzip2:
else
build-bzip2: have-bzip2
(pfx=`pwd` && \
cd $(BZIP2) && \
$(MAKE) && \
$(MAKE) install PREFIX=$$pfx/inst-bzip2)
touch build-bzip2
install:
mkdir -p $(DESTDIR)${bzip2_bin}
$(INSTALL_PROGRAM) $(bzip2_bin_test)/bzip2 $(bzip2_bin_test)/bunzip2 $(DESTDIR)${bzip2_bin}
endif
all: build-aterm build-bzip2
EXTRA_DIST = $(ATERM).tar.bz2 $(BZIP2).tar.gz
ext-clean:
$(RM) -f have-aterm build-aterm have-bzip2 build-bzip2
$(RM) -rf $(ATERM) $(BZIP2)

View File

@@ -0,0 +1,30 @@
{sharedLib ? true}:
rec {
inherit (import ../../../lib) compileC makeLibrary;
sources = [
./afun.c
./aterm.c
./bafio.c
./byteio.c
./gc.c
./hash.c
./list.c
./make.c
./md5c.c
./memory.c
./tafio.c
./version.c
];
compile = main: compileC {inherit main sharedLib;};
libATerm = makeLibrary {
libraryName = "ATerm";
objects = map compile sources;
inherit sharedLib;
};
}

View File

@@ -0,0 +1 @@
import test/default.nix

View File

@@ -0,0 +1,15 @@
with (import ../../../lib);
let {
inherit (import ../aterm {}) libATerm;
compileTest = main: link {
objects = [(compileC {inherit main; localIncludePath = [ ../aterm ];})];
libraries = libATerm;
};
body = [
(compileTest ./fib.c)
(compileTest ./primes.c)
];
}

View File

@@ -0,0 +1,6 @@
[ (import ./trivial)
(import ./simple-header)
(import ./not-so-simple-header)
(import ./not-so-simple-header-auto)
(import ./aterm)
]

View File

@@ -0,0 +1 @@
#define WHAT "World"

View File

@@ -0,0 +1,13 @@
with import ../../lib;
let {
hello = link {programName = "hello"; objects = compileC {
main = ./foo/hello.c;
localIncludes = "auto";
};};
# body = findIncludes {main = ./foo/hello.c;};
body = [hello];
}

View File

@@ -0,0 +1,3 @@
#define HELLO "Hello"
#include "../../bar/hello.h"

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include "fnord/indirect.h"
int main(int argc, char * * argv)
{
printf(HELLO " " WHAT "\n");
return 0;
}

View File

@@ -0,0 +1 @@
#define WHAT "World"

View File

@@ -0,0 +1,14 @@
let {
inherit (import ../../lib) compileC link;
hello = link {programName = "hello"; objects = compileC {
main = ./foo/hello.c;
localIncludes = [
[./foo/fnord/indirect.h "fnord/indirect.h"]
[./bar/hello.h "fnord/../../bar/hello.h"]
];
};};
body = [hello];
}

View File

@@ -0,0 +1,3 @@
#define HELLO "Hello"
#include "../../bar/hello.h"

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include "fnord/indirect.h"
int main(int argc, char * * argv)
{
printf(HELLO " " WHAT "\n");
return 0;
}

View File

@@ -0,0 +1,11 @@
let {
inherit (import ../../lib) compileC link;
hello = link {objects = compileC {
main = ./hello.c;
localIncludes = [ [./hello.h "hello.h"] ];
};};
body = [hello];
}

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include "hello.h"
int main(int argc, char * * argv)
{
printf("Hello " WHAT "\n");
return 0;
}

View File

@@ -0,0 +1 @@
#define WHAT "World"

View File

@@ -0,0 +1,8 @@
let {
inherit (import ../../lib) compileC link;
hello = link {objects = compileC {main = ./hello.c;};};
body = [hello];
}

View File

@@ -0,0 +1,7 @@
#include <stdio.h>
int main(int argc, char * * argv)
{
printf("Hello World\n");
return 0;
}

73
make/lib/compile-c.sh Normal file
View File

@@ -0,0 +1,73 @@
. $stdenv/setup
mainName=$(basename $main | cut -c34-)
echo "compiling \`$mainName'..."
# Turn $localIncludes into an array.
localIncludes=($localIncludes)
# Determine how many `..' levels appear in the header file references.
# E.g., if there is some reference `../../foo.h', then we have to
# insert two extra levels in the directory structure, so that `a.c' is
# stored at `dotdot/dotdot/a.c', and a reference from it to
# `../../foo.h' resolves to `dotdot/dotdot/../../foo.h' == `foo.h'.
n=0
maxDepth=0
for ((n = 0; n < ${#localIncludes[*]}; n += 2)); do
target=${localIncludes[$((n + 1))]}
# Split the target name into path components using some IFS magic.
savedIFS="$IFS"
IFS=/
components=($target)
depth=0
for ((m = 0; m < ${#components[*]}; m++)); do
c=${components[m]}
if test "$c" = ".."; then
depth=$((depth + 1))
fi
done
IFS="$savedIFS"
if test $depth -gt $maxDepth; then
maxDepth=$depth;
fi
done
# Create the extra levels in the directory hierarchy.
prefix=
for ((n = 0; n < maxDepth; n++)); do
prefix="dotdot/$prefix"
done
# Create symlinks to the header files.
for ((n = 0; n < ${#localIncludes[*]}; n += 2)); do
source=${localIncludes[n]}
target=${localIncludes[$((n + 1))]}
# Create missing directories. We use IFS magic to split the path
# into path components.
savedIFS="$IFS"
IFS=/
components=($prefix$target)
fullPath=(.)
for ((m = 0; m < ${#components[*]} - 1; m++)); do
fullPath=("${fullPath[@]}" ${components[m]})
if ! test -d "${fullPath[*]}"; then
mkdir "${fullPath[*]}"
fi
done
IFS="$savedIFS"
ln -sf $source $prefix$target
done
# Create a symlink to the main file.
if ! test "$(readlink $prefix$mainName)" = $main; then
ln -s $main $prefix$mainName
fi
mkdir $out
test "$prefix" && cd $prefix
gcc -Wall $cFlags -c $mainName -o $out/$mainName.o

69
make/lib/default.nix Normal file
View File

@@ -0,0 +1,69 @@
rec {
# Should point at your Nixpkgs installation.
pkgPath = ./pkgs;
pkgs = import (pkgPath + /system/all-packages.nix) {};
stdenv = pkgs.stdenv;
compileC =
{ main
, localIncludes ? "auto"
, localIncludePath ? []
, cFlags ? ""
, sharedLib ? false
}:
stdenv.mkDerivation {
name = "compile-c";
builder = ./compile-c.sh;
localIncludes =
if localIncludes == "auto" then
dependencyClosure {
scanner = main:
import (findIncludes {
inherit main;
});
searchPath = localIncludePath;
startSet = [main];
}
else
localIncludes;
inherit main;
cFlags = [
cFlags
(if sharedLib then ["-fpic"] else [])
(map (p: "-I" + (relativise (dirOf main) p)) localIncludePath)
];
};
findIncludes = {main}: stdenv.mkDerivation {
name = "find-includes";
realBuilder = pkgs.perl ~ "bin/perl";
args = [ ./find-includes.pl ];
inherit main;
};
link = {objects, programName ? "program", libraries ? []}: stdenv.mkDerivation {
name = "link";
builder = ./link.sh;
inherit objects programName libraries;
};
makeLibrary = {objects, libraryName ? [], sharedLib ? false}:
# assert sharedLib -> fold (obj: x: assert obj.sharedLib && x) false objects
stdenv.mkDerivation {
name = "library";
builder = ./make-library.sh;
inherit objects libraryName sharedLib;
};
}

21
make/lib/find-includes.pl Normal file
View File

@@ -0,0 +1,21 @@
use strict;
my $root = $ENV{"main"};
my $out = $ENV{"out"};
open OUT, ">$out" or die "$!";
print OUT "[\n";
open IN, "<$root" or die "$!";
while (<IN>) {
if (/^\#include\s+\"(.*)\"/) {
print OUT "\"$1\"\n";
}
if (/^\#include\s+\<(.*)\>/) {
print OUT "\"$1\"\n";
}
}
close IN;
print OUT "]\n";
close OUT;

21
make/lib/link.sh Normal file
View File

@@ -0,0 +1,21 @@
. $stdenv/setup
shopt -s nullglob
objs=
for i in $objects; do
obj=$(echo $i/*.o)
objs="$objs $obj"
done
libs=
for i in $libraries; do
lib=$(echo $i/*.a; echo $i/*.so)
name=$(echo $(basename $lib) | sed -e 's/^lib//' -e 's/.a$//' -e 's/.so$//')
libs="$libs -L$(dirname $lib) -l$name"
done
echo "linking object files into \`$programName'..."
mkdir $out
gcc -o $out/$programName $objs $libs

28
make/lib/make-library.sh Normal file
View File

@@ -0,0 +1,28 @@
. $stdenv/setup
objs=
for i in $objects; do
obj=$(echo $i/*.o)
objs="$objs $obj"
done
echo "archiving object files into library \`$libraryName'..."
ensureDir $out
if test -z "$sharedLib"; then
outPath=$out/lib${libraryName}.a
ar crs $outPath $objs
ranlib $outPath
else
outPath=$out/lib${libraryName}.so
gcc -shared -o $outPath $objs
fi

View File

@@ -67,7 +67,7 @@ The hook `nix-mode-hook' is run when Nix mode is started.
(defvar nix-keywords
'("\\<if\\>" "\\<then\\>" "\\<else\\>" "\\<assert\\>" "\\<with\\>"
"\\<let\\>" "\\<in\\>" "\\<rec\\>" "\\<inherit\\>" "\\<or\\>"
"\\<let\\>" "\\<in\\>" "\\<rec\\>" "\\<inherit\\>"
("\\<true\\>" . font-lock-builtin-face)
("\\<false\\>" . font-lock-builtin-face)
("\\<null\\>" . font-lock-builtin-face)
@@ -80,8 +80,6 @@ The hook `nix-mode-hook' is run when Nix mode is started.
. font-lock-constant-face)
("\\<\\([a-zA-Z_][a-zA-Z0-9_'\.]*\\)[ \t]*="
(1 font-lock-variable-name-face nil nil))
("<[a-zA-Z0-9._\\+-]+\\(/[a-zA-Z0-9._\\+-]+\\)*>"
. font-lock-constant-face)
("[a-zA-Z0-9._\\+-]*\\(/[a-zA-Z0-9._\\+-]+\\)+"
. font-lock-constant-face)
))
@@ -109,5 +107,3 @@ The hook `nix-mode-hook' is run when Nix mode is started.
(setq auto-mode-alist (cons '("\\.nix\\'" . nix-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.nix.in\\'" . nix-mode) auto-mode-alist))
(provide 'nix-mode)

View File

@@ -59,17 +59,6 @@
#build-max-jobs = 1
### Option `build-cores'
#
# This option defines the number of CPU cores to utilize in parallel
# within a build job, i.e. by passing an appropriate `-jN' flag to GNU
# Make. The default is 1, meaning that parallel building within jobs
# is disabled. Passing the special value `0' causes Nix to try and
# auto-detect the number of available cores on the local host. This
# setting can be overridden using the `--cores' command line switch.
#build-cores = 1
### Option `build-max-silent-time'
#
# This option defines the maximum number of seconds that a builder can

View File

@@ -19,16 +19,9 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
Prefix: /usr
Requires: /usr/bin/perl
Requires: curl
Requires: perl-DBD-SQLite
Requires: perl-devel
Requires: bzip2
Requires: bzip2-libs
Requires: sqlite
BuildRequires: bzip2-devel
BuildRequires: sqlite-devel
# Hack to make that shitty RPM scanning hack shut up.
Provides: perl(Nix::SSH)
Provides: perl(readmanifest)
%description

View File

@@ -1,7 +0,0 @@
Changes
Makefile.PL
MANIFEST
Nix.xs
README
t/Nix.t
lib/Nix.pm

View File

@@ -1,37 +0,0 @@
PERL_MODULES = lib/Nix/Store.pm lib/Nix/Manifest.pm lib/Nix/GeneratePatches.pm lib/Nix/SSH.pm lib/Nix/CopyClosure.pm lib/Nix/Config.pm.in
all: $(PERL_MODULES:.in=)
install-exec-local: $(PERL_MODULES:.in=) install-perl-xs
$(INSTALL) -d $(DESTDIR)$(perllibdir)/Nix
$(INSTALL_DATA) $(PERL_MODULES:.in=) $(DESTDIR)$(perllibdir)/Nix
if PERL_BINDINGS
install-perl-xs:
$(INSTALL) -d $(DESTDIR)$(perllibdir)/auto/Nix/Store
ln -sfn $(pkglibdir)/libNixStore$(dynlib_suffix) $(DESTDIR)$(perllibdir)/auto/Nix/Store/Store$(dynlib_suffix)
# Awful hackery to get libtool to build Perl XS bindings.
pkglib_LTLIBRARIES = libNixStore.la
nodist_libNixStore_la_SOURCES = lib/Nix/Store.cc
CLEANFILES = lib/Nix/Store.cc
libNixStore_la_LIBADD = $(top_builddir)/src/libstore/libstore.la
AM_CXXFLAGS = \
-I$(top_srcdir)/src -I$(top_srcdir)/src/libutil -I$(top_srcdir)/src/libstore \
-I$(shell $(perl) -e 'use Config; print $$Config{archlibexp};')/CORE \
-D_FILE_OFFSET_BITS=64
lib/Nix/Store.cc: lib/Nix/Store.xs
xsubpp $^ -output $@
else
install-perl-xs:
endif
EXTRA_DIST = $(PERL_MODULES) lib/Nix/Store.xs
include ../substitute.mk

View File

@@ -1,29 +0,0 @@
package Nix::Config;
$binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
$libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@libexecdir@";
$stateDir = $ENV{"NIX_STATE_DIR"} || "@localstatedir@/nix";
$manifestDir = $ENV{"NIX_MANIFESTS_DIR"} || "@localstatedir@/nix/manifests";
$logDir = $ENV{"NIX_LOG_DIR"} || "@localstatedir@/log/nix";
$confDir = $ENV{"NIX_CONF_DIR"} || "@sysconfdir@/nix";
$bzip2 = $ENV{"NIX_BZIP2"} || "@bzip2@";
$curl = "@curl@";
$useBindings = "@perlbindings@" eq "yes";
sub readConfig {
my %config;
my $config = "@sysconfdir@/nix/nix.conf";
return unless -f $config;
open CONFIG, "<$config" or die "cannot open `$config'";
while (<CONFIG>) {
/^\s*([\w|-]+)\s*=\s*(.*)$/ or next;
$config{$1} = $2;
print "|$1| -> |$2|\n";
}
close CONFIG;
}
return 1;

View File

@@ -1,46 +0,0 @@
package Nix::CopyClosure;
use strict;
use Nix::Config;
use Nix::Store;
sub copyTo {
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor, $includeOutputs, $dryRun, $sign, $progressViewer) = @_;
$compressor = "$compressor |" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
$progressViewer = "$progressViewer |" if $progressViewer ne "";
# Get the closure of this path.
my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,
map { followLinksToStorePath $_ } @{$storePaths})));
# Ask the remote host which paths are invalid. Because of limits
# to the command line length, do this in chunks. Eventually,
# we'll want to use --from-stdin, but we can't rely on the
# target having this option yet.
my @missing = ();
while (scalar(@closure) > 0) {
my @ps = splice(@closure, 0, 1500);
open(READ, "set -f; ssh $sshHost @{$sshOpts} nix-store --check-validity --print-invalid @ps|");
while (<READ>) {
chomp;
push @missing, $_;
}
close READ or die;
}
# Export the store paths and import them on the remote machine.
if (scalar @missing > 0) {
print STDERR "copying ", scalar @missing, " missing paths to $sshHost...\n";
unless ($dryRun) {
open SSH, "| $compressor $progressViewer ssh $sshHost @{$sshOpts} '$decompressor nix-store --import' > /dev/null" or die;
exportPaths(fileno(SSH), $sign, @missing);
close SSH or die "copying store paths to remote machine `$sshHost' failed: $?";
}
}
}
1;

View File

@@ -1,340 +0,0 @@
package Nix::GeneratePatches;
use strict;
use File::Temp qw(tempdir);
use File::stat;
use Nix::Config;
use Nix::Manifest;
our @ISA = qw(Exporter);
our @EXPORT = qw(generatePatches propagatePatches copyPatches);
# Some patch generations options.
# Max size of NAR archives to generate patches for.
my $maxNarSize = $ENV{"NIX_MAX_NAR_SIZE"};
$maxNarSize = 160 * 1024 * 1024 if !defined $maxNarSize;
# If patch is bigger than this fraction of full archive, reject.
my $maxPatchFraction = $ENV{"NIX_PATCH_FRACTION"};
$maxPatchFraction = 0.60 if !defined $maxPatchFraction;
my $timeLimit = $ENV{"NIX_BSDIFF_TIME_LIMIT"};
$timeLimit = 180 if !defined $timeLimit;
my $hashAlgo = "sha256";
sub findOutputPaths {
my $narFiles = shift;
my %outPaths;
foreach my $p (keys %{$narFiles}) {
# Ignore derivations.
next if ($p =~ /\.drv$/);
# Ignore builders (too much ambiguity -- they're all called
# `builder.sh').
next if ($p =~ /\.sh$/);
next if ($p =~ /\.patch$/);
# Don't bother including tar files etc.
next if ($p =~ /\.tar$/ || $p =~ /\.tar\.(gz|bz2|Z|lzma|xz)$/ || $p =~ /\.zip$/ || $p =~ /\.bin$/ || $p =~ /\.tgz$/ || $p =~ /\.rpm$/ || $p =~ /cvs-export$/ || $p =~ /fetchhg$/);
$outPaths{$p} = 1;
}
return %outPaths;
}
sub getNameVersion {
my $p = shift;
$p =~ /\/[0-9a-z]+((?:-[a-zA-Z][^\/-]*)+)([^\/]*)$/;
my $name = $1;
my $version = $2;
return undef unless defined $name && defined $version;
$name =~ s/^-//;
$version =~ s/^-//;
return ($name, $version);
}
# A quick hack to get a measure of the `distance' between two
# versions: it's just the position of the first character that differs
# (or 999 if they are the same).
sub versionDiff {
my $s = shift;
my $t = shift;
my $i;
return 999 if $s eq $t;
for ($i = 0; $i < length $s; $i++) {
return $i if $i >= length $t or
substr($s, $i, 1) ne substr($t, $i, 1);
}
return $i;
}
sub getNarBz2 {
my $narPath = shift;
my $narFiles = shift;
my $storePath = shift;
my $narFileList = $$narFiles{$storePath};
die "missing path $storePath" unless defined $narFileList;
my $narFile = @{$narFileList}[0];
die unless defined $narFile;
$narFile->{url} =~ /\/([^\/]+)$/;
die unless defined $1;
return "$narPath/$1";
}
sub containsPatch {
my $patches = shift;
my $storePath = shift;
my $basePath = shift;
my $patchList = $$patches{$storePath};
return 0 if !defined $patchList;
my $found = 0;
foreach my $patch (@{$patchList}) {
# !!! baseHash might differ
return 1 if $patch->{basePath} eq $basePath;
}
return 0;
}
sub generatePatches {
my ($srcNarFiles, $dstNarFiles, $srcPatches, $dstPatches, $narPath, $patchesPath, $patchesURL, $tmpDir) = @_;
my %srcOutPaths = findOutputPaths $srcNarFiles;
my %dstOutPaths = findOutputPaths $dstNarFiles;
# For each output path in the destination, see if we need to / can
# create a patch.
print STDERR "creating patches...\n";
foreach my $p (keys %dstOutPaths) {
# If exactly the same path already exists in the source, skip it.
next if defined $srcOutPaths{$p};
print " $p\n";
# If not, then we should find the paths in the source that are
# `most' likely to be present on a system that wants to
# install this path.
(my $name, my $version) = getNameVersion $p;
next unless defined $name && defined $version;
my @closest = ();
my $closestVersion;
my $minDist = -1; # actually, larger means closer
# Find all source paths with the same name.
foreach my $q (keys %srcOutPaths) {
(my $name2, my $version2) = getNameVersion $q;
next unless defined $name2 && defined $version2;
if ($name eq $name2) {
my $srcSystem = @{$$dstNarFiles{$p}}[0]->{system};
my $dstSystem = @{$$srcNarFiles{$q}}[0]->{system};
if (defined $srcSystem && defined $dstSystem && $srcSystem ne $dstSystem) {
print " SKIPPING $q due to different systems ($srcSystem vs. $dstSystem)\n";
next;
}
# If the sizes differ too much, then skip. This
# disambiguates between, e.g., a real component and a
# wrapper component (cf. Firefox in Nixpkgs).
my $srcSize = @{$$srcNarFiles{$q}}[0]->{size};
my $dstSize = @{$$dstNarFiles{$p}}[0]->{size};
my $ratio = $srcSize / $dstSize;
$ratio = 1 / $ratio if $ratio < 1;
# print " SIZE $srcSize $dstSize $ratio $q\n";
if ($ratio >= 3) {
print " SKIPPING $q due to size ratio $ratio ($srcSize vs. $dstSize)\n";
next;
}
# If there are multiple matching names, include the
# ones with the closest version numbers.
my $dist = versionDiff $version, $version2;
if ($dist > $minDist) {
$minDist = $dist;
@closest = ($q);
$closestVersion = $version2;
} elsif ($dist == $minDist) {
push @closest, $q;
}
}
}
if (scalar(@closest) == 0) {
print " NO BASE: $p\n";
next;
}
foreach my $closest (@closest) {
# Generate a patch between $closest and $p.
print STDERR " $p <- $closest\n";
# If the patch already exists, skip it.
if (containsPatch($srcPatches, $p, $closest) ||
containsPatch($dstPatches, $p, $closest))
{
print " skipping, already exists\n";
next;
}
my $srcNarBz2 = getNarBz2 $narPath, $srcNarFiles, $closest;
my $dstNarBz2 = getNarBz2 $narPath, $dstNarFiles, $p;
if (! -f $srcNarBz2) {
warn "patch source archive $srcNarBz2 is missing\n";
next;
}
system("$Nix::Config::bzip2 -d < $srcNarBz2 > $tmpDir/A") == 0
or die "cannot unpack $srcNarBz2";
if (stat("$tmpDir/A")->size >= $maxNarSize) {
print " skipping, source is too large\n";
next;
}
system("$Nix::Config::bzip2 -d < $dstNarBz2 > $tmpDir/B") == 0
or die "cannot unpack $dstNarBz2";
if (stat("$tmpDir/B")->size >= $maxNarSize) {
print " skipping, destination is too large\n";
next;
}
my $time1 = time();
my $res = system("ulimit -t $timeLimit; $Nix::Config::libexecDir/bsdiff $tmpDir/A $tmpDir/B $tmpDir/DIFF");
my $time2 = time();
if ($res) {
warn "binary diff computation aborted after ", $time2 - $time1, " seconds\n";
next;
}
my $baseHash = `$Nix::Config::binDir/nix-hash --flat --type $hashAlgo --base32 $tmpDir/A` or die;
chomp $baseHash;
my $narHash = `$Nix::Config::binDir/nix-hash --flat --type $hashAlgo --base32 $tmpDir/B` or die;
chomp $narHash;
my $narDiffHash = `$Nix::Config::binDir/nix-hash --flat --type $hashAlgo --base32 $tmpDir/DIFF` or die;
chomp $narDiffHash;
my $narDiffSize = stat("$tmpDir/DIFF")->size;
my $dstNarBz2Size = stat($dstNarBz2)->size;
print " size $narDiffSize; full size $dstNarBz2Size; ", $time2 - $time1, " seconds\n";
if ($narDiffSize >= $dstNarBz2Size) {
print " rejecting; patch bigger than full archive\n";
next;
}
if ($narDiffSize / $dstNarBz2Size >= $maxPatchFraction) {
print " rejecting; patch too large relative to full archive\n";
next;
}
my $finalName = "$narDiffHash.nar-bsdiff";
if (-e "$patchesPath/$finalName") {
print " not copying, already exists\n";
}
else {
system("cp '$tmpDir/DIFF' '$patchesPath/$finalName.tmp'") == 0
or die "cannot copy diff";
rename("$patchesPath/$finalName.tmp", "$patchesPath/$finalName")
or die "cannot rename $patchesPath/$finalName.tmp";
}
# Add the patch to the manifest.
addPatch $dstPatches, $p,
{ url => "$patchesURL/$finalName", hash => "$hashAlgo:$narDiffHash"
, size => $narDiffSize, basePath => $closest, baseHash => "$hashAlgo:$baseHash"
, narHash => "$hashAlgo:$narHash", patchType => "nar-bsdiff"
};
}
}
}
# Propagate useful patches from $srcPatches to $dstPatches. A patch
# is useful if it produces either paths in the $dstNarFiles or paths
# that can be used as the base for other useful patches.
sub propagatePatches {
my ($srcPatches, $dstNarFiles, $dstPatches) = @_;
print STDERR "propagating patches...\n";
my $changed;
do {
# !!! we repeat this to reach the transitive closure; inefficient
$changed = 0;
print STDERR "loop\n";
my %dstBasePaths;
foreach my $q (keys %{$dstPatches}) {
foreach my $patch (@{$$dstPatches{$q}}) {
$dstBasePaths{$patch->{basePath}} = 1;
}
}
foreach my $p (keys %{$srcPatches}) {
my $patchList = $$srcPatches{$p};
my $include = 0;
# Is path $p included in the destination? If so, include
# patches that produce it.
$include = 1 if defined $$dstNarFiles{$p};
# Is path $p a path that serves as a base for paths in the
# destination? If so, include patches that produce it.
# !!! check baseHash
$include = 1 if defined $dstBasePaths{$p};
if ($include) {
foreach my $patch (@{$patchList}) {
$changed = 1 if addPatch $dstPatches, $p, $patch;
}
}
}
} while $changed;
}
# Add all new patches in $srcPatches to $dstPatches.
sub copyPatches {
my ($srcPatches, $dstPatches) = @_;
foreach my $p (keys %{$srcPatches}) {
addPatch $dstPatches, $p, $_ foreach @{$$srcPatches{$p}};
}
}
return 1;

View File

@@ -1,367 +0,0 @@
package Nix::Manifest;
use strict;
use DBI;
use Cwd;
use File::stat;
use File::Path;
use Fcntl ':flock';
use Nix::Config;
our @ISA = qw(Exporter);
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch);
sub addNAR {
my ($narFiles, $storePath, $info) = @_;
$$narFiles{$storePath} = []
unless defined $$narFiles{$storePath};
my $narFileList = $$narFiles{$storePath};
my $found = 0;
foreach my $narFile (@{$narFileList}) {
$found = 1 if $narFile->{url} eq $info->{url};
}
push @{$narFileList}, $info if !$found;
}
sub addPatch {
my ($patches, $storePath, $patch) = @_;
$$patches{$storePath} = []
unless defined $$patches{$storePath};
my $patchList = $$patches{$storePath};
my $found = 0;
foreach my $patch2 (@{$patchList}) {
$found = 1 if
$patch2->{url} eq $patch->{url} &&
$patch2->{basePath} eq $patch->{basePath};
}
push @{$patchList}, $patch if !$found;
return !$found;
}
sub readManifest_ {
my ($manifest, $addNAR, $addPatch) = @_;
# Decompress the manifest if necessary.
if ($manifest =~ /\.bz2$/) {
open MANIFEST, "$Nix::Config::bzip2 -d < $manifest |"
or die "cannot decompress `$manifest': $!";
} else {
open MANIFEST, "<$manifest"
or die "cannot open `$manifest': $!";
}
my $inside = 0;
my $type;
my $manifestVersion = 2;
my ($storePath, $url, $hash, $size, $basePath, $baseHash, $patchType);
my ($narHash, $narSize, $references, $deriver, $copyFrom, $system);
while (<MANIFEST>) {
chomp;
s/\#.*$//g;
next if (/^$/);
if (!$inside) {
if (/^\s*(\w*)\s*\{$/) {
$type = $1;
$type = "narfile" if $type eq "";
$inside = 1;
undef $storePath;
undef $url;
undef $hash;
undef $size;
undef $narHash;
undef $narSize;
undef $basePath;
undef $baseHash;
undef $patchType;
undef $system;
$references = "";
$deriver = "";
}
} else {
if (/^\}$/) {
$inside = 0;
if ($type eq "narfile") {
&$addNAR($storePath,
{ url => $url, hash => $hash, size => $size
, narHash => $narHash, narSize => $narSize
, references => $references
, deriver => $deriver
, system => $system
});
}
elsif ($type eq "patch") {
&$addPatch($storePath,
{ url => $url, hash => $hash, size => $size
, basePath => $basePath, baseHash => $baseHash
, narHash => $narHash, narSize => $narSize
, patchType => $patchType
});
}
}
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }
elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }
elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }
elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
elsif (/^\s*Type:\s*(\S+)\s*$/) { $patchType = $1; }
elsif (/^\s*NarHash:\s*(\S+)\s*$/) { $narHash = $1; }
elsif (/^\s*NarSize:\s*(\d+)\s*$/) { $narSize = $1; }
elsif (/^\s*References:\s*(.*)\s*$/) { $references = $1; }
elsif (/^\s*Deriver:\s*(\S+)\s*$/) { $deriver = $1; }
elsif (/^\s*ManifestVersion:\s*(\d+)\s*$/) { $manifestVersion = $1; }
elsif (/^\s*System:\s*(\S+)\s*$/) { $system = $1; }
# Compatibility;
elsif (/^\s*NarURL:\s*(\S+)\s*$/) { $url = $1; }
elsif (/^\s*MD5:\s*(\S+)\s*$/) { $hash = "md5:$1"; }
}
}
close MANIFEST;
return $manifestVersion;
}
sub readManifest {
my ($manifest, $narFiles, $patches) = @_;
readManifest_($manifest,
sub { addNAR($narFiles, @_); },
sub { addPatch($patches, @_); } );
}
sub writeManifest {
my ($manifest, $narFiles, $patches, $noCompress) = @_;
open MANIFEST, ">$manifest.tmp"; # !!! check exclusive
print MANIFEST "version {\n";
print MANIFEST " ManifestVersion: 3\n";
print MANIFEST "}\n";
foreach my $storePath (sort (keys %{$narFiles})) {
my $narFileList = $$narFiles{$storePath};
foreach my $narFile (@{$narFileList}) {
print MANIFEST "{\n";
print MANIFEST " StorePath: $storePath\n";
print MANIFEST " NarURL: $narFile->{url}\n";
print MANIFEST " Hash: $narFile->{hash}\n" if defined $narFile->{hash};
print MANIFEST " Size: $narFile->{size}\n" if defined $narFile->{size};
print MANIFEST " NarHash: $narFile->{narHash}\n";
print MANIFEST " NarSize: $narFile->{narSize}\n" if $narFile->{narSize};
print MANIFEST " References: $narFile->{references}\n"
if defined $narFile->{references} && $narFile->{references} ne "";
print MANIFEST " Deriver: $narFile->{deriver}\n"
if defined $narFile->{deriver} && $narFile->{deriver} ne "";
print MANIFEST " System: $narFile->{system}\n" if defined $narFile->{system};
print MANIFEST "}\n";
}
}
foreach my $storePath (sort (keys %{$patches})) {
my $patchList = $$patches{$storePath};
foreach my $patch (@{$patchList}) {
print MANIFEST "patch {\n";
print MANIFEST " StorePath: $storePath\n";
print MANIFEST " NarURL: $patch->{url}\n";
print MANIFEST " Hash: $patch->{hash}\n";
print MANIFEST " Size: $patch->{size}\n";
print MANIFEST " NarHash: $patch->{narHash}\n";
print MANIFEST " NarSize: $patch->{narSize}\n" if $patch->{narSize};
print MANIFEST " BasePath: $patch->{basePath}\n";
print MANIFEST " BaseHash: $patch->{baseHash}\n";
print MANIFEST " Type: $patch->{patchType}\n";
print MANIFEST "}\n";
}
}
close MANIFEST;
rename("$manifest.tmp", $manifest)
or die "cannot rename $manifest.tmp: $!";
# Create a bzipped manifest.
unless (defined $noCompress) {
system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0
or die "cannot compress manifest";
rename("$manifest.bz2.tmp", "$manifest.bz2")
or die "cannot rename $manifest.bz2.tmp: $!";
}
}
sub updateManifestDB {
my $manifestDir = $Nix::Config::manifestDir;
mkpath($manifestDir);
my $dbPath = "$manifestDir/cache.sqlite";
# Open/create the database.
our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
or die "cannot open database `$dbPath'";
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
$dbh->do("pragma foreign_keys = on");
$dbh->do("pragma synchronous = off"); # we can always reproduce the cache
$dbh->do("pragma journal_mode = truncate");
# Initialise the database schema, if necessary.
$dbh->do(<<EOF);
create table if not exists Manifests (
id integer primary key autoincrement not null,
path text unique not null,
timestamp integer not null
);
EOF
$dbh->do(<<EOF);
create table if not exists NARs (
id integer primary key autoincrement not null,
manifest integer not null,
storePath text not null,
url text not null,
hash text,
size integer,
narHash text,
narSize integer,
refs text,
deriver text,
system text,
foreign key (manifest) references Manifests(id) on delete cascade
);
EOF
$dbh->do("create index if not exists NARs_storePath on NARs(storePath)");
$dbh->do(<<EOF);
create table if not exists Patches (
id integer primary key autoincrement not null,
manifest integer not null,
storePath text not null,
basePath text not null,
baseHash text not null,
url text not null,
hash text,
size integer,
narHash text,
narSize integer,
patchType text not null,
foreign key (manifest) references Manifests(id) on delete cascade
);
EOF
$dbh->do("create index if not exists Patches_storePath on Patches(storePath)");
# Acquire an exclusive lock to ensure that only one process
# updates the DB at the same time. This isn't really necessary,
# but it prevents work duplication and lock contention in SQLite.
my $lockFile = "$manifestDir/cache.lock";
open MAINLOCK, ">>$lockFile" or die "unable to acquire lock $lockFile: $!\n";
flock(MAINLOCK, LOCK_EX) or die;
our $insertNAR = $dbh->prepare(
"insert into NARs(manifest, storePath, url, hash, size, narHash, " .
"narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
our $insertPatch = $dbh->prepare(
"insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " .
"size, narHash, narSize, patchType) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$dbh->begin_work;
# Read each manifest in $manifestDir and add it to the database,
# unless we've already done so on a previous run.
my %seen;
for my $manifestLink (glob "$manifestDir/*.nixmanifest") {
my $manifest = Cwd::abs_path($manifestLink);
next unless -f $manifest;
my $timestamp = lstat($manifest)->mtime;
$seen{$manifest} = 1;
next if scalar @{$dbh->selectcol_arrayref(
"select 1 from Manifests where path = ? and timestamp = ?",
{}, $manifest, $timestamp)} == 1;
print STDERR "caching $manifest...\n";
$dbh->do("delete from Manifests where path = ?", {}, $manifest);
$dbh->do("insert into Manifests(path, timestamp) values (?, ?)",
{}, $manifest, $timestamp);
our $id = $dbh->last_insert_id("", "", "", "");
sub addNARToDB {
my ($storePath, $narFile) = @_;
$insertNAR->execute(
$id, $storePath, $narFile->{url}, $narFile->{hash}, $narFile->{size},
$narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
$narFile->{deriver}, $narFile->{system});
};
sub addPatchToDB {
my ($storePath, $patch) = @_;
$insertPatch->execute(
$id, $storePath, $patch->{basePath}, $patch->{baseHash}, $patch->{url},
$patch->{hash}, $patch->{size}, $patch->{narHash}, $patch->{narSize},
$patch->{patchType});
};
my $version = readManifest_($manifest, \&addNARToDB, \&addPatchToDB);
if ($version < 3) {
die "you have an old-style or corrupt manifest `$manifestLink'; please delete it\n";
}
if ($version >= 10) {
die "manifest `$manifestLink' is too new; please delete it or upgrade Nix\n";
}
}
# Removed cached information for removed manifests from the DB.
foreach my $manifest (@{$dbh->selectcol_arrayref("select path from Manifests")}) {
next if defined $seen{$manifest};
$dbh->do("delete from Manifests where path = ?", {}, $manifest);
}
$dbh->commit;
close MAINLOCK;
return $dbh;
}
return 1;

View File

@@ -1,52 +0,0 @@
use strict;
use File::Temp qw(tempdir);
our @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");
push @sshOpts, "-x";
my $sshStarted = 0;
my $sshHost;
# Open a master SSH connection to `host', unless there already is a
# running master connection (as determined by `-O check').
sub openSSHConnection {
my ($host) = @_;
die if $sshStarted;
$sshHost = $host;
return 1 if system("ssh $sshHost @sshOpts -O check 2> /dev/null") == 0;
my $tmpDir = tempdir("nix-ssh.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
push @sshOpts, "-S", "$tmpDir/control";
# Start the master. We can't use the `-f' flag (fork into
# background after establishing the connection) because then the
# child continues to run if we are killed. So instead make SSH
# print "started" when it has established the connection, and wait
# until we see that.
open SSHPIPE, "ssh $sshHost @sshOpts -M -N -o LocalCommand='echo started' -o PermitLocalCommand=yes |" or die;
while (<SSHPIPE>) {
chomp;
if ($_ eq "started") {
$sshStarted = 1;
return 1;
}
}
return 0;
}
# Tell the master SSH client to exit.
sub closeSSHConnection {
if ($sshStarted) {
system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0
or warn "unable to stop SSH master: $?";
}
}
END { my $saved = $?; closeSSHConnection; $? = $saved; }
return 1;

View File

@@ -1,91 +0,0 @@
package Nix::Store;
use strict;
use warnings;
use Nix::Config;
require Exporter;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
isValidPath queryReferences queryPathInfo queryDeriver queryPathHash
topoSortPaths computeFSClosure followLinksToStorePath exportPaths
hashPath hashFile hashString
addToStore makeFixedOutputPath
derivationFromPath
);
our $VERSION = '0.15';
sub backtick {
open(RES, "-|", @_) or die;
local $/;
my $res = <RES> || "";
close RES or die;
return $res;
}
if ($Nix::Config::useBindings) {
require XSLoader;
XSLoader::load('Nix::Store', $VERSION);
} else {
# Provide slow fallbacks of some functions on platforms that don't
# support the Perl bindings.
use File::Temp;
use Fcntl qw/F_SETFD/;
sub hashFile {
my ($algo, $base32, $path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
}
sub hashPath {
my ($algo, $base32, $path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
}
sub hashString {
my ($algo, $base32, $s) = @_;
my $fh = File::Temp->new();
print $fh $s;
my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
}
sub addToStore {
my ($srcPath, $recursive, $algo) = @_;
die "not implemented" if $recursive || $algo ne "sha256";
my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);
chomp $res;
return $res;
}
sub isValidPath {
my ($path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);
chomp $res;
return $res ne $path;
}
sub queryPathHash {
my ($path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);
chomp $res;
return $res;
}
}
1;
__END__

View File

@@ -1,260 +0,0 @@
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
/* Prevent a clash between some Perl and libstdc++ macros. */
#undef do_open
#undef do_close
#include <store-api.hh>
#include <globals.hh>
#include <misc.hh>
#include <util.hh>
using namespace nix;
void doInit()
{
if (!store) {
try {
setDefaultsFromEnvironment();
store = openStore();
} catch (Error & e) {
croak(e.what());
}
}
}
MODULE = Nix::Store PACKAGE = Nix::Store
PROTOTYPES: ENABLE
void init()
CODE:
doInit();
int isValidPath(char * path)
CODE:
try {
doInit();
RETVAL = store->isValidPath(path);
} catch (Error & e) {
croak(e.what());
}
OUTPUT:
RETVAL
SV * queryReferences(char * path)
PPCODE:
try {
doInit();
PathSet paths;
store->queryReferences(path, paths);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * queryPathHash(char * path)
PPCODE:
try {
doInit();
Hash hash = store->queryPathHash(path);
string s = "sha256:" + printHash32(hash);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * queryDeriver(char * path)
PPCODE:
try {
doInit();
Path deriver = store->queryDeriver(path);
if (deriver == "") XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * queryPathInfo(char * path)
PPCODE:
try {
doInit();
ValidPathInfo info = store->queryPathInfo(path);
if (info.deriver == "")
XPUSHs(&PL_sv_undef);
else
XPUSHs(sv_2mortal(newSVpv(info.deriver.c_str(), 0)));
string s = "sha256:" + printHash(info.hash);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
mXPUSHi(info.registrationTime);
mXPUSHi(info.narSize);
AV * arr = newAV();
for (PathSet::iterator i = info.references.begin(); i != info.references.end(); ++i)
av_push(arr, newSVpv(i->c_str(), 0));
XPUSHs(sv_2mortal(newRV((SV *) arr)));
} catch (Error & e) {
croak(e.what());
}
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
PPCODE:
try {
doInit();
PathSet paths;
for (int n = 2; n < items; ++n)
computeFSClosure(*store, SvPV_nolen(ST(n)), paths, flipDirection, includeOutputs);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * topoSortPaths(...)
PPCODE:
try {
doInit();
PathSet paths;
for (int n = 0; n < items; ++n) paths.insert(SvPV_nolen(ST(n)));
Paths sorted = topoSortPaths(*store, paths);
for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * followLinksToStorePath(char * path)
CODE:
try {
doInit();
RETVAL = newSVpv(followLinksToStorePath(path).c_str(), 0);
} catch (Error & e) {
croak(e.what());
}
OUTPUT:
RETVAL
void exportPaths(int fd, int sign, ...)
PPCODE:
try {
doInit();
Paths paths;
for (int n = 2; n < items; ++n) paths.push_back(SvPV_nolen(ST(n)));
FdSink sink(fd);
exportPaths(*store, paths, sign, sink);
} catch (Error & e) {
croak(e.what());
}
SV * hashPath(char * algo, int base32, char * path)
PPCODE:
try {
Hash h = hashPath(parseHashType(algo), path).first;
string s = base32 ? printHash32(h) : printHash(h);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * hashFile(char * algo, int base32, char * path)
PPCODE:
try {
Hash h = hashFile(parseHashType(algo), path);
string s = base32 ? printHash32(h) : printHash(h);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * hashString(char * algo, int base32, char * s)
PPCODE:
try {
Hash h = hashString(parseHashType(algo), s);
string s = base32 ? printHash32(h) : printHash(h);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * addToStore(char * srcPath, int recursive, char * algo)
PPCODE:
try {
doInit();
Path path = store->addToStore(srcPath, recursive, parseHashType(algo));
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
PPCODE:
try {
doInit();
HashType ht = parseHashType(algo);
Path path = makeFixedOutputPath(recursive, ht,
parseHash16or32(ht, hash), name);
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
} catch (Error & e) {
croak(e.what());
}
SV * derivationFromPath(char * drvPath)
PREINIT:
HV *hash;
CODE:
try {
doInit();
Derivation drv = derivationFromPath(*store, drvPath);
hash = newHV();
/* TODO: handle drv.outputs */
AV * inputDrvs = newAV();
for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
av_push(inputDrvs, newSVpv(i->first.c_str(), 0)); // !!! ignores i->second
hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));
AV * inputSrcs = newAV();
for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i)
av_push(inputSrcs, newSVpv(i->c_str(), 0));
hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));
hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));
hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));
AV * args = newAV();
for (Strings::iterator i = drv.args.begin(); i != drv.args.end(); ++i)
av_push(args, newSVpv(i->c_str(), 0));
hv_stores(hash, "args", newRV((SV *) args));
HV * env = newHV();
for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i)
hv_store(env, i->first.c_str(), i->first.size(), newSVpv(i->second.c_str(), 0), 0);
hv_stores(hash, "env", newRV((SV *) env));
RETVAL = newRV_noinc((SV *)hash);
} catch (Error & e) {
croak(e.what());
}
OUTPUT:
RETVAL

View File

@@ -1,7 +1,4 @@
{ nixpkgs ? <nixpkgs>
, nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
, officialRelease ? false
}:
{ nixpkgs ? ../nixpkgs }:
let
@@ -9,34 +6,37 @@ let
tarball =
{ nix ? {outPath = ./.; rev = 1234;}
, officialRelease ? false
}:
with import nixpkgs {};
releaseTools.sourceTarball {
name = "nix-tarball";
version = builtins.readFile ./version;
versionSuffix = if officialRelease then "" else "pre${toString nix.revCount}_${nix.shortRev}";
src = nix;
inherit officialRelease;
buildInputs =
[ curl bison25 flex2535 perl libxml2 libxslt w3m bzip2
tetex dblatex nukeReferences pkgconfig sqlite git
[ curl bison flex2533 perl libxml2 libxslt w3m bzip2
tetex dblatex nukeReferences
];
configureFlags = ''
--with-docbook-rng=${docbook5}/xml/rng/docbook
--with-docbook-xsl=${docbook5_xsl}/xml/xsl/docbook
--with-xml-flags=--nonet
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
'';
postUnpack = ''
# Clean up when building from a working tree.
(cd $sourceRoot && (git ls-files -o | xargs -r rm -v))
'';
# Include the ATerm and Bzip2 tarballs in the distribution.
preConfigure = ''
stripHash ${aterm242fixes.src}
cp -pv ${aterm242fixes.src} externals/$strippedName
stripHash ${bzip2.src}
cp -pv ${bzip2.src} externals/$strippedName
# TeX needs a writable font cache.
export VARTEXFONTS=$TMPDIR/texfonts
'';
@@ -63,51 +63,70 @@ let
build =
{ system ? "i686-linux" }:
{ tarball ? jobs.tarball {}
, system ? "i686-linux"
}:
with import nixpkgs { inherit system; };
with import nixpkgs {inherit system;};
releaseTools.nixBuild {
name = "nix";
src = tarball;
buildInputs = [ curl perl bzip2 openssl pkgconfig sqlite boehmgc ];
buildInputs = [curl perl bzip2 openssl];
configureFlags = ''
--disable-init-state
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
--enable-gc
--with-aterm=${aterm242fixes} --with-bzip2=${bzip2}
'';
doInstallCheck = true;
};
/*
static =
{ tarball ? jobs.tarball {}
, system ? "i686-linux"
}:
with import nixpkgs {inherit system;};
releaseTools.binaryTarball {
name = "nix-static-tarball";
src = tarball;
buildInputs = [curl perl bzip2];
configureFlags = ''
--disable-init-state
--with-aterm=${aterm242fixes} --with-bzip2=${bzip2}
--enable-static-nix
'';
};
*/
coverage =
with import nixpkgs { system = "x86_64-linux"; };
{ tarball ? jobs.tarball {}
}:
with import nixpkgs {};
releaseTools.coverageAnalysis {
name = "nix-build";
src = tarball;
buildInputs =
[ curl perl bzip2 openssl pkgconfig sqlite
# These are for "make check" only:
graphviz libxml2 libxslt
];
buildInputs = [
curl perl bzip2 openssl
# These are for "make check" only:
graphviz libxml2 libxslt
];
configureFlags = ''
--disable-init-state
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
--disable-init-state --disable-shared
--with-aterm=${aterm242fixes} --with-bzip2=${bzip2}
'';
dontInstall = false;
doInstallCheck = true;
lcovFilter = [ "*/boost/*" "*-tab.*" ];
lcovFilter = ["*/boost/*" "*-tab.*"];
# We call `dot', and even though we just use it to
# syntax-check generated dot files, it still requires some
@@ -116,38 +135,34 @@ let
};
rpm_fedora13i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora13i386) 50;
rpm_fedora13x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora13x86_64) 50;
rpm_fedora16i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora16i386) 50;
rpm_fedora16x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora16x86_64) 50;
rpm_opensuse103i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse103i386) 40;
rpm_opensuse110i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse110i386) 50;
rpm_opensuse110x86_64 = makeRPM_x86_64 (diskImageFuns: diskImageFuns.opensuse110x86_64) 50;
rpm_fedora5i386 = makeRPM_i686 (diskImages: diskImages.fedora5i386) 10;
rpm_fedora9i386 = makeRPM_i686 (diskImages: diskImages.fedora9i386) 20;
rpm_fedora9x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora9x86_64) 20;
rpm_fedora10i386 = makeRPM_i686 (diskImages: diskImages.fedora10i386) 30;
rpm_fedora10x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora10x86_64) 30;
rpm_fedora11i386 = makeRPM_i686 (diskImages: diskImages.fedora11i386) 40;
rpm_fedora11x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora11x86_64) 40;
rpm_fedora12i386 = makeRPM_i686 (diskImages: diskImages.fedora12i386) 50;
rpm_fedora12x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora12x86_64) 50;
rpm_opensuse103i386 = makeRPM_i686 (diskImages: diskImages.opensuse103i386) 40;
rpm_opensuse110i386 = makeRPM_i686 (diskImages: diskImages.opensuse110i386) 50;
rpm_opensuse110x86_64 = makeRPM_x86_64 (diskImages: diskImages.opensuse110x86_64) 50;
deb_debian60i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian60i386) 50;
deb_debian60x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian60x86_64) 50;
deb_ubuntu1004i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1004i386) 50;
deb_ubuntu1004x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1004x86_64) 50;
deb_ubuntu1010i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1010i386) 50;
deb_ubuntu1010x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1010x86_64) 50;
deb_ubuntu1110i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1110i386) 60;
deb_ubuntu1110x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1110x86_64) 60;
deb_ubuntu1204i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1204i386) 60;
deb_ubuntu1204x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1204x86_64) 60;
deb_debian40i386 = makeDeb_i686 (diskImages: diskImages.debian40i386) 40;
deb_debian40x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian40x86_64) 40;
deb_debian50i386 = makeDeb_i686 (diskImages: diskImages.debian50i386) 50;
deb_debian50x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian50x86_64) 50;
deb_ubuntu804i386 = makeDeb_i686 (diskImages: diskImages.ubuntu804i386) 20;
deb_ubuntu804x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu804x86_64) 20;
deb_ubuntu810i386 = makeDeb_i686 (diskImages: diskImages.ubuntu810i386) 30;
deb_ubuntu810x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu810x86_64) 30;
deb_ubuntu904i386 = makeDeb_i686 (diskImages: diskImages.ubuntu904i386) 40;
deb_ubuntu904x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu904x86_64) 40;
deb_ubuntu910i386 = makeDeb_i686 (diskImages: diskImages.ubuntu910i386) 50;
deb_ubuntu910x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu910x86_64) 50;
# System tests.
tests.remote_builds = (import ./tests/remote-builds.nix rec {
nix = build { inherit system; }; system = "x86_64-linux";
}).test;
tests.nix_copy_closure = (import ./tests/nix-copy-closure.nix rec {
nix = build { inherit system; }; system = "x86_64-linux";
}).test;
};
@@ -156,17 +171,17 @@ let
makeRPM =
system: diskImageFun: prio:
{ tarball ? jobs.tarball {}
}:
with import nixpkgs { inherit system; };
with import nixpkgs {inherit system;};
releaseTools.rpmBuild rec {
name = "nix-rpm-${diskImage.name}";
src = jobs.tarball;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages = [ "perl-DBD-SQLite" "perl-devel" "sqlite" "sqlite-devel" "bzip2-devel" ]; };
src = tarball;
diskImage = diskImageFun vmTools.diskImages;
memSize = 1024;
meta.schedulingPriority = prio;
postRPMInstall = "cd /tmp/rpmout/BUILD/nix-* && make installcheck";
meta = { schedulingPriority = toString prio; };
};
@@ -175,19 +190,19 @@ let
makeDeb =
system: diskImageFun: prio:
{ tarball ? jobs.tarball {}
}:
with import nixpkgs { inherit system; };
with import nixpkgs {inherit system;};
releaseTools.debBuild {
name = "nix-deb";
src = jobs.tarball;
diskImage = (diskImageFun vmTools.diskImageFuns)
{ extraPackages = [ "libdbd-sqlite3-perl" "libsqlite3-dev" "libbz2-dev" ]; };
src = tarball;
diskImage = diskImageFun vmTools.diskImages;
memSize = 1024;
meta.schedulingPriority = prio;
meta = { schedulingPriority = toString prio; };
configureFlags = "--sysconfdir=/etc";
debRequires = [ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" ];
doInstallCheck = true;
debRequires = ["curl"];
};

View File

@@ -1,19 +1,22 @@
bin_SCRIPTS = nix-collect-garbage \
nix-pull nix-push nix-prefetch-url \
nix-install-package nix-channel nix-build \
nix-copy-closure nix-generate-patches
nix-copy-closure
noinst_SCRIPTS = nix-profile.sh \
noinst_SCRIPTS = nix-profile.sh generate-patches.pl \
find-runtime-roots.pl build-remote.pl nix-reduce-build \
copy-from-other-stores.pl nix-http-export.cgi
nix-pull nix-push: download-using-manifests.pl
nix-pull nix-push: readmanifest.pm readconfig.pm download-using-manifests.pl
install-exec-local: download-using-manifests.pl copy-from-other-stores.pl find-runtime-roots.pl
install-exec-local: readmanifest.pm download-using-manifests.pl copy-from-other-stores.pl find-runtime-roots.pl
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/profile.d
$(INSTALL_PROGRAM) nix-profile.sh $(DESTDIR)$(sysconfdir)/profile.d/nix.sh
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix
$(INSTALL_DATA) readmanifest.pm $(DESTDIR)$(libexecdir)/nix
$(INSTALL_DATA) readconfig.pm $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) generate-patches.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) build-remote.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix/substituters
$(INSTALL_PROGRAM) download-using-manifests.pl $(DESTDIR)$(libexecdir)/nix/substituters
@@ -26,15 +29,14 @@ EXTRA_DIST = nix-collect-garbage.in \
nix-pull.in nix-push.in nix-profile.sh.in \
nix-prefetch-url.in nix-install-package.in \
nix-channel.in \
readmanifest.pm.in \
readconfig.pm.in \
nix-build.in \
download-using-manifests.pl.in \
copy-from-other-stores.pl.in \
generate-patches.pl.in \
nix-copy-closure.in \
find-runtime-roots.pl.in \
build-remote.pl.in \
nix-reduce-build.in \
nix-http-export.cgi.in \
nix-generate-patches.in
clean:
rm -f $(bin_SCRIPTS) $(noinst_SCRIPTS)
nix-http-export.cgi.in

View File

@@ -1,13 +1,9 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w
use Fcntl qw(:DEFAULT :flock);
use strict;
use Fcntl ':flock';
use English '-no_match_vars';
use IO::Handle;
use Nix::Config;
use Nix::SSH qw/sshOpts openSSHConnection/;
use Nix::CopyClosure;
no warnings('once');
# General operation:
#
@@ -26,272 +22,235 @@ no warnings('once');
# The nice thing about this scheme is that if we die prematurely, the
# locks are released automatically.
my $loadIncreased = 0;
# Make sure that we don't get any SSH passphrase or host key popups -
# if there is any problem it should fail, not do something
# interactive.
$ENV{"DISPLAY"} = "";
$ENV{"SSH_ASKPASS"} = "";
my ($amWilling, $localSystem, $neededSystem, $drvPath, $maxSilentTime) = @ARGV;
$maxSilentTime = 0 unless defined $maxSilentTime;
sub sendReply {
my $reply = shift;
print STDERR "# $reply\n";
}
sub all { $_ || return 0 for @_; 1 }
# Initialisation.
my $loadIncreased = 0;
my ($localSystem, $maxSilentTime, $printBuildTrace) = @ARGV;
$maxSilentTime = 0 unless defined $maxSilentTime;
sub decline {
sendReply "decline";
exit 0;
}
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
decline unless defined $currentLoad;
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
decline if !defined $conf || ! -e $conf;
my $canBuildLocally = $amWilling && ($localSystem eq $neededSystem);
# Read the list of machines.
my @machines;
open CONF, "< $conf" or die;
while (<CONF>) {
chomp;
s/\#.*$//g;
next if /^\s*$/;
/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)(\s+([0-9\.]+))?\s*$/ or die;
push @machines,
{ hostName => $1
, systemTypes => [split(/,/, $2)]
, sshKeys => $3
, maxJobs => $4
, speedFactor => 1.0 * ($6 || 1)
};
}
close CONF;
# Acquire the exclusive lock on $currentLoad/main-lock.
my $mainLock = "$currentLoad/main-lock";
open MAINLOCK, ">>$mainLock" or die;
flock(MAINLOCK, LOCK_EX) or die;
sub openSlotLock {
my ($machine, $slot) = @_;
my $slotLockFn = "$currentLoad/" . (join '+', @{$machine->{systemTypes}}) . "-" . $machine->{hostName} . "-$slot";
my $slotLock = new IO::Handle;
sysopen $slotLock, "$slotLockFn", O_RDWR|O_CREAT, 0600 or die;
open $slotLock, ">>$slotLockFn" or die;
return $slotLock;
}
# Read the list of machines.
my @machines;
if (defined $conf && -e $conf) {
open CONF, "<$conf" or die;
while (<CONF>) {
chomp;
s/\#.*$//g;
next if /^\s*$/;
my @tokens = split /\s/, $_;
my @supportedFeatures = split(/,/, $tokens[5] || "");
my @mandatoryFeatures = split(/,/, $tokens[6] || "");
push @machines,
{ hostName => $tokens[0]
, systemTypes => [ split(/,/, $tokens[1]) ]
, sshKeys => $tokens[2]
, maxJobs => int($tokens[3])
, speedFactor => 1.0 * (defined $tokens[4] ? int($tokens[4]) : 1)
, supportedFeatures => [ @supportedFeatures, @mandatoryFeatures ]
, mandatoryFeatures => [ @mandatoryFeatures ]
, enabled => 1
};
}
close CONF;
}
# Wait for the calling process to ask us whether we can build some derivation.
my ($drvPath, $hostName, $slotLock);
REQ: while (1) {
$_ = <STDIN> || exit 0;
(my $amWilling, my $neededSystem, $drvPath, my $requiredFeatures) = split;
my @requiredFeatures = split /,/, $requiredFeatures;
my $canBuildLocally = $amWilling && ($localSystem eq $neededSystem);
if (!defined $currentLoad) {
sendReply "decline";
next;
}
# Acquire the exclusive lock on $currentLoad/main-lock.
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
my $mainLock = "$currentLoad/main-lock";
sysopen MAINLOCK, "$mainLock", O_RDWR|O_CREAT, 0600 or die;
flock(MAINLOCK, LOCK_EX) or die;
while (1) {
# Find all machine that can execute this build, i.e., that
# support builds for the given platform and features, and are
# not at their job limit.
my $rightType = 0;
my @available = ();
LOOP: foreach my $cur (@machines) {
if ($cur->{enabled}
&& (grep { $neededSystem eq $_ } @{$cur->{systemTypes}})
&& all(map { my $f = $_; 0 != grep { $f eq $_ } @{$cur->{supportedFeatures}} } (@requiredFeatures, @mandatoryFeatures))
&& all(map { my $f = $_; 0 != grep { $f eq $_ } @requiredFeatures } @{$cur->{mandatoryFeatures}})
)
{
$rightType = 1;
# We have a machine of the right type. Determine the load on
# the machine.
my $slot = 0;
my $load = 0;
my $free;
while ($slot < $cur->{maxJobs}) {
my $slotLock = openSlotLock($cur, $slot);
if (flock($slotLock, LOCK_EX | LOCK_NB)) {
$free = $slot unless defined $free;
flock($slotLock, LOCK_UN) or die;
} else {
$load++;
}
close $slotLock;
$slot++;
}
push @available, { machine => $cur, load => $load, free => $free }
if $load < $cur->{maxJobs};
}
}
# Find all machine that can execute this build, i.e., that support
# builds for the given platform and are not at their job limit.
my $rightType = 0;
my @available = ();
LOOP: foreach my $cur (@machines) {
if (grep { $neededSystem eq $_ } @{$cur->{systemTypes}}) {
$rightType = 1;
if (defined $ENV{NIX_DEBUG_HOOK}) {
print STDERR "load on " . $_->{machine}->{hostName} . " = " . $_->{load} . "\n"
foreach @available;
}
# Didn't find any available machine? Then decline or postpone.
if (scalar @available == 0) {
# Postpone if we have a machine of the right type, except
# if the local system can and wants to do the build.
if ($rightType && !$canBuildLocally) {
sendReply "postpone";
# We have a machine of the right type. Determine the load on
# the machine.
my $slot = 0;
my $load = 0;
my $free;
while ($slot < $cur->{maxJobs}) {
my $slotLock = openSlotLock($cur, $slot);
if (flock($slotLock, LOCK_EX | LOCK_NB)) {
$free = $slot unless defined $free;
flock($slotLock, LOCK_UN) or die;
} else {
sendReply "decline";
$load++;
}
close MAINLOCK;
next REQ;
close $slotLock;
$slot++;
}
# Prioritise the available machines as follows:
# - First by load divided by speed factor, rounded to the nearest
# integer. This causes fast machines to be preferred over slow
# machines with similar loads.
# - Then by speed factor.
# - Finally by load.
sub lf { my $x = shift; return int($x->{load} / $x->{machine}->{speedFactor} + 0.4999); }
@available = sort
{ lf($a) <=> lf($b)
|| $b->{machine}->{speedFactor} <=> $a->{machine}->{speedFactor}
|| $a->{load} <=> $b->{load}
} @available;
# Select the best available machine and lock a free slot.
my $selected = $available[0];
my $machine = $selected->{machine};
$slotLock = openSlotLock($machine, $selected->{free});
flock($slotLock, LOCK_EX | LOCK_NB) or die;
utime undef, undef, $slotLock;
close MAINLOCK;
# Connect to the selected machine.
@sshOpts = ("-i", $machine->{sshKeys}, "-x");
$hostName = $machine->{hostName};
last REQ if openSSHConnection $hostName;
warn "unable to open SSH connection to $hostName, trying other available machines...\n";
$machine->{enabled} = 0;
push @available, { machine => $cur, load => $load, free => $free }
if $load < $cur->{maxJobs};
}
}
if (defined $ENV{NIX_DEBUG_HOOK}) {
print STDERR "load on " . $_->{machine}->{hostName} . " = " . $_->{load} . "\n"
foreach @available;
}
# Didn't find any available machine? Then decline or postpone.
if (scalar @available == 0) {
# Postpone if we have a machine of the right type, except if the
# local system can and wants to do the build.
if ($rightType && !$canBuildLocally) {
sendReply "postpone";
exit 0;
} else {
decline;
}
}
# Prioritise the available machines as follows:
# - First by load divided by speed factor, rounded to the nearest
# integer. This causes fast machines to be preferred over slow
# machines with similar loads.
# - Then by speed factor.
# - Finally by load.
sub lf { my $x = shift; return int($x->{load} / $x->{machine}->{speedFactor} + 0.4999); }
@available = sort
{ lf($a) <=> lf($b)
|| $b->{machine}->{speedFactor} <=> $a->{machine}->{speedFactor}
|| $a->{load} <=> $b->{load}
} @available;
# Select the best available machine and lock a free slot.
my $selected = $available[0];
my $machine = $selected->{machine};
my $slotLock = openSlotLock($machine, $selected->{free});
flock($slotLock, LOCK_EX | LOCK_NB) or die;
utime undef, undef, $slotLock;
close MAINLOCK;
# Tell Nix we've accepted the build.
sendReply "accept";
my @inputs = split /\s/, readline(STDIN);
my @outputs = split /\s/, readline(STDIN);
if (defined $ENV{NIX_DEBUG_HOOK}) {
my $hostName = $machine->{hostName};
my $sp = $machine->{speedFactor};
print STDERR "building `$drvPath' on `$hostName' - $sp - " . $selected->{free} . "\n";
sleep 10;
exit 0;
}
my $x = <STDIN>;
chomp $x;
if ($x ne "okay") {
exit 0;
}
# Do the actual build.
my $hostName = $machine->{hostName};
print STDERR "building `$drvPath' on `$hostName'\n";
print STDERR "@ build-remote $drvPath $hostName\n" if $printBuildTrace;
# 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 " . $machine->{sshKeys} . " -x";
# Hack to support Cygwin: if we login without a password, we don't
# have exactly the same rights 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 ($machine->{sshKeys} =~ /^password:/) {
my $passwordFile = $machine->{sshKeys};
$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::Config::confDir/signing-key.sec";
$maybeSign = "--sign" if -e "/nix/etc/nix/signing-key.sec";
system("NIX_SSHOPTS=\"$sshOpts\" @bindir@/nix-copy-closure $hostName $maybeSign $drvPath $inputs") == 0
or die "cannot copy inputs to $hostName: $?";
# Register the derivation as a temporary GC root. Note that $PPID is
# the PID of the remote SSH process, which, due to the use of a
# persistant SSH connection, should be the same across all remote
# command invocations for this session.
my $rootsDir = "@localstatedir@/nix/gcroots/tmp";
system("ssh $hostName @sshOpts 'mkdir -m 1777 -p $rootsDir; ln -sfn $drvPath $rootsDir/\$PPID.drv'");
print "building...\n";
sub removeRoots {
system("ssh $hostName @sshOpts 'rm -f $rootsDir/\$PPID.drv $rootsDir/\$PPID.out'");
}
my $buildFlags = "--max-silent-time $maxSilentTime";
# Copy the derivation and its dependencies to the build machine. This
# is guarded by an exclusive lock per machine to prevent multiple
# build-remote instances from copying to a machine simultaneously.
# That's undesirable because we may end up with N instances uploading
# the same missing path simultaneously, causing the effective network
# bandwidth and target disk speed to be divided by N.
my $uploadLock = "$currentLoad/$hostName.upload-lock";
sysopen UPLOADLOCK, "$uploadLock", O_RDWR|O_CREAT, 0600 or die;
eval {
local $SIG{ALRM} = sub { die "alarm\n" };
# Don't wait forever, so that a process that gets stuck while
# holding the lock doesn't block everybody else indefinitely.
# It's safe to continue after a timeout, just (potentially)
# inefficient.
alarm 15 * 60;
flock(UPLOADLOCK, LOCK_EX);
alarm 0;
};
if ($@) {
die unless $@ eq "alarm\n";
print STDERR "somebody is hogging $uploadLock, continuing...\n";
unlink $uploadLock;
}
Nix::CopyClosure::copyTo($hostName, [ @sshOpts ], [ $drvPath, @inputs ], "", "", 0, 0, $maybeSign ne "", "");
close UPLOADLOCK;
# Perform the build.
my $buildFlags = "--max-silent-time $maxSilentTime --fallback --add-root $rootsDir/\$PPID.out --option verbosity 0";
# We let the remote side kill its process group when the connection is
# closed unexpectedly. This is necessary to ensure that no processes
# are left running on the remote system if the local Nix process is
# killed. (SSH itself doesn't kill child processes if the connection
# is interrupted unless the `-tt' flag is used to force a pseudo-tty,
# in which case every child receives SIGHUP; however, `-tt' doesn't
# work on some platforms when connection sharing is used.)
pipe STDIN, DUMMY; # make sure we have a readable STDIN
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
# Note that if we get exit code 100 from `nix-store -r', it
# denotes a permanent build failure (as opposed to an SSH problem
# or a temporary Nix problem). We propagate this to the caller to
# allow it to distinguish between transient and permanent
# failures.
my $res = $? >> 8;
print STDERR "build of `$drvPath' on `$hostName' failed with exit code $res\n";
removeRoots;
# `-tt' forces allocation of a pseudo-terminal. This is required to
# make the remote nix-store process receive a signal when the
# connection dies. Without it, the remote process might continue to
# run indefinitely (that is, until it next tries to write to
# stdout/stderr).
if (system("ssh -tt $sshOpts $hostName 'nix-store --realise $buildFlags $drvPath > /dev/null'") != 0) {
# If we couldn't run ssh or there was an ssh problem (indicated by
# exit code 255), then we return exit code 1; otherwise we assume
# that the builder failed, which we indicated to Nix using exit
# code 100. It's important to distinguish between the two because
# the first is a transient failure and the latter is permanent.
my $res = $? == -1 || ($? >> 8) == 255 ? 1 : 100;
print STDERR "build of `$drvPath' on `$hostName' failed with exit code $?\n";
exit $res;
}
#print "build of `$drvPath' on `$hostName' succeeded\n";
print "build of `$drvPath' on `$hostName' succeeded\n";
# Copy the output from the build machine.
foreach my $output (@outputs) {
foreach my $output (split '\n', $outputs) {
my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0;
system("exec ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output'" .
"| NIX_HELD_LOCKS=$output @bindir@/nix-store --import > /dev/null") == 0
system("ssh $sshOpts $hostName 'nix-store --export $maybeSignRemote $output' | @bindir@/nix-store --import > /dev/null") == 0
or die "cannot copy $output from $hostName: $?";
}
# Get rid of the temporary GC roots.
removeRoots;

65
scripts/copy-from-other-stores.pl.in Executable file → Normal file
View File

@@ -1,4 +1,4 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w
use strict;
use File::Basename;
@@ -17,19 +17,25 @@ foreach my $dir (@remoteStoresAll) {
}
$ENV{"NIX_REMOTE"} = "";
sub findStorePath {
my $storePath = shift;
my $storePathName = basename $storePath;
foreach my $store (@remoteStores) {
my $sourcePath = "$store/store/" . basename $storePath;
next unless -e $sourcePath || -l $sourcePath;
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
return ($store, $sourcePath) if
system("@bindir@/nix-store --check-validity $storePath") == 0;
# Determine whether $storePath exists by looking for the
# existence of the info file, and if so, get store path info
# from that file. This rather breaks abstraction: we should
# be using `nix-store' for that. But right now there is no
# good way to tell nix-store to access a store mounted under a
# different location (there's $NIX_STORE, but that only works
# if the remote store is mounted under its "real" location).
my $infoFile = "$store/var/nix/db/info/$storePathName";
my $storePath2 = "$store/store/$storePathName";
if (-f $infoFile && -e $storePath2) {
return ($infoFile, $storePath2);
}
}
return undef;
}
@@ -40,38 +46,37 @@ if ($ARGV[0] eq "--query") {
if ($cmd eq "have") {
my $storePath = <STDIN>; chomp $storePath;
print STDOUT (defined findStorePath($storePath) ? "1\n" : "0\n");
(my $infoFile) = findStorePath $storePath;
print STDOUT ($infoFile ? "1\n" : "0\n");
}
elsif ($cmd eq "info") {
my $storePath = <STDIN>; chomp $storePath;
my ($store, $sourcePath) = findStorePath($storePath);
if (!defined $store) {
(my $infoFile) = findStorePath $storePath;
if (!$infoFile) {
print "0\n";
next; # not an error
}
print "1\n";
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
my $deriver = `@bindir@/nix-store --query --deriver $storePath`;
die "cannot query deriver of `$storePath'" if $? != 0;
chomp $deriver;
$deriver = "" if $deriver eq "unknown-deriver";
my $deriver = "";
my @references = ();
my @references = split "\n",
`@bindir@/nix-store --query --references $storePath`;
die "cannot query references of `$storePath'" if $? != 0;
my $narSize = `@bindir@/nix-store --query --size $storePath`;
die "cannot query size of `$storePath'" if $? != 0;
chomp $narSize;
open INFO, "<$infoFile" or die "cannot read info file $infoFile\n";
while (<INFO>) {
chomp;
/^([\w-]+): (.*)$/ or die "bad info file";
my $key = $1;
my $value = $2;
if ($key eq "Deriver") { $deriver = $value; }
elsif ($key eq "References") { @references = split ' ', $value; }
}
close INFO;
print "$deriver\n";
print scalar @references, "\n";
print "$_\n" foreach @references;
print "$narSize\n";
print "$narSize\n";
print "0\n"; # !!! showing size not supported (yet)
}
else { die "unknown command `$cmd'"; }
@@ -82,8 +87,8 @@ if ($ARGV[0] eq "--query") {
elsif ($ARGV[0] eq "--substitute") {
die unless scalar @ARGV == 2;
my $storePath = $ARGV[1];
my ($store, $sourcePath) = findStorePath $storePath;
die unless $store;
(my $infoFile, my $sourcePath) = findStorePath $storePath;
die unless $infoFile;
print "\n*** Copying `$storePath' from `$sourcePath'\n\n";
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $storePath") == 0
or die "cannot copy `$sourcePath' to `$storePath'";

427
scripts/download-using-manifests.pl.in Executable file → Normal file
View File

@@ -1,170 +1,33 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w -I@libexecdir@/nix
use strict;
use Nix::Config;
use Nix::Manifest;
use Nix::Store;
use readmanifest;
use POSIX qw(strftime);
use File::Temp qw(tempdir);
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
STDOUT->autoflush(1);
my $logFile = "$Nix::Config::logDir/downloads";
# For queries, skip expensive calls to nix-hash etc. We're just
# estimating the expected download size.
my $fast = 1;
my $manifestDir = ($ENV{"NIX_MANIFESTS_DIR"} or "@localstatedir@/nix/manifests");
my $logFile = "@localstatedir@/log/nix/downloads";
# Open the manifest cache and update it if necessary.
my $dbh = updateManifestDB();
# Load all manifests.
my %narFiles;
my %localPaths;
my %patches;
# $hashCache->{$algo}->{$path} yields the $algo-hash of $path.
my $hashCache;
sub parseHash {
my $hash = shift;
if ($hash =~ /^(.+):(.+)$/) {
return ($1, $2);
} else {
return ("md5", $hash);
for my $manifest (glob "$manifestDir/*.nixmanifest") {
my $version = readManifest($manifest, \%narFiles, \%localPaths, \%patches);
if ($version < 3) {
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
exit 1;
}
}
# Compute the most efficient sequence of downloads to produce the
# given path.
sub computeSmallestDownload {
my $targetPath = shift;
# Build a graph of all store paths that might contribute to the
# construction of $targetPath, and the special node "start". The
# edges are either patch operations, or downloads of full NAR
# files. The latter edges only occur between "start" and a store
# path.
my %graph;
$graph{"start"} = {d => 0, pred => undef, edges => []};
my @queue = ();
my $queueFront = 0;
my %done;
sub addNode {
my $graph = shift;
my $u = shift;
$$graph{$u} = {d => 999999999999, pred => undef, edges => []}
unless defined $$graph{$u};
if ($version >= 10) {
print STDERR "manifest `$manifest' is too new; please delete it or upgrade Nix\n";
exit 1;
}
sub addEdge {
my $graph = shift;
my $u = shift;
my $v = shift;
my $w = shift;
my $type = shift;
my $info = shift;
addNode $graph, $u;
push @{$$graph{$u}->{edges}},
{weight => $w, start => $u, end => $v, type => $type, info => $info};
my $n = scalar @{$$graph{$u}->{edges}};
}
push @queue, $targetPath;
while ($queueFront < scalar @queue) {
my $u = $queue[$queueFront++];
next if defined $done{$u};
$done{$u} = 1;
addNode \%graph, $u;
# If the path already exists, it has distance 0 from the
# "start" node.
if (isValidPath($u)) {
addEdge \%graph, "start", $u, 0, "present", undef;
}
else {
# Add patch edges.
my $patchList = $dbh->selectall_arrayref(
"select * from Patches where storePath = ?",
{ Slice => {} }, $u);
foreach my $patch (@{$patchList}) {
if (isValidPath($patch->{basePath})) {
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
my $hash = $hashCache->{$baseHashAlgo}->{$patch->{basePath}};
if (!defined $hash) {
$hash = $fast && $baseHashAlgo eq "sha256"
? queryPathHash($patch->{basePath})
: hashPath($baseHashAlgo, $baseHashAlgo ne "md5", $patch->{basePath});
$hash =~ s/.*://;
$hashCache->{$baseHashAlgo}->{$patch->{basePath}} = $hash;
}
next if $hash ne $baseHash;
}
push @queue, $patch->{basePath};
addEdge \%graph, $patch->{basePath}, $u, $patch->{size}, "patch", $patch;
}
# Add NAR file edges to the start node.
my $narFileList = $dbh->selectall_arrayref(
"select * from NARs where storePath = ?",
{ Slice => {} }, $u);
foreach my $narFile (@{$narFileList}) {
# !!! how to handle files whose size is not known in advance?
# For now, assume some arbitrary size (1 GB).
# This has the side-effect of preferring non-Hydra downloads.
addEdge \%graph, "start", $u, ($narFile->{size} || 1000000000), "narfile", $narFile;
}
}
}
# Run Dijkstra's shortest path algorithm to determine the shortest
# sequence of download and/or patch actions that will produce
# $targetPath.
my @todo = keys %graph;
while (scalar @todo > 0) {
# Remove the closest element from the todo list.
# !!! inefficient, use a priority queue
@todo = sort { -($graph{$a}->{d} <=> $graph{$b}->{d}) } @todo;
my $u = pop @todo;
my $u_ = $graph{$u};
foreach my $edge (@{$u_->{edges}}) {
my $v_ = $graph{$edge->{end}};
if ($v_->{d} > $u_->{d} + $edge->{weight}) {
$v_->{d} = $u_->{d} + $edge->{weight};
# Store the edge; to edge->start is actually the
# predecessor.
$v_->{pred} = $edge;
}
}
}
# Retrieve the shortest path from "start" to $targetPath.
my @path = ();
my $cur = $targetPath;
return () unless defined $graph{$targetPath}->{pred};
while ($cur ne "start") {
push @path, $graph{$cur}->{pred};
$cur = $graph{$cur}->{pred}->{start};
}
return @path;
}
@@ -177,52 +40,30 @@ if ($ARGV[0] eq "--query") {
if ($cmd eq "have") {
my $storePath = <STDIN>; chomp $storePath;
print STDOUT (
scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0
print STDOUT ((defined $narFiles{$storePath} or defined $localPaths{$storePath})
? "1\n" : "0\n");
}
elsif ($cmd eq "info") {
my $storePath = <STDIN>; chomp $storePath;
my $infos = $dbh->selectall_arrayref(
"select * from NARs where storePath = ?",
{ Slice => {} }, $storePath);
my $info;
if (scalar @{$infos} > 0) {
$info = @{$infos}[0];
if (defined $narFiles{$storePath}) {
$info = @{$narFiles{$storePath}}[0];
}
elsif (defined $localPaths{$storePath}) {
$info = @{$localPaths{$storePath}}[0];
}
else {
print "0\n";
next; # not an error
}
print "1\n";
print "$info->{deriver}\n";
my @references = split " ", $info->{refs};
my @references = split " ", $info->{references};
print scalar @references, "\n";
print "$_\n" foreach @references;
my @path = computeSmallestDownload $storePath;
my $downloadSize = 0;
while (scalar @path > 0) {
my $edge = pop @path;
my $u = $edge->{start};
my $v = $edge->{end};
if ($edge->{type} eq "patch") {
$downloadSize += $edge->{info}->{size} || 0;
}
elsif ($edge->{type} eq "narfile") {
$downloadSize += $edge->{info}->{size} || 0;
}
}
print "$downloadSize\n";
my $narSize = $info->{narSize} || 0;
print "$narSize\n";
my $size = $info->{size} || 0;
print "$size\n";
}
else { die "unknown command `$cmd'"; }
@@ -232,19 +73,20 @@ if ($ARGV[0] eq "--query") {
}
elsif ($ARGV[0] ne "--substitute") {
die;
die "syntax: $0 [--query-paths | --query-info PATHS... | --substitute PATH]\n";
}
die unless scalar @ARGV == 2;
my $targetPath = $ARGV[1];
$fast = 0;
# Create a temporary directory.
my $tmpDir = tempdir("nix-download.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
chdir $tmpDir or die "cannot change to `$tmpDir': $!";
my $tmpNar = "$tmpDir/nar";
my $tmpNar2 = "$tmpDir/nar2";
@@ -254,18 +96,164 @@ open LOGFILE, ">>$logFile" or die "cannot open log file $logFile";
my $date = strftime ("%F %H:%M:%S UTC", gmtime (time));
print LOGFILE "$$ get $targetPath $date\n";
print STDERR "\n*** Trying to download/patch `$targetPath'\n";
print "\n*** Trying to download/patch `$targetPath'\n";
# Compute the shortest path.
my @path = computeSmallestDownload $targetPath;
die "don't know how to produce $targetPath\n" if scalar @path == 0;
# If we can copy from a local path, do that.
my $localPathList = $localPaths{$targetPath};
foreach my $localPath (@{$localPathList}) {
my $sourcePath = $localPath->{copyFrom};
if (-e $sourcePath) {
print "\n*** Step 1/1: copying from $sourcePath\n";
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $targetPath") == 0
or die "cannot copy `$sourcePath' to `$targetPath'";
exit 0;
}
}
# We don't need the manifest anymore, so close it as an optimisation:
# if we still have SQLite locks blocking other processes (we
# shouldn't), this gets rid of them.
$dbh->disconnect;
# Build a graph of all store paths that might contribute to the
# construction of $targetPath, and the special node "start". The
# edges are either patch operations, or downloads of full NAR files.
# The latter edges only occur between "start" and a store path.
my %graph;
$graph{"start"} = {d => 0, pred => undef, edges => []};
my @queue = ();
my $queueFront = 0;
my %done;
sub addToQueue {
my $v = shift;
return if defined $done{$v};
$done{$v} = 1;
push @queue, $v;
}
sub addNode {
my $u = shift;
$graph{$u} = {d => 999999999999, pred => undef, edges => []}
unless defined $graph{$u};
}
sub addEdge {
my $u = shift;
my $v = shift;
my $w = shift;
my $type = shift;
my $info = shift;
addNode $u;
push @{$graph{$u}->{edges}},
{weight => $w, start => $u, end => $v, type => $type, info => $info};
my $n = scalar @{$graph{$u}->{edges}};
}
addToQueue $targetPath;
sub isValidPath {
my $p = shift;
return system("$binDir/nix-store --check-validity '$p' 2> /dev/null") == 0;
}
sub parseHash {
my $hash = shift;
if ($hash =~ /^(.+):(.+)$/) {
return ($1, $2);
} else {
return ("md5", $hash);
}
}
while ($queueFront < scalar @queue) {
my $u = $queue[$queueFront++];
# print "$u\n";
addNode $u;
# If the path already exists, it has distance 0 from the "start"
# node.
if (isValidPath($u)) {
addEdge "start", $u, 0, "present", undef;
}
else {
# Add patch edges.
my $patchList = $patches{$u};
foreach my $patch (@{$patchList}) {
if (isValidPath($patch->{basePath})) {
# !!! this should be cached
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
my $format = "--base32";
$format = "" if $baseHashAlgo eq "md5";
my $hash = `$binDir/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`;
chomp $hash;
if ($hash ne $baseHash) {
print LOGFILE "$$ rejecting $patch->{basePath}\n";
next;
}
}
addToQueue $patch->{basePath};
addEdge $patch->{basePath}, $u, $patch->{size}, "patch", $patch;
}
# Add NAR file edges to the start node.
my $narFileList = $narFiles{$u};
foreach my $narFile (@{$narFileList}) {
# !!! how to handle files whose size is not known in advance?
# For now, assume some arbitrary size (1 MB).
addEdge "start", $u, ($narFile->{size} || 1000000), "narfile", $narFile;
if ($u eq $targetPath) {
my $size = $narFile->{size} || -1;
print LOGFILE "$$ full-download-would-be $size\n";
}
}
}
}
# Run Dijkstra's shortest path algorithm to determine the shortest
# sequence of download and/or patch actions that will produce
# $targetPath.
sub byDistance { # sort by distance, reversed
return -($graph{$a}->{d} <=> $graph{$b}->{d});
}
my @todo = keys %graph;
while (scalar @todo > 0) {
# Remove the closest element from the todo list.
@todo = sort byDistance @todo;
my $u = pop @todo;
my $u_ = $graph{$u};
foreach my $edge (@{$u_->{edges}}) {
my $v_ = $graph{$edge->{end}};
if ($v_->{d} > $u_->{d} + $edge->{weight}) {
$v_->{d} = $u_->{d} + $edge->{weight};
# Store the edge; to edge->start is actually the
# predecessor.
$v_->{pred} = $edge;
}
}
}
# Retrieve the shortest path from "start" to $targetPath.
my @path = ();
my $cur = $targetPath;
die "don't know how to produce $targetPath\n"
unless defined $graph{$targetPath}->{pred};
while ($cur ne "start") {
push @path, $graph{$cur}->{pred};
$cur = $graph{$cur}->{pred}->{start};
}
# Traverse the shortest path, perform the actions described by the
@@ -277,8 +265,8 @@ sub downloadFile {
my $url = shift;
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `$Nix::Config::binDir/nix-prefetch-url '$url'`;
die "download of `$url' failed" . ($! ? ": $!" : "") . "\n" unless $? == 0;
my ($hash, $path) = `$binDir/nix-prefetch-url '$url'`;
die "download of `$url' failed" unless $? == 0;
chomp $path;
return $path;
}
@@ -290,36 +278,36 @@ while (scalar @path > 0) {
my $u = $edge->{start};
my $v = $edge->{end};
print STDERR "\n*** Step $curStep/$maxStep: ";
print "\n*** Step $curStep/$maxStep: ";
if ($edge->{type} eq "present") {
print STDERR "using already present path `$v'\n";
print "using already present path `$v'\n";
print LOGFILE "$$ present $v\n";
if ($curStep < $maxStep) {
# Since this is not the last step, the path will be used
# as a base to one or more patches. So turn the base path
# into a NAR archive, to which we can apply the patch.
print STDERR " packing base path...\n";
system("$Nix::Config::binDir/nix-store --dump $v > $tmpNar") == 0
print " packing base path...\n";
system("$binDir/nix-store --dump $v > $tmpNar") == 0
or die "cannot dump `$v'";
}
}
elsif ($edge->{type} eq "patch") {
my $patch = $edge->{info};
print STDERR "applying patch `$patch->{url}' to `$u' to create `$v'\n";
print "applying patch `$patch->{url}' to `$u' to create `$v'\n";
print LOGFILE "$$ patch $patch->{url} $patch->{size} $patch->{baseHash} $u $v\n";
# Download the patch.
print STDERR " downloading patch...\n";
print " downloading patch...\n";
my $patchPath = downloadFile "$patch->{url}";
# Apply the patch to the NAR archive produced in step 1 (for
# the already present path) or a later step (for patch sequences).
print STDERR " applying patch...\n";
system("$Nix::Config::libexecDir/bspatch $tmpNar $tmpNar2 $patchPath") == 0
print " applying patch...\n";
system("@libexecdir@/bspatch $tmpNar $tmpNar2 $patchPath") == 0
or die "cannot apply patch `$patchPath' to $tmpNar";
if ($curStep < $maxStep) {
@@ -328,8 +316,8 @@ while (scalar @path > 0) {
} else {
# This was the last patch. Unpack the final NAR archive
# into the target path.
print STDERR " unpacking patched archive...\n";
system("$Nix::Config::binDir/nix-store --restore $v < $tmpNar2") == 0
print " unpacking patched archive...\n";
system("$binDir/nix-store --restore $v < $tmpNar2") == 0
or die "cannot unpack $tmpNar2 into `$v'";
}
@@ -338,23 +326,23 @@ while (scalar @path > 0) {
elsif ($edge->{type} eq "narfile") {
my $narFile = $edge->{info};
print STDERR "downloading `$narFile->{url}' into `$v'\n";
print "downloading `$narFile->{url}' into `$v'\n";
my $size = $narFile->{size} || -1;
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
# Download the archive.
print STDERR " downloading archive...\n";
print " downloading archive...\n";
my $narFilePath = downloadFile "$narFile->{url}";
if ($curStep < $maxStep) {
# The archive will be used a base to a patch.
system("$Nix::Config::bzip2 -d < '$narFilePath' > $tmpNar") == 0
system("@bunzip2@ < '$narFilePath' > $tmpNar") == 0
or die "cannot unpack `$narFilePath' into `$v'";
} else {
# Unpack the archive into the target path.
print STDERR " unpacking archive...\n";
system("$Nix::Config::bzip2 -d < '$narFilePath' | $Nix::Config::binDir/nix-store --restore '$v'") == 0
print " unpacking archive...\n";
system("@bunzip2@ < '$narFilePath' | $binDir/nix-store --restore '$v'") == 0
or die "cannot unpack `$narFilePath' into `$v'";
}
@@ -373,15 +361,20 @@ if (defined $finalNarHash) {
# The hash in the manifest can be either in base-16 or base-32.
# Handle both.
my $hash2 = hashPath($hashAlgo, $hashAlgo eq "sha256" && length($hash) != 64, $targetPath);
my $extraFlag =
($hashAlgo eq "sha256" && length($hash) != 64)
? "--base32" : "";
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2\n"
my $hash2 = `@bindir@/nix-hash --type $hashAlgo $extraFlag $targetPath`
or die "cannot compute hash of path `$targetPath'";
chomp $hash2;
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2"
if $hash ne $hash2;
} else {
die "cannot check integrity of the downloaded path since its hash is not known\n";
die "cannot check integrity of the downloaded path since its hash is not known";
}
print STDERR "\n";
print LOGFILE "$$ success\n";
close LOGFILE;

0
scripts/find-runtime-roots.pl.in Executable file → Normal file
View File

408
scripts/generate-patches.pl.in Executable file
View File

@@ -0,0 +1,408 @@
#! @perl@ -w -I@libexecdir@/nix
use strict;
use File::Temp qw(tempdir);
use readmanifest;
# Some patch generations options.
# Max size of NAR archives to generate patches for.
my $maxNarSize = $ENV{"NIX_MAX_NAR_SIZE"};
$maxNarSize = 100 * 1024 * 1024 if !defined $maxNarSize;
# If patch is bigger than this fraction of full archive, reject.
my $maxPatchFraction = $ENV{"NIX_PATCH_FRACTION"};
$maxPatchFraction = 0.60 if !defined $maxPatchFraction;
die unless scalar @ARGV == 5;
my $hashAlgo = "sha256";
my $cacheDir = $ARGV[0];
my $patchesDir = $ARGV[1];
my $patchesURL = $ARGV[2];
my $srcDir = $ARGV[3];
my $dstDir = $ARGV[4];
my $tmpDir = tempdir("nix-generate-patches.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
print "TEMP = $tmpDir\n";
#END { rmdir $tmpDir; }
my %srcNarFiles;
my %srcLocalPaths;
my %srcPatches;
my %dstNarFiles;
my %dstLocalPaths;
my %dstPatches;
readManifest "$srcDir/MANIFEST",
\%srcNarFiles, \%srcLocalPaths, \%srcPatches;
readManifest "$dstDir/MANIFEST",
\%dstNarFiles, \%dstLocalPaths, \%dstPatches;
sub findOutputPaths {
my $narFiles = shift;
my %outPaths;
foreach my $p (keys %{$narFiles}) {
# Ignore store expressions.
next if ($p =~ /\.store$/);
next if ($p =~ /\.drv$/);
# Ignore builders (too much ambiguity -- they're all called
# `builder.sh').
next if ($p =~ /\.sh$/);
next if ($p =~ /\.patch$/);
# Don't bother including tar files etc.
next if ($p =~ /\.tar\.(gz|bz2)$/ || $p =~ /\.zip$/ || $p =~ /\.bin$/);
$outPaths{$p} = 1;
}
return %outPaths;
}
print "finding src output paths...\n";
my %srcOutPaths = findOutputPaths \%srcNarFiles;
print "finding dst output paths...\n";
my %dstOutPaths = findOutputPaths \%dstNarFiles;
sub getNameVersion {
my $p = shift;
$p =~ /\/[0-9a-z]+((?:-[a-zA-Z][^\/-]*)+)([^\/]*)$/;
my $name = $1;
my $version = $2;
$name =~ s/^-//;
$version =~ s/^-//;
return ($name, $version);
}
# A quick hack to get a measure of the `distance' between two
# versions: it's just the position of the first character that differs
# (or 999 if they are the same).
sub versionDiff {
my $s = shift;
my $t = shift;
my $i;
return 999 if $s eq $t;
for ($i = 0; $i < length $s; $i++) {
return $i if $i >= length $t or
substr($s, $i, 1) ne substr($t, $i, 1);
}
return $i;
}
sub getNarBz2 {
my $narFiles = shift;
my $storePath = shift;
my $narFileList = $$narFiles{$storePath};
die "missing store expression $storePath" unless defined $narFileList;
my $narFile = @{$narFileList}[0];
die unless defined $narFile;
$narFile->{url} =~ /\/([^\/]+)$/;
die unless defined $1;
return "$cacheDir/$1";
}
sub containsPatch {
my $patches = shift;
my $storePath = shift;
my $basePath = shift;
my $patchList = $$patches{$storePath};
return 0 if !defined $patchList;
my $found = 0;
foreach my $patch (@{$patchList}) {
# !!! baseHash might differ
return 1 if $patch->{basePath} eq $basePath;
}
return 0;
}
# Compute the "weighted" number of uses of a path in the build graph.
sub computeUses {
my $narFiles = shift;
my $path = shift;
# Find the deriver of $path.
return 1 unless defined $$narFiles{$path};
my $deriver = @{$$narFiles{$path}}[0]->{deriver};
return 1 unless defined $deriver && $deriver ne "";
# print " DERIVER $deriver\n";
# Optimisation: build the referrers graph from the references
# graph.
my %referrers;
foreach my $q (keys %{$narFiles}) {
my @refs = split " ", @{$$narFiles{$q}}[0]->{references};
foreach my $r (@refs) {
$referrers{$r} = [] unless defined $referrers{$r};
push @{$referrers{$r}}, $q;
}
}
# Determine the shortest path from $deriver to all other reachable
# paths in the `referrers' graph.
my %dist;
$dist{$deriver} = 0;
my @queue = ($deriver);
my $pos = 0;
while ($pos < scalar @queue) {
my $p = $queue[$pos];
$pos++;
foreach my $q (@{$referrers{$p}}) {
if (!defined $dist{$q}) {
$dist{$q} = $dist{$p} + 1;
# print " $q $dist{$q}\n";
push @queue, $q;
}
}
}
my $wuse = 1.0;
foreach my $user (keys %dist) {
next if $user eq $deriver;
# print " $user $dist{$user}\n";
$wuse += 1.0 / 2.0**$dist{$user};
}
# print " XXX $path $wuse\n";
return $wuse;
}
# For each output path in the destination, see if we need to / can
# create a patch.
print "creating patches...\n";
foreach my $p (keys %dstOutPaths) {
# If exactly the same path already exists in the source, skip it.
next if defined $srcOutPaths{$p};
print " $p\n";
# If not, then we should find the paths in the source that are
# `most' likely to be present on a system that wants to install
# this path.
(my $name, my $version) = getNameVersion $p;
my @closest = ();
my $closestVersion;
my $minDist = -1; # actually, larger means closer
# Find all source paths with the same name.
foreach my $q (keys %srcOutPaths) {
(my $name2, my $version2) = getNameVersion $q;
if ($name eq $name2) {
# If the sizes differ too much, then skip. This
# disambiguates between, e.g., a real component and a
# wrapper component (cf. Firefox in Nixpkgs).
my $srcSize = @{$srcNarFiles{$q}}[0]->{size};
my $dstSize = @{$dstNarFiles{$p}}[0]->{size};
my $ratio = $srcSize / $dstSize;
$ratio = 1 / $ratio if $ratio < 1;
# print " SIZE $srcSize $dstSize $ratio $q\n";
if ($ratio >= 3) {
print " SKIPPING $q due to size ratio $ratio ($srcSize $dstSize)\n";
next;
}
# If the numbers of weighted uses differ too much, then
# skip. This disambiguates between, e.g., the bootstrap
# GCC and the final GCC in Nixpkgs.
my $srcUses = computeUses \%srcNarFiles, $q;
my $dstUses = computeUses \%dstNarFiles, $p;
$ratio = $srcUses / $dstUses;
$ratio = 1 / $ratio if $ratio < 1;
print " USE $srcUses $dstUses $ratio $q\n";
# if ($ratio >= 2) {
# print " SKIPPING $q due to use ratio $ratio ($srcUses $dstUses)\n";
# next;
# }
# If there are multiple matching names, include the ones
# with the closest version numbers.
my $dist = versionDiff $version, $version2;
if ($dist > $minDist) {
$minDist = $dist;
@closest = ($q);
$closestVersion = $version2;
} elsif ($dist == $minDist) {
push @closest, $q;
}
}
}
if (scalar(@closest) == 0) {
print " NO BASE: $p\n";
next;
}
foreach my $closest (@closest) {
# Generate a patch between $closest and $p.
print " $p <- $closest\n";
# If the patch already exists, skip it.
if (containsPatch(\%srcPatches, $p, $closest) ||
containsPatch(\%dstPatches, $p, $closest))
{
print " skipping, already exists\n";
next;
}
# next;
my $srcNarBz2 = getNarBz2 \%srcNarFiles, $closest;
my $dstNarBz2 = getNarBz2 \%dstNarFiles, $p;
system("@bunzip2@ < $srcNarBz2 > $tmpDir/A") == 0
or die "cannot unpack $srcNarBz2";
if ((stat "$tmpDir/A")[7] >= $maxNarSize) {
print " skipping, source is too large\n";
next;
}
system("@bunzip2@ < $dstNarBz2 > $tmpDir/B") == 0
or die "cannot unpack $dstNarBz2";
if ((stat "$tmpDir/B")[7] >= $maxNarSize) {
print " skipping, destination is too large\n";
next;
}
system("@libexecdir@/bsdiff $tmpDir/A $tmpDir/B $tmpDir/DIFF") == 0
or die "cannot compute binary diff";
my $baseHash = `@bindir@/nix-hash --flat --type $hashAlgo --base32 $tmpDir/A` or die;
chomp $baseHash;
my $narHash = `@bindir@/nix-hash --flat --type $hashAlgo --base32 $tmpDir/B` or die;
chomp $narHash;
my $narDiffHash = `@bindir@/nix-hash --flat --type $hashAlgo --base32 $tmpDir/DIFF` or die;
chomp $narDiffHash;
my $narDiffSize = (stat "$tmpDir/DIFF")[7];
my $dstNarBz2Size = (stat $dstNarBz2)[7];
print " size $narDiffSize; full size $dstNarBz2Size\n";
if ($narDiffSize >= $dstNarBz2Size) {
print " rejecting; patch bigger than full archive\n";
next;
}
if ($narDiffSize / $dstNarBz2Size >= $maxPatchFraction) {
print " rejecting; patch too large relative to full archive\n";
next;
}
my $finalName =
"$narDiffHash.nar-bsdiff";
if (-e "$patchesDir/$finalName") {
print " not copying, already exists\n";
}
else {
system("cp '$tmpDir/DIFF' '$patchesDir/$finalName.tmp'") == 0
or die "cannot copy diff";
rename("$patchesDir/$finalName.tmp", "$patchesDir/$finalName")
or die "cannot rename $patchesDir/$finalName.tmp";
}
# Add the patch to the manifest.
addPatch \%dstPatches, $p,
{ url => "$patchesURL/$finalName", hash => "$hashAlgo:$narDiffHash"
, size => $narDiffSize, basePath => $closest, baseHash => "$hashAlgo:$baseHash"
, narHash => "$hashAlgo:$narHash", patchType => "nar-bsdiff"
}, 0;
}
}
# Add in any potentially useful patches in the source (namely, those
# patches that produce either paths in the destination or paths that
# can be used as the base for other useful patches).
print "propagating patches...\n";
my $changed;
do {
# !!! we repeat this to reach the transitive closure; inefficient
$changed = 0;
print "loop\n";
my %dstBasePaths;
foreach my $q (keys %dstPatches) {
foreach my $patch (@{$dstPatches{$q}}) {
$dstBasePaths{$patch->{basePath}} = 1;
}
}
foreach my $p (keys %srcPatches) {
my $patchList = $srcPatches{$p};
my $include = 0;
# Is path $p included in the destination? If so, include
# patches that produce it.
$include = 1 if defined $dstNarFiles{$p};
# Is path $p a path that serves as a base for paths in the
# destination? If so, include patches that produce it.
# !!! check baseHash
$include = 1 if defined $dstBasePaths{$p};
if ($include) {
foreach my $patch (@{$patchList}) {
$changed = 1 if addPatch \%dstPatches, $p, $patch;
}
}
}
} while $changed;
# Rewrite the manifest of the destination (with the new patches).
writeManifest "$dstDir/MANIFEST",
\%dstNarFiles, \%dstPatches;

View File

@@ -0,0 +1,2 @@
./gc-releases.pl /data/webserver/dist/*/*/MANIFEST > dead
cat dead | xargs mv --target-directory=/data/webserver/trash/

View File

@@ -0,0 +1,55 @@
#! /usr/bin/perl -w -I. -I..
use strict;
use readmanifest;
use readcache;
# Read the manifests.
my %narFiles;
my %localPaths;
my %patches;
foreach my $manifest (@ARGV) {
print STDERR "loading $manifest\n";
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches, 1) < 3) {
# die "manifest `$manifest' is too old (i.e., for Nix <= 0.7)\n";
}
}
# Find the live archives.
my %usedFiles;
foreach my $narFile (keys %narFiles) {
foreach my $file (@{$narFiles{$narFile}}) {
$file->{url} =~ /\/([^\/]+)$/;
my $basename = $1;
die unless defined $basename;
# print $basename, "\n";
$usedFiles{$basename} = 1;
print STDERR "missing archive `$basename'\n"
unless defined $readcache::archives{$basename};
}
}
foreach my $patch (keys %patches) {
foreach my $file (@{$patches{$patch}}) {
$file->{url} =~ /\/([^\/]+)$/;
my $basename = $1;
die unless defined $basename;
# print $basename, "\n";
$usedFiles{$basename} = 1;
die "missing archive `$basename'"
unless defined $readcache::archives{$basename};
}
}
# Print out the dead archives.
foreach my $archive (keys %readcache::archives) {
next if $archive eq "." || $archive eq "..";
if (!defined $usedFiles{$archive}) {
print $readcache::archives{$archive}, "\n";
}
}

View File

@@ -0,0 +1,21 @@
package readcache;
use strict;
# Read the archive directories.
our %archives;
sub readDir {
my $dir = shift;
opendir(DIR, "$dir") or die "cannot open `$dir': $!";
my @as = readdir DIR;
foreach my $archive (@as) {
$archives{$archive} = "$dir/$archive";
}
closedir DIR;
}
readDir "/data/webserver/dist/nix-cache";
readDir "/data/webserver/dist/test-cache";
readDir "/data/webserver/dist/patches";
print STDERR scalar (keys %archives), "\n";

View File

@@ -0,0 +1,76 @@
#! /usr/bin/perl -w -I. -I..
use strict;
use readmanifest;
use readcache;
my %allNarFiles;
my %allLocalPaths;
my %allPatches;
foreach my $manifest (glob "/data/webserver/dist/*/*/MANIFEST") {
print STDERR "loading $manifest\n";
readManifest($manifest, \%allNarFiles, \%allLocalPaths, \%allPatches, 1);
}
foreach my $manifest (@ARGV) {
print STDERR "shrinking manifest $manifest...\n";
my %narFiles;
my %patches;
if (readManifest($manifest, \%narFiles, \%patches, 1) < 3) {
print STDERR "manifest `$manifest' is too old (i.e., for Nix <= 0.7)\n";
next;
}
my %done;
sub traverse {
my $p = shift;
my $prefix = shift;
print "$prefix$p\n";
my $reachesNAR = 0;
foreach my $patch (@{$patches{$p}}) {
next if defined $done{$patch->{url}};
$done{$patch->{url}} = 1;
$reachesNAR = 1 if traverse ($patch->{basePath}, $prefix . " ");
}
$reachesNAR = 1 if defined $allNarFiles{$p};
print " $prefix$reachesNAR\n";
return $reachesNAR;
}
# foreach my $p (keys %narFiles) {
# traverse ($p, "");
# }
my %newPatches;
foreach my $p (keys %patches) {
my $patchList = $patches{$p};
my @newList;
foreach my $patch (@{$patchList}) {
if (! defined $allNarFiles{$patch->{basePath}} ||
! defined $allNarFiles{$p} )
{
# print "REMOVING PATCH ", $patch->{basePath}, " -> ", $p, "\n";
} else {
# print "KEEPING PATCH ", $patch->{basePath}, " -> ", $p, "\n";
push @newList, $patch;
}
}
$newPatches{$p} = \@newList;
}
writeManifest ($manifest, \%narFiles, \%newPatches);
}

110
scripts/nix-build.in Executable file → Normal file
View File

@@ -1,32 +1,35 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w -I@libexecdir@/nix
use strict;
use Nix::Config;
use Nix::Store;
use File::Temp qw(tempdir);
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
my $addDrvLink = 0;
my $addOutLink = 1;
my $outLink;
my $drvLink;
my $dryRun = 0;
my $verbose = 0;
my $runEnv = 0;
my @instArgs = ();
my @buildArgs = ();
my @exprs = ();
my $shell = $ENV{SHELL} || "/bin/sh";
my $envCommand = "p=\$PATH; source \$stdenv/setup; PATH=\$PATH:\$p; exec $shell";
my @envExclude = ();
END {
foreach my $fn (glob ".nix-build-tmp-*") {
unlink $fn;
}
}
my $tmpDir = tempdir("nix-build.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
sub intHandler {
exit 1;
}
my $outLink = "./result";
my $drvLink = "$tmpDir/derivation";
# Ensure that the $tmpDir is deleted.
$SIG{'INT'} = sub { exit 1 };
$SIG{'INT'} = 'intHandler';
for (my $n = 0; $n < scalar @ARGV; $n++) {
@@ -45,12 +48,7 @@ Flags:
--drv-link NAME: create symlink NAME instead of `derivation'
--no-out-link: do not create the `result' symlink
--out-link / -o NAME: create symlink NAME instead of `result'
--attr / -A ATTR: select a specific attribute from the Nix expression
--run-env: build dependencies of the specified derivation, then start a
shell with the environment of the derivation
--command: command to run with `--run-env'
--exclude: regexp specifying dependencies to be excluded by `--run-env'
--attr ATTR: select a specific attribution from the Nix expression
Any additional flags are passed to `nix-store'.
EOF
@@ -59,11 +57,11 @@ EOF
}
elsif ($arg eq "--add-drv-link") {
$drvLink = "./derivation";
$addDrvLink = 1;
}
elsif ($arg eq "--no-out-link" or $arg eq "--no-link") {
$outLink = "$tmpDir/result";
$addOutLink = 0;
}
elsif ($arg eq "--drv-link") {
@@ -78,10 +76,10 @@ EOF
$outLink = $ARGV[$n];
}
elsif ($arg eq "--attr" or $arg eq "-A" or $arg eq "-I") {
elsif ($arg eq "--attr" or $arg eq "-A") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @instArgs, ($arg, $ARGV[$n]);
push @instArgs, ("--attr", $ARGV[$n]);
}
elsif ($arg eq "--arg" || $arg eq "--argstr") {
@@ -104,7 +102,7 @@ EOF
$n += 2;
}
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type" or $arg eq "--cores") {
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @buildArgs, ($arg, $ARGV[$n]);
@@ -125,27 +123,6 @@ EOF
$verbose = 1;
}
elsif ($arg eq "--quiet") {
push @buildArgs, $arg;
push @instArgs, $arg;
}
elsif ($arg eq "--run-env") {
$runEnv = 1;
}
elsif ($arg eq "--command") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$envCommand = $ARGV[$n];
}
elsif ($arg eq "--exclude") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @envExclude, $ARGV[$n];
}
elsif (substr($arg, 0, 1) eq "-") {
push @buildArgs, $arg;
}
@@ -158,42 +135,29 @@ EOF
@exprs = ("./default.nix") if scalar @exprs == 0;
if (!defined $drvLink) {
$drvLink = "derivation";
$drvLink = ".nix-build-tmp-" . $drvLink if !$addDrvLink;
}
if (!defined $outLink) {
$outLink = "result";
$outLink = ".nix-build-tmp-" . $outLink if !$addOutLink;
}
foreach my $expr (@exprs) {
# Instantiate.
my @drvPaths;
# !!! would prefer the perl 5.8.0 pipe open feature here.
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
my $pid = open(DRVPATHS, "-|") || exec "$binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
if (!close DRVPATHS) {
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
}
if ($runEnv) {
die "$0: --run-env requires a single derivation\n" if scalar @drvPaths != 1;
my $drvPath = readlink $drvPaths[0] or die "cannot read symlink `$drvPaths[0]'";
my $drv = derivationFromPath($drvPath);
# Build or fetch all dependencies of the derivation.
my @inputDrvs = grep { my $x = $_; (grep { $x =~ $_ } @envExclude) == 0 } @{$drv->{inputDrvs}};
system("$Nix::Config::binDir/nix-store -r @buildArgs @inputDrvs @{$drv->{inputSrcs}} > /dev/null") == 0
or die "$0: failed to build all dependencies\n";
# Set the environment.
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} || "/tmp";
foreach (keys %{$drv->{env}}) {
$ENV{$_} = $drv->{env}->{$_};
}
# Run a shell using the derivation's environment. For
# convenience, source $stdenv/setup to setup additional
# environment variables. Also don't lose the current $PATH
# directories.
exec($ENV{SHELL}, "-c", $envCommand);
die;
}
foreach my $drvPath (@drvPaths) {
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
print STDERR "derivation is $target\n" if $verbose;
@@ -201,7 +165,7 @@ foreach my $expr (@exprs) {
# Build.
my @outPaths;
$pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
$pid = open(OUTPATHS, "-|") || exec "$binDir/nix-store", "--add-root", $outLink, "--indirect", "-rv",
@buildArgs, @drvPaths;
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
if (!close OUTPATHS) {

184
scripts/nix-channel.in Executable file → Normal file
View File

@@ -1,151 +1,155 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w
use strict;
use File::Basename;
use File::Path qw(mkpath);
use Nix::Config;
my $manifestDir = $Nix::Config::manifestDir;
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 = "$Nix::Config::stateDir/channel-cache";
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"} or die '$HOME not set\n';
my $home = $ENV{"HOME"};
die '$HOME not set' unless defined $home;
my $channelsList = "$home/.nix-channels";
my $nixDefExpr = "$home/.nix-defexpr";
# Figure out the name of the channels profile.
my $userName = getpwuid($<) or die "cannot figure out user name";
my $profile = "$Nix::Config::stateDir/profiles/per-user/$userName/channels";
mkpath(dirname $profile, 0, 0755);
my %channels;
my @channels;
# Reads the list of channels.
# Reads the list of channels from the file $channelsList;
sub readChannels {
return if (!-f $channelsList);
open CHANNELS, "<$channelsList" or die "cannot open `$channelsList': $!";
while (<CHANNELS>) {
chomp;
next if /^\s*\#/;
my ($url, $name) = split ' ', $_;
$url =~ s/\/*$//; # remove trailing slashes
$name = basename $url unless defined $name;
$channels{$name} = $url;
push @channels, $_;
}
close CHANNELS;
}
# Writes the list of channels.
# Writes the list of channels to the file $channelsList;
sub writeChannels {
open CHANNELS, ">$channelsList" or die "cannot open `$channelsList': $!";
foreach my $name (keys %channels) {
print CHANNELS "$channels{$name} $name\n";
foreach my $url (@channels) {
print CHANNELS "$url\n";
}
close CHANNELS;
}
# Adds a channel.
# Adds a channel to the file $channelsList;
sub addChannel {
my ($url, $name) = @_;
my $url = shift;
readChannels;
$channels{$name} = $url;
foreach my $url2 (@channels) {
return if $url eq $url2;
}
push @channels, $url;
writeChannels;
}
# Remove a channel.
# Remove a channel from the file $channelsList;
sub removeChannel {
my ($name) = @_;
my $url = shift;
my @left = ();
readChannels;
delete $channels{$name};
foreach my $url2 (@channels) {
push @left, $url2 if $url ne $url2;
}
@channels = @left;
writeChannels;
system("$Nix::Config::binDir/nix-env --profile '$profile' -e '$name'") == 0
or die "cannot remove channel `$name'";
}
# Fetch Nix expressions and pull manifests from the subscribed
# Fetch Nix expressions and pull cache manifests from the subscribed
# channels.
sub update {
my @channelNames = @_;
readChannels;
# Create the manifests directory if it doesn't exist.
mkdir $manifestDir, 0755 unless -e $manifestDir;
mkdir "$stateDir/manifests", 0755 unless -e "$stateDir/manifests";
# Do we have write permission to the manifests directory?
die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir;
# 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") {
# Download each channel.
my $exprs = "";
foreach my $name (keys %channels) {
next if scalar @channelNames > 0 && ! grep { $_ eq $name } @{channelNames};
my $url = $channels{$name};
my $origUrl = "$url/MANIFEST";
# 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'";
}
# Check if $url is a redirect. If so, follow it now to ensure
# consistency if the redirection is changed between
# downloading the manifest and the tarball.
my $headers = `$Nix::Config::curl --silent --head '$url'`;
die "$0: unable to check `$url'\n" if $? != 0;
$headers =~ s/\r//g;
$url = $1 if $headers =~ /^Location:\s*(.*)\s*$/m;
# Pull the channel manifest.
$ENV{'NIX_ORIG_URL'} = $origUrl;
system("$Nix::Config::binDir/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
or die "cannot pull manifest from `$url'\n";
# Download the channel tarball.
my $fullURL = "$url/nixexprs.tar.bz2";
print STDERR "downloading Nix expressions from `$fullURL'...\n";
my ($hash, $path) = `PRINT_PATH=1 QUIET=1 $Nix::Config::binDir/nix-prefetch-url '$fullURL'`;
die "cannot fetch `$fullURL'" if $? != 0;
chomp $path;
# If the URL contains a version number, append it to the name
# attribute (so that "nix-env -q" on the channels profile
# shows something useful).
my $cname = $name;
$cname .= $1 if basename($url) =~ /(-\d.*)$/;
$exprs .= "'f: f { name = \"$cname\"; channelName = \"$name\"; src = builtins.storePath \"$path\"; }' ";
}
# Unpack the channel tarballs into the Nix store and install them
# into the channels profile.
print STDERR "unpacking channels...\n";
system("$Nix::Config::binDir/nix-env --profile '$profile' " .
"-f '<nix/unpack-channel.nix>' -i -E $exprs --quiet") == 0
or die "cannot unpack the channels";
# Create a Nix expression that fetches and unpacks the channel Nix
# expressions.
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;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL'`;
die "cannot fetch `$fullURL'" if $? != 0;
chomp $path;
$inputs .= '"' . $channelName . '"' . " " . $path . " ";
}
$inputs .= "]";
# Figure out a name for the GC root.
my $userName = getpwuid($<);
die "who ARE you? go away" unless defined $userName;
my $rootFile = "$rootsDir/per-user/$userName/channels";
# Build the Nix expression.
print "unpacking channel Nix expressions...\n";
my $outPath = `\\
@bindir@/nix-build --out-link '$rootFile' --drv-link '$rootFile'.tmp \\
@datadir@/nix/corepkgs/channels/unpack.nix \\
--argstr system @system@ --arg inputs '$inputs'`
or die "cannot unpack the channels";
chomp $outPath;
unlink "$rootFile.tmp";
# 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($profile, $channelLink) or die "cannot symlink `$channelLink' to `$profile'";
symlink($outPath, $channelLink) or die "cannot symlink `$channelLink' to `$outPath'";
}
sub usageError {
print STDERR <<EOF;
Usage:
nix-channel --add URL [CHANNEL-NAME]
nix-channel --remove CHANNEL-NAME
nix-channel --add URL
nix-channel --remove URL
nix-channel --list
nix-channel --update [CHANNEL-NAME...]
nix-channel --update
EOF
exit 1;
}
@@ -158,35 +162,29 @@ while (scalar @ARGV) {
my $arg = shift @ARGV;
if ($arg eq "--add") {
usageError if scalar @ARGV < 1 || scalar @ARGV > 2;
my $url = shift @ARGV;
my $name = shift @ARGV;
unless (defined $name) {
$name = basename $url;
$name =~ s/-unstable//;
$name =~ s/-stable//;
}
addChannel($url, $name);
usageError if scalar @ARGV != 1;
addChannel (shift @ARGV);
last;
}
if ($arg eq "--remove") {
usageError if scalar @ARGV != 1;
removeChannel(shift @ARGV);
removeChannel (shift @ARGV);
last;
}
if ($arg eq "--list") {
usageError if scalar @ARGV != 0;
readChannels;
foreach my $name (keys %channels) {
print "$name $channels{$name}\n";
foreach my $url (@channels) {
print "$url\n";
}
last;
}
elsif ($arg eq "--update") {
update(@ARGV);
usageError if scalar @ARGV != 0;
update;
last;
}

9
scripts/nix-collect-garbage.in Executable file → Normal file
View File

@@ -1,10 +1,11 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w
use strict;
use Nix::Config;
my $profilesDir = "@localstatedir@/nix/profiles";
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
# Process the command line arguments.
my @args = ();
@@ -35,7 +36,7 @@ sub removeOldGenerations {
$name = $dir . "/" . $name;
if (-l $name && (readlink($name) =~ /link/)) {
print STDERR "removing old generations of profile $name\n";
system("$Nix::Config::binDir/nix-env", "-p", $name, "--delete-generations", "old");
system("$binDir/nix-env", "-p", $name, "--delete-generations", "old");
}
elsif (! -l $name && -d $name) {
removeOldGenerations $name;
@@ -49,4 +50,4 @@ removeOldGenerations $profilesDir if $removeOld;
# Run the actual garbage collector.
exec "$Nix::Config::binDir/nix-store", "--gc", @args;
exec "$binDir/nix-store", "--gc", @args;

110
scripts/nix-copy-closure.in Executable file → Normal file
View File

@@ -1,14 +1,11 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w
use Nix::SSH;
use Nix::Config;
use Nix::Store;
use Nix::CopyClosure;
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
if (scalar @ARGV < 1) {
print STDERR <<EOF
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] [--bzip2] [--xz] PATHS...
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] PATHS...
EOF
;
exit 1;
@@ -17,20 +14,15 @@ EOF
# Get the target host.
my $sshHost;
my @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");
my $sign = 0;
my $compressor = "";
my $decompressor = "";
my $progressViewer = "";
my $compressor = "cat";
my $decompressor = "cat";
my $toMode = 1;
my $includeOutputs = 0;
my $dryRun = 0;
# !!! Copied from nix-pack-closure, should put this in a module.
my @storePaths = ();
@@ -45,29 +37,12 @@ while (@ARGV) {
$compressor = "gzip";
$decompressor = "gunzip";
}
elsif ($arg eq "--bzip2") {
$compressor = "bzip2";
$decompressor = "bunzip2";
}
elsif ($arg eq "--xz") {
$compressor = "xz";
$decompressor = "xz -d";
}
elsif ($arg eq "--from") {
$toMode = 0;
}
elsif ($arg eq "--to") {
$toMode = 1;
}
elsif ($arg eq "--include-outputs") {
$includeOutputs = 1;
}
elsif ($arg eq "--show-progress") {
$progressViewer = "@pv@";
}
elsif ($arg eq "--dry-run") {
$dryRun = 1;
}
elsif (!defined $sshHost) {
$sshHost = $arg;
}
@@ -77,41 +52,80 @@ while (@ARGV) {
}
openSSHConnection $sshHost or die "$0: unable to start SSH\n";
if ($toMode) { # Copy TO the remote machine.
Nix::CopyClosure::copyTo($sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor, $includeOutputs, $dryRun, $sign, $progressViewer);
my @allStorePaths;
# Get the closure of this path.
my $pid = open(READ, "$binDir/nix-store --query --requisites @storePaths|") or die;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
push @allStorePaths, $_;
}
close READ or die "nix-store failed: $?";
# Ask the remote host which paths are invalid.
open(READ, "ssh @sshOpts $sshHost nix-store --check-validity --print-invalid @allStorePaths|");
my @missing = ();
while (<READ>) {
chomp;
print STDERR "target machine needs $_\n";
push @missing, $_;
}
close READ or die;
# Export the store paths and import them on the remote machine.
if (scalar @missing > 0) {
my $extraOpts = "";
$extraOpts .= "--sign" if $sign == 1;
system("nix-store --export $extraOpts @missing | $compressor | ssh @sshOpts $sshHost '$decompressor | nix-store --import'") == 0
or die "copying store paths to remote machine `$sshHost' failed: $?";
}
}
else { # Copy FROM the remote machine.
# Query the closure of the given store paths on the remote
# machine. Paths are assumed to be store paths; there is no
# resolution (following of symlinks).
my $extraOpts = $includeOutputs ? "--include-outputs" : "";
my $pid = open(READ,
"set -f; ssh @sshOpts $sshHost nix-store --query --requisites $extraOpts @storePaths|") or die;
"ssh @sshOpts $sshHost nix-store --query --requisites @storePaths|") or die;
my @allStorePaths;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
push @missing, $_ unless isValidPath($_);
push @allStorePaths, $_;
}
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
# Export the store paths on the remote machine and import them locally.
# What paths are already valid locally?
open(READ, "@bindir@/nix-store --check-validity --print-invalid @allStorePaths|");
my @missing = ();
while (<READ>) {
chomp;
print STDERR "local machine needs $_\n";
push @missing, $_;
}
close READ or die;
# Export the store paths on the remote machine and import them on locally.
if (scalar @missing > 0) {
print STDERR "copying ", scalar @missing, " missing paths from $sshHost...\n";
$compressor = "| $compressor" if $compressor ne "";
$decompressor = "$decompressor |" if $decompressor ne "";
$progressViewer = "$progressViewer |" if $progressViewer ne "";
unless ($dryRun) {
my $extraOpts = $sign ? "--sign" : "";
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $progressViewer $decompressor $Nix::Config::binDir/nix-store --import > /dev/null") == 0
or die "copying store paths from remote machine `$sshHost' failed: $?";
}
my $extraOpts = "";
$extraOpts .= "--sign" if $sign == 1;
system("ssh @sshOpts $sshHost 'nix-store --export $extraOpts @missing | $compressor' | $decompressor | @bindir@/nix-store --import") == 0
or die "copying store paths to remote machine `$sshHost' failed: $?";
}
}

View File

@@ -1,52 +0,0 @@
#! @perl@ -w @perlFlags@
use strict;
use File::Temp qw(tempdir);
use Nix::Manifest;
use Nix::GeneratePatches;
if (scalar @ARGV != 5) {
print STDERR <<EOF;
Usage: nix-generate-patches NAR-DIR PATCH-DIR PATCH-URI OLD-MANIFEST NEW-MANIFEST
This command generates binary patches between NAR files listed in
OLD-MANIFEST and NEW-MANIFEST. The patches are written to the
directory PATCH-DIR, and the prefix PATCH-URI is used to generate URIs
for the patches. The patches are added to NEW-MANIFEST. All NARs are
required to exist in NAR-DIR. Patches are generated between
succeeding versions of packages with the same name.
EOF
exit 1;
}
my $narPath = $ARGV[0];
my $patchesPath = $ARGV[1];
my $patchesURL = $ARGV[2];
my $srcManifest = $ARGV[3];
my $dstManifest = $ARGV[4];
my (%srcNarFiles, %srcLocalPaths, %srcPatches);
readManifest $srcManifest, \%srcNarFiles, \%srcPatches;
my (%dstNarFiles, %dstLocalPaths, %dstPatches);
readManifest $dstManifest, \%dstNarFiles, \%dstPatches;
my $tmpDir = tempdir("nix-generate-patches.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
generatePatches \%srcNarFiles, \%dstNarFiles, \%srcPatches, \%dstPatches,
$narPath, $patchesPath, $patchesURL, $tmpDir;
propagatePatches \%srcPatches, \%dstNarFiles, \%dstPatches;
# Optionally add all new patches to the manifest in $NIX_ALL_PATCHES.
my $allPatchesFile = $ENV{"NIX_ALL_PATCHES"};
if (defined $allPatchesFile) {
my (%dummy, %allPatches);
readManifest("$patchesPath/all-patches", \%dummy, \%allPatches)
if -f $allPatchesFile;
copyPatches \%dstPatches, \%allPatches;
writeManifest($allPatchesFile, {}, \%allPatches, 0);
}
writeManifest $dstManifest, \%dstNarFiles, \%dstPatches;

16
scripts/nix-install-package.in Executable file → Normal file
View File

@@ -1,8 +1,9 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w
use strict;
use File::Temp qw(tempdir);
use Nix::Config;
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
sub usageError {
@@ -60,7 +61,7 @@ if ($interactive && !defined $ENV{"NIX_HAVE_TERMINAL"}) {
$ENV{"NIX_HAVE_TERMINAL"} = "1";
$ENV{"LD_LIBRARY_PATH"} = "";
foreach my $term ("xterm", "konsole", "gnome-terminal", "xterm") {
exec($term, "-e", "$Nix::Config::binDir/nix-install-package", @ARGV);
exec($term, "-e", "$binDir/nix-install-package", @ARGV);
}
die "cannot execute `xterm'";
}
@@ -123,20 +124,17 @@ if ($interactive) {
# Store the manifest in the temporary directory so that we don't
# pollute /nix/var/nix/manifests. This also requires that we don't
# use the Nix daemon (because otherwise download-using-manifests won't
# see our NIX_MANIFESTS_DIRS environment variable).
# pollute /nix/var/nix/manifests.
$ENV{NIX_MANIFESTS_DIR} = $tmpDir;
$ENV{NIX_REMOTE} = "";
print "\nPulling manifests...\n";
system("$Nix::Config::binDir/nix-pull", $manifestURL) == 0
system("$binDir/nix-pull", $manifestURL) == 0
or barf "nix-pull failed: $?";
print "\nInstalling package...\n";
system("$Nix::Config::binDir/nix-env", "--install", $outPath, "--force-name", $drvName, @extraNixEnvArgs) == 0
system("$binDir/nix-env", "--install", $outPath, "--force-name", $drvName, @extraNixEnvArgs) == 0
or barf "nix-env failed: $?";

229
scripts/nix-prefetch-url.in Executable file → Normal file
View File

@@ -1,128 +1,159 @@
#! @perl@ -w @perlFlags@
#! @shell@ -e
use strict;
use File::Basename;
use File::Temp qw(tempdir);
use File::stat;
use Nix::Store;
use Nix::Config;
url=$1
expHash=$2
my $url = shift;
my $expHash = shift;
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256";
my $cacheDir = $ENV{'NIX_DOWNLOAD_CACHE'};
# needed to make it work on NixOS
export PATH=$PATH:@coreutils@
if (!defined $url || $url eq "") {
print STDERR <<EOF
Usage: nix-prefetch-url URL [EXPECTED-HASH]
EOF
;
exit 1;
}
hashType=$NIX_HASH_ALGO
if test -z "$hashType"; then
hashType=sha256
fi
sub writeFile {
my ($fn, $s) = @_;
open TMP, ">$fn" or die;
print TMP "$s" or die;
close TMP or die;
}
hashFormat=
if test "$hashType" != "md5"; then
hashFormat=--base32
fi
sub readFile {
local $/ = undef;
my ($fn) = @_;
open TMP, "<$fn" or die;
my $s = <TMP>;
close TMP or die;
return $s;
}
if test -z "$url"; then
echo "syntax: nix-prefetch-url URL [EXPECTED-HASH]" >&2
exit 1
fi
my $tmpDir = tempdir("nix-prefetch-url.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
name=$(basename "$url")
if test -z "$name"; then echo "invalid url"; exit 1; fi
# Hack to support the mirror:// scheme from Nixpkgs.
if ($url =~ /^mirror:\/\//) {
system("$Nix::Config::binDir/nix-build '<nixpkgs>' -A resolveMirrorURLs --argstr url '$url' -o $tmpDir/urls > /dev/null") == 0
or die "$0: nix-build failed; maybe \$NIX_PATH is not set properly\n";
my @expanded = split ' ', readFile("$tmpDir/urls");
die "$0: cannot resolve $url" unless scalar @expanded > 0;
print STDERR "$url expands to $expanded[0]\n";
$url = $expanded[0];
}
# Handle escaped characters in the URI. `+', `=' and `?' are the only
# characters that are valid in Nix store path names but have a special
# meaning in URIs.
my $name = basename $url;
die "cannot figure out file name for $url\n" if $name eq "";
$name =~ s/%2b/+/g;
$name =~ s/%3d/=/g;
$name =~ s/%3f/?/g;
my $finalPath;
my $hash;
# If the hash was given, a file with that hash may already be in the
# store.
if (defined $expHash) {
$finalPath = makeFixedOutputPath(0, $hashType, $expHash, $name);
if (isValidPath($finalPath)) { $hash = $expHash; } else { $finalPath = undef; }
if test -n "$expHash"; then
finalPath=$(@bindir@/nix-store --print-fixed-path "$hashType" "$expHash" "$name")
if ! @bindir@/nix-store --check-validity "$finalPath" 2> /dev/null; then
finalPath=
fi
hash=$expHash
fi
mkTempDir() {
if test -n "$tmpPath"; then return; fi
local i=0
while true; do
if test -z "$TMPDIR"; then TMPDIR=/tmp; fi
tmpPath=$TMPDIR/nix-prefetch-url-$$-$i
if mkdir "$tmpPath"; then break; fi
# !!! to bad we can't check for ENOENT in mkdir, so this check
# is slightly racy (it bombs out if somebody just removed
# $tmpPath...).
if ! test -e "$tmpPath"; then exit 1; fi
i=$((i + 1))
done
trap removeTempDir EXIT SIGINT SIGQUIT
}
removeTempDir() {
if test -n "$tmpPath"; then
rm -rf "$tmpPath" || true
fi
}
doDownload() {
@curl@ $cacheFlags --fail --location --max-redirs 20 --disable-epsv \
--cookie-jar $tmpPath/cookies "$url" -o $tmpFile
}
# Hack to support the mirror:// scheme from Nixpkgs.
if test "${url:0:9}" = "mirror://"; then
if test -z "$NIXPKGS_ALL"; then
echo "Resolving mirror:// URLs requires Nixpkgs. Please point \$NIXPKGS_ALL at a Nixpkgs tree." >&2
exit 1
fi
mkTempDir
nix-build "$NIXPKGS_ALL" -A resolveMirrorURLs --argstr url "$url" -o $tmpPath/urls > /dev/null
expanded=($(cat $tmpPath/urls))
if test "${#expanded[*]}" = 0; then
echo "$0: cannot resolve $url." >&2
exit 1
fi
echo "$url expands to ${expanded[*]} (using ${expanded[0]})" >&2
url="${expanded[0]}"
fi
# If we don't know the hash or a file with that hash doesn't exist,
# download the file and add it to the store.
if (!defined $finalPath) {
if test -z "$finalPath"; then
mkTempDir
tmpFile=$tmpPath/$name
my $tmpFile = "$tmpDir/$name";
# 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.
my ($cachedTimestampFN, $cachedHashFN, @cacheFlags);
if (defined $cacheDir) {
my $urlHash = hashString("sha256", 1, $url);
writeFile "$cacheDir/$urlHash.url", $url;
$cachedHashFN = "$cacheDir/$urlHash.$hashType";
$cachedTimestampFN = "$cacheDir/$urlHash.stamp";
@cacheFlags = ("--time-cond", $cachedTimestampFN) if -f $cachedHashFN && -f $cachedTimestampFN;
}
# Perform the download.
my @curlFlags = ("curl", $url, "-o", $tmpFile, "--fail", "--location", "--max-redirs", "20", "--disable-epsv", "--cookie-jar", "$tmpDir/cookies", "--remote-time", (split " ", ($ENV{NIX_CURL_FLAGS} || "")));
(system $Nix::Config::curl @curlFlags, @cacheFlags) == 0 or die "$0: download of $url failed\n";
if test -n "$NIX_DOWNLOAD_CACHE"; then
echo -n "$url" > $tmpPath/url
urlHash=$(@bindir@/nix-hash --type sha256 --base32 --flat $tmpPath/url)
echo "$url" > "$NIX_DOWNLOAD_CACHE/$urlHash.url"
cachedHashFN="$NIX_DOWNLOAD_CACHE/$urlHash.$hashType"
cachedTimestampFN="$NIX_DOWNLOAD_CACHE/$urlHash.stamp"
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
if (defined $cacheDir && ! -e $tmpFile) {
# Perform the download.
doDownload
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 = readFile $cachedHashFN or die;
$finalPath = makeFixedOutputPath(0, $hashType, $hash, $name);
unless (isValidPath $finalPath) {
print STDERR "cached contents of $url disappeared, redownloading...\n";
$finalPath = undef;
(system $Nix::Config::curl @curlFlags) == 0 or die "$0: download of $url failed\n";
}
}
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
if test -z "$finalPath"; then
if (!defined $finalPath) {
# Compute the hash.
$hash = hashFile($hashType, $hashType ne "md5", $tmpFile);
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"; then
echo $hash > $cachedHashFN
touch -r $tmpFile $cachedTimestampFN
fi
if (defined $cacheDir) {
writeFile $cachedHashFN, $hash;
my $st = stat($tmpFile) or die;
open STAMP, ">$cachedTimestampFN" or die; close STAMP;
utime($st->atime, $st->mtime, $cachedTimestampFN) or die;
}
# Add the downloaded file to the Nix store.
$finalPath = addToStore($tmpFile, 0, $hashType);
}
finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)
die "$0: hash mismatch for $url\n" if defined $expHash && $expHash ne $hash;
}
if test -n "$expHash" -a "$expHash" != "$hash"; then
echo "hash mismatch for URL \`$url'" >&2
exit 1
fi
fi
fi
print STDERR "path is $finalPath\n" unless $ENV{'QUIET'};
print "$hash\n";
print "$finalPath\n" if $ENV{'PRINT_PATH'};
if ! test -n "$QUIET"; then echo "path is $finalPath" >&2; fi
echo $hash
if test -n "$PRINT_PATH"; then
echo $finalPath
fi

69
scripts/nix-pull.in Executable file → Normal file
View File

@@ -1,14 +1,17 @@
#! @perl@ -w @perlFlags@
#! @perl@ -w -I@libexecdir@/nix
use strict;
use File::Temp qw(tempdir);
use Nix::Config;
use Nix::Manifest;
use readmanifest;
my $tmpDir = tempdir("nix-pull.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
my $manifestDir = $Nix::Config::manifestDir;
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
my $libexecDir = ($ENV{"NIX_LIBEXEC_DIR"} or "@libexecdir@");
my $storeDir = ($ENV{"NIX_STORE_DIR"} or "@storedir@");
my $stateDir = ($ENV{"NIX_STATE_DIR"} or "@localstatedir@/nix");
my $manifestDir = ($ENV{"NIX_MANIFESTS_DIR"} or "$stateDir/manifests");
# Prevent access problems in shared-stored installations.
@@ -21,21 +24,18 @@ if (! -e $manifestDir) {
}
# Make sure that the manifests directory is scanned for GC roots.
my $gcRootsDir = "$Nix::Config::stateDir/gcroots";
my $manifestDirLink = "$gcRootsDir/manifests";
if (! -l $manifestDirLink) {
symlink($manifestDir, $manifestDirLink) or die "cannot create symlink `$manifestDirLink'";
}
# Process the URLs specified on the command line.
my %narFiles;
my %localPaths;
my %patches;
my $skipWrongStore = 0;
sub downloadFile {
my $url = shift;
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($dummy, $path) = `$Nix::Config::binDir/nix-prefetch-url '$url'`;
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;
@@ -49,32 +49,53 @@ sub processURL {
my $manifest;
my $origUrl = $ENV{'NIX_ORIG_URL'} || $url;
# First see if a bzipped manifest is available.
if (system("$Nix::Config::curl --fail --silent --location --head '$url'.bz2 > /dev/null") == 0) {
if (system("@curl@ --fail --silent --head '$url'.bz2 > /dev/null") == 0) {
print "fetching list of Nix archives at `$url.bz2'...\n";
$manifest = downloadFile "$url.bz2";
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 "fetching list of Nix archives at `$url'...\n";
print "obtaining list of Nix archives at `$url'...\n";
$manifest = downloadFile $url;
}
my $version = readManifest($manifest, \%narFiles, \%localPaths, \%patches);
die "`$url' is not a manifest or it is too old (i.e., for Nix <= 0.7)\n" if $version < 3;
die "manifest `$url' is too new\n" if $version >= 5;
if ($skipWrongStore) {
foreach my $path (keys %narFiles) {
if (substr($path, 0, length($storeDir) + 1) ne "$storeDir/") {
print STDERR "warning: manifest `$url' assumes a Nix store at a different location than $storeDir, skipping...\n";
exit 0;
}
}
}
my $baseName = "unnamed";
if ($url =~ /\/([^\/]+)\/[^\/]+$/) { # get the forelast component
$baseName = $1;
}
my $hash = `$Nix::Config::binDir/nix-hash --flat '$manifest'`
my $hash = `$binDir/nix-hash --flat '$manifest'`
or die "cannot hash `$manifest'";
chomp $hash;
my $urlFile = "$manifestDir/$baseName-$hash.url";
open URL, ">$urlFile" or die "cannot create `$urlFile'";
print URL $origUrl;
print URL "$url";
close URL;
my $finalPath = "$manifestDir/$baseName-$hash.nixmanifest";
@@ -91,7 +112,7 @@ sub processURL {
my $url2 = <URL>;
chomp $url2;
close URL;
next unless $origUrl eq $url2;
next unless $url eq $url2;
my $base = $urlFile2; $base =~ s/.url$//;
unlink "${base}.url";
unlink "${base}.nixmanifest";
@@ -101,12 +122,12 @@ sub processURL {
while (@ARGV) {
my $url = shift @ARGV;
if ($url eq "--skip-wrong-store") {
# No-op, no longer supported.
$skipWrongStore = 1;
} else {
processURL $url;
}
}
# Update the cache.
updateManifestDB();
my $size = scalar (keys %narFiles) + scalar (keys %localPaths);
print "$size store paths in manifest\n";

Some files were not shown because too many files have changed in this diff Show More