Compare commits

..

3 Commits

Author SHA1 Message Date
Eelco Dolstra
dce54ac74f * Tagged Nix 0.12. 2008-11-20 21:51:39 +00:00
Eelco Dolstra
713d97efc0 2008-11-20 20:57:15 +00:00
Eelco Dolstra
44cfd237d9 2008-11-20 20:56:27 +00:00
127 changed files with 1936 additions and 3019 deletions

View File

@@ -1,11 +1,17 @@
SUBDIRS = externals src scripts corepkgs doc misc tests
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
nix.conf.example NEWS version
svn-revision nix.conf.example NEWS
include ./substitute.mk
nix.spec: nix.spec.in
rpm: nix.spec dist
rpm $(EXTRA_RPM_FLAGS) -ta $(distdir).tar.gz
relname:
echo -n $(distdir) > relname
install-data-local: init-state
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
$(INSTALL_DATA) $(srcdir)/nix.conf.example $(DESTDIR)$(sysconfdir)/nix
@@ -38,11 +44,13 @@ init-state:
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests
else
init-state:
endif
NEWS:
$(MAKE) -C doc/manual NEWS.txt
svn-revision:
svnversion . > svn-revision
all-local: NEWS
NEWS: doc/manual/NEWS.txt
cp $(srcdir)/doc/manual/NEWS.txt NEWS

View File

@@ -1,8 +1,21 @@
AC_INIT(nix, m4_esyscmd([echo -n $(cat ./version)$VERSION_SUFFIX]))
AC_INIT(nix, 0.12)
AC_CONFIG_SRCDIR(README)
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE([dist-bzip2 foreign])
# Change to `1' to produce a `stable' release (i.e., the `preREVISION'
# suffix is not added).
STABLE=1
# Put the revision number in the version.
if test "$STABLE" != "1"; then
if REVISION=`test -d $srcdir/.svn && svnversion -n $srcdir 2> /dev/null`; then
VERSION=${VERSION}pre${REVISION}
elif REVISION=`cat $srcdir/svn-revision 2> /dev/null`; then
VERSION=${VERSION}pre${REVISION}
fi
fi
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [Nix version.])
AC_CANONICAL_HOST
@@ -50,30 +63,14 @@ AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
test "$localstatedir" = '${prefix}/var' && localstatedir=/nix/var
# Whether to produce a statically linked binary. On Cygwin, this is
# the default: dynamically linking against the ATerm DLL does work,
# except that it requires the ATerm "lib" directory to be in $PATH, as
# Windows doesn't have anything like an RPATH embedded in executable.
# Since this is kind of annoying, we use static libraries for now.
AC_ARG_ENABLE(static-nix, AC_HELP_STRING([--enable-static-nix],
[produce statically linked binaries]),
static_nix=$enableval, static_nix=no)
if test "$sys_name" = cygwin; then
static_nix=yes
fi
if test "$static_nix" = yes; then
AC_DISABLE_SHARED
AC_ENABLE_STATIC
fi
# Windows-specific stuff.
if test "$sys_name" = "cygwin"; then
# We cannot delete open files.
AC_DEFINE(CANNOT_DELETE_OPEN_FILES, 1, [Whether it is impossible to delete open files.])
# Shared libraries don't work, currently.
AC_DISABLE_SHARED
AC_ENABLE_STATIC
fi
@@ -106,8 +103,6 @@ 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([sys/mount.h], [], [],
[#ifdef HAVE_SYS_PARAM_H
@@ -116,17 +111,12 @@ AC_CHECK_HEADERS([sys/mount.h], [], [],
])
# Check for <locale>.
# Check for <locale>
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS([locale], [], [], [])
AC_LANG_POP(C++)
# Check whether we have the personality() syscall, which allows us to
# do i686-linux builds on x86_64-linux machines.
AC_CHECK_HEADERS([sys/personality.h])
AC_DEFUN([NEED_PROG],
[
AC_PATH_PROG($1, $2)
@@ -282,7 +272,6 @@ AC_CHECK_FUNCS([setresuid setreuid lchown])
# Nice to have, but not essential.
AC_CHECK_FUNCS([strsignal])
AC_CHECK_FUNCS([posix_fallocate])
# This is needed if ATerm, Berkeley DB or bzip2 are static libraries,
@@ -292,14 +281,6 @@ if test "$(uname)" = "Darwin"; then
fi
if test "$static_nix" = yes; then
# `-all-static' has to be added at the end of configure, because
# the C compiler doesn't know about -all-static (it's filtered out
# by libtool, but configure doesn't use libtool).
LDFLAGS="-all-static $LDFLAGS"
fi
AM_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile
externals/Makefile

View File

@@ -8,15 +8,9 @@ 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

View File

@@ -79,14 +79,10 @@ all-local: manual.html NEWS.html NEWS.txt
install-data-local: manual.html
$(INSTALL) -d $(DESTDIR)$(docdir)/manual
$(INSTALL_DATA) manual.html $(DESTDIR)$(docdir)/manual
ln -sf manual.html $(DESTDIR)$(docdir)/manual/index.html
$(INSTALL_DATA) style.css $(DESTDIR)$(docdir)/manual
cp -r images $(DESTDIR)$(docdir)/manual/images
$(INSTALL) -d $(DESTDIR)$(docdir)/manual/figures
$(INSTALL_DATA) $(FIGURES) $(DESTDIR)$(docdir)/manual/figures
$(INSTALL) -d $(DESTDIR)$(docdir)/release-notes
$(INSTALL_DATA) NEWS.html $(DESTDIR)$(docdir)/release-notes/index.html
$(INSTALL_DATA) style.css $(DESTDIR)$(docdir)/release-notes/
images:
mkdir images

View File

@@ -77,8 +77,18 @@ attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames
if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
This allows a Nix expression to fall back gracefully on older Nix
installations that dont have the desired built-in
function.</para></listitem>
installations that dont have the desired built-in function.
However, in that case you should not write
<programlisting>
if builtins ? getEnv then __getEnv "PATH" else ""</programlisting>
This Nix expression will trigger an “undefined variable” error on
older Nix versions since <function>__getEnv</function> doesnt
exist. <literal>builtins.getEnv</literal>, on the other hand, is
safe since <literal>builtins</literal> always exists and attribute
selection is lazy, so its only performed if the test
succeeds.</para></listitem>
</varlistentry>
@@ -354,36 +364,6 @@ x: x + 456</programlisting>
</varlistentry>
<varlistentry><term><function>builtins.isString</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a string, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isInt</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a int, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isBool</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a bool, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>isNull</function>
<replaceable>e</replaceable></term>

View File

@@ -151,12 +151,12 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<para>On the basis of this information, and whatever persistent
state the build hook keeps about other machines and their current
load, it has to decide what to do with the build. It should print
out on standard error one of the following responses (terminated by
a newline, <literal>"\n"</literal>):
out on file descriptor 3 one of the following responses (terminated
by a newline, <literal>"\n"</literal>):
<variablelist>
<varlistentry><term><literal># decline</literal></term>
<varlistentry><term><literal>decline</literal></term>
<listitem><para>The build hook is not willing or able to perform
the build; the calling Nix process should do the build itself,
@@ -164,7 +164,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
</varlistentry>
<varlistentry><term><literal># postpone</literal></term>
<varlistentry><term><literal>postpone</literal></term>
<listitem><para>The build hook cannot perform the build now, but
can do so in the future (e.g., because all available build slots
@@ -174,7 +174,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
</varlistentry>
<varlistentry><term><literal># accept</literal></term>
<varlistentry><term><literal>accept</literal></term>
<listitem><para>The build hook has accepted the
build.</para></listitem>
@@ -185,12 +185,37 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
</para>
<para>After sending <literal># accept</literal>, the hook should
read one line from standard input, which will be the string
<literal>okay</literal>. It can then proceed with the build.
Before sending <literal>okay</literal>, Nix will store in the hooks
current directory a number of text files that contain information
about the derivation:
<para>If the build hook accepts the build, it is possible that it is
no longer necessary to do the build because some other process has
performed the build in the meantime. To prevent races, the hook
must read from file descriptor 4 a single line that tells it whether
to continue:
<variablelist>
<varlistentry><term><literal>cancel</literal></term>
<listitem><para>The build has already been done, so the hook
should exit.</para></listitem>
</varlistentry>
<varlistentry><term><literal>okay</literal></term>
<listitem><para>The hook should proceed with the build. At this
point, the calling Nix process has acquired locks on the output
path, so no other Nix process will perform the
build.</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>If the hook has been told to proceed, Nix will store in the
hooks current directory a number of text files that contain
information about the derivation:
<variablelist>
@@ -230,9 +255,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
<para>The hook should copy the inputs to the remote machine,
register the validity of the inputs, perform the remote build, and
copy the outputs back to the local machine. An exit code other than
<literal>0</literal> indicates that the hook has failed. An exit
code equal to 100 means that the remote build failed (as opposed to,
e.g., a network error).</para>
<literal>0</literal> indicates that the hook has failed.</para>
</listitem>

View File

@@ -110,7 +110,7 @@
</appendix>
<xi:include href="troubleshooting.xml" />
<!-- <xi:include href="bugs.xml" /> -->
<xi:include href="bugs.xml" />
<xi:include href="glossary.xml" />
<appendix>

View File

@@ -24,7 +24,6 @@
<arg><option>--fallback</option></arg>
<arg><option>--readonly-mode</option></arg>
<arg><option>--log-type</option> <replaceable>type</replaceable></arg>
<arg><option>--show-trace</option></arg>
<sbr />
</nop>

View File

@@ -251,14 +251,14 @@
<programlisting>
{ # The system (e.g., `i686-linux') for which to build the packages.
system ? builtins.currentSystem
system ? __currentSystem
<replaceable>...</replaceable>
}: <replaceable>...</replaceable></programlisting>
So if you call this Nix expression (e.g., when you do
<literal>nix-env -i <replaceable>pkgname</replaceable></literal>),
the function will be called automatically using the value <link
linkend='builtin-currentSystem'><literal>builtins.currentSystem</literal></link>
linkend='builtin-currentSystem'><literal>__currentSystem</literal></link>
for the <literal>system</literal> argument. You can override this
using <option>--arg</option>, e.g., <literal>nix-env -i
<replaceable>pkgname</replaceable> --arg system
@@ -305,14 +305,6 @@
</varlistentry>
<varlistentry><term><option>--show-trace</option></term>
<listitem><para>Causes Nix to print out a stack trace in case of Nix
expression evaluation errors.</para></listitem>
</varlistentry>
</variablelist>

View File

@@ -6,93 +6,6 @@
<!--==================================================================-->
<section xml:id="ssec-relnotes-0.13"><title>Release 0.13 (April NN,
2009)</title>
<para>This is primarily a bug fix release. It has some new
features:</para>
<itemizedlist>
<listitem>
<para>Syntactic sugar for writing nested attribute sets. Instead of
<programlisting>
{
foo = {
bar = 123;
xyzzy = true;
};
a = { b = { c = "d"; }; };
}
</programlisting>
you can write
<programlisting>
{
foo.bar = 123;
foo.xyzzy = true;
a.b.c = "d";
}
</programlisting>
This is useful, for instance, in NixOS configuration files.</para>
</listitem>
<listitem>
<para>Support for Nix channels generated by Hydra, the Nix-based
continuous build system. (Hydra generates NAR archives on the
fly, so the size and hash of these archives isnt known in
advance.)</para>
</listitem>
<listitem>
<para>Support <literal>i686-linux</literal> builds directly on
<literal>x86_64-linux</literal> Nix installations. This is
implemented using the <function>personality()</function> syscall,
which causes <command>uname</command> to return
<literal>i686</literal> in child processes.</para>
</listitem>
<listitem>
<para>Various improvements to the <literal>chroot</literal>
support. Building in a <literal>chroot</literal> works quite well
now.</para>
</listitem>
<listitem>
<para>Nix no longer blocks if it tries to build a path and another
process is already building the same path. Instead it tries to
build another buildable path first. This improves
parallelism.</para>
</listitem>
<listitem>
<para>Support for large (> 4 GiB) files in NAR archives.</para>
</listitem>
<listitem>
<para>Various (performance) improvements to the remote build
mechanism.</para>
</listitem>
<listitem>
<para>New primops: <varname>builtins.addErrorContext</varname> (to
add a string to stack traces — useful for debugging),
<varname>builtins.isBool</varname>,
<varname>builtins.isString</varname>,
<varname>builtins.isInt</varname>.</para>
</listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-0.12"><title>Release 0.12 (November 20,

View File

@@ -1432,7 +1432,7 @@ command-line argument. See <xref linkend='sec-standard-environment'
inputs.</para></listitem>
<listitem><para>After the build, Nix sets the last-modified
timestamp on all files in the build result to 1 (00:00:01 1/1/1970
timestamp on all files in the build result to 0 (00:00:00 1/1/1970
UTC), sets the group to the default group, and sets the mode of the
file to 0444 or 0555 (i.e., read-only, with execute permission
enabled if the file was originally executable). Note that possible

View File

@@ -48,7 +48,7 @@ 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 " http://losser.st-lab.cs.uu.nl/~eelco/dist/aterm-2.4.2-fixes-r2.tar.bz2"
@echo "and place it in the externals/ directory."
false

View File

@@ -76,10 +76,10 @@ The hook `nix-mode-hook' is run when Nix mode is started.
("\\<baseNameOf\\>" . font-lock-builtin-face)
("\\<toString\\>" . font-lock-builtin-face)
("\\<isNull\\>" . font-lock-builtin-face)
("\\<\\([a-zA-Z_][a-zA-Z0-9_']*\\)[ \t]*="
(1 font-lock-variable-name-face nil nil))
("[a-zA-Z][a-zA-Z0-9\\+-\\.]*:[a-zA-Z0-9%/\\?:@&=\\+\\$,_\\.!~\\*'-]+"
. font-lock-constant-face)
("\\<\\([a-zA-Z_][a-zA-Z0-9_'\.]*\\)[ \t]*="
(1 font-lock-variable-name-face nil nil))
("[a-zA-Z0-9._\\+-]*\\(/[a-zA-Z0-9._\\+-]+\\)+"
. font-lock-constant-face)
))

View File

@@ -21,14 +21,12 @@ syn match nixFuncArg "\zs\w\+\ze\s*:"
syn region nixStringParam start=+\${+ end=+}+
syn region nixMultiLineComment start=+/\*+ skip=+\\"+ end=+\*/+
syn match nixEndOfLineComment "#.*$"
syn region nixStringIndented start=+''+ skip=+'''\|''${\|"+ end=+''+ contains=nixStringParam
syn region nixString start=+"+ skip=+\\"+ end=+"+ contains=nixStringParam
syn region nixString start=+"+ skip=+\\"+ end=+"+ contains=nixStringParam
hi def link nixKeyword Keyword
hi def link nixConditional Conditional
hi def link nixBrace Special
hi def link nixString String
hi def link nixStringIndented String
hi def link nixBuiltin Special
hi def link nixStringParam Macro
hi def link nixMultiLineComment Comment

View File

@@ -154,17 +154,21 @@
#build-chroot-dirs = /dev /dev/pts /proc
### Option `build-cache-failure'
### Option `system'
#
# If this option is enabled, Nix will do negative caching; that is, it
# will remember failed builds, and won't attempt to try to build them
# again if you ask for it. Negative caching is disabled by default
# because Nix cannot distinguish between permanent build errors (e.g.,
# a syntax error in a source file) and transient build errors (e.g., a
# full disk), as they both cause the builder to return a non-zero exit
# code. You can clear the cache by doing `rm -f
# /nix/var/nix/db/failed/*'.
# This option specifies the canonical Nix system name of the current
# installation, such as `i686-linux' or `powerpc-darwin'. Nix can
# only build derivations whose `system' attribute equals the value
# specified here. In general, it never makes sense to modify this
# value from its default, since you can use it to `lie' about the
# platform you are building on (e.g., perform a Mac OS build on a
# Linux machine; the result would obviously be wrong). It only makes
# sense if the Nix binaries can run on multiple platforms, e.g.,
# `universal binaries' that run on `powerpc-darwin' and `i686-darwin'.
#
# It defaults to the canonical Nix system name detected by `configure'
# at build time.
#
# Example:
# build-cache-failure = true
#build-cache-failure = false
# system = i686-darwin
#system =

View File

@@ -1,196 +0,0 @@
{ nixpkgs ? ../nixpkgs }:
let
jobs = rec {
tarball =
{ nix ? {outPath = ./.; rev = 1234;}
, officialRelease ? false
}:
with import nixpkgs {};
releaseTools.sourceTarball {
name = "nix-tarball";
version = builtins.readFile ./version;
src = nix;
inherit officialRelease;
buildInputs = [curl bison flex2533 perl libxml2 libxslt w3m bzip2 jing_tools tetex dblatex];
configureFlags = ''
--with-docbook-rng=${docbook5}/xml/rng/docbook
--with-docbook-xsl=${docbook5_xsl}/xml/xsl/docbook
--with-xml-flags=--nonet
'';
# Include the BDB, ATerm and Bzip2 tarballs in the distribution.
preConfigure = ''
stripHash ${db45.src}
# Remove unnecessary stuff from the Berkeley DB tarball.
( mkdir bdb-temp
cd bdb-temp
tar xfz ${db45.src}
cd *
rm -rf docs test tcl perl libdb_java java rpc_server build_vxworks \
examples_java examples_c examples_cxx dist/tags
mkdir test
touch test/include.tcl
cd ..
tar cvfz ../externals/$strippedName *
)
stripHash ${aterm242fixes.src}
cp -pv ${aterm242fixes.src} externals/$strippedName
stripHash ${bzip2.src}
cp -pv ${bzip2.src} externals/$strippedName
'';
preDist = ''
make -C doc/manual install prefix=$out
make -C doc/manual manual.pdf prefix=$out
cp doc/manual/manual.pdf $out/manual.pdf
echo "doc manual $out/share/doc/nix/manual" >> $out/nix-support/hydra-build-products
echo "doc-pdf manual $out/manual.pdf" >> $out/nix-support/hydra-build-products
echo "doc release-notes $out/share/doc/nix/release-notes" >> $out/nix-support/hydra-build-products
'';
};
build =
{ tarball ? jobs.tarball {}
, system ? "i686-linux"
}:
with import nixpkgs {inherit system;};
releaseTools.nixBuild {
name = "nix";
src = tarball;
buildInputs = [curl perl bzip2 openssl];
configureFlags = ''
--disable-init-state
--with-bdb=${db45} --with-aterm=${aterm242fixes} --with-bzip2=${bzip2}
'';
};
static =
{ tarball ? jobs.tarball {}
, system ? "i686-linux"
}:
with import nixpkgs {inherit system;};
releaseTools.binaryTarball {
name = "nix-static-tarball";
src = tarball;
buildInputs = [curl perl bzip2];
configureFlags = ''
--disable-init-state
--disable-old-db-compat --with-aterm=${aterm242fixes} --with-bzip2=${bzip2}
--enable-static-nix
'';
};
coverage =
{ tarball ? jobs.tarball {}
}:
with import nixpkgs {};
releaseTools.coverageAnalysis {
name = "nix-build";
src = tarball;
buildInputs = [
curl perl bzip2 openssl
# These are for "make check" only:
graphviz libxml2 libxslt
];
configureFlags = ''
--disable-init-state --disable-shared
--with-bdb=${db45} --with-aterm=${aterm242fixes} --with-bzip2=${bzip2}
'';
lcovFilter = ["*/boost/*" "*-tab.*"];
# We call `dot', and even though we just use it to
# syntax-check generated dot files, it still requires some
# fonts. So provide those.
FONTCONFIG_FILE = texFunctions.fontsConf;
};
rpm_fedora5i386 = makeRPM_i686 (diskImages: diskImages.fedora5i386) 20;
rpm_fedora9i386 = makeRPM_i686 (diskImages: diskImages.fedora9i386) 50;
rpm_fedora9x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora9x86_64) 50;
rpm_fedora10i386 = makeRPM_i686 (diskImages: diskImages.fedora10i386) 40;
rpm_fedora10x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora10x86_64) 40;
rpm_opensuse103i386 = makeRPM_i686 (diskImages: diskImages.opensuse103i386) 40;
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) 30;
deb_debian50x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian50x86_64) 30;
deb_ubuntu804i386 = makeDeb_i686 (diskImages: diskImages.ubuntu804i386) 50;
deb_ubuntu804x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu804x86_64) 50;
deb_ubuntu810i386 = makeDeb_i686 (diskImages: diskImages.ubuntu810i386) 40;
deb_ubuntu810x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu810x86_64) 40;
};
makeRPM_i686 = makeRPM "i686-linux";
makeRPM_x86_64 = makeRPM "x86_64-linux";
makeRPM =
system: diskImageFun: prio:
{ tarball ? jobs.tarball {}
}:
with import nixpkgs {inherit system;};
releaseTools.rpmBuild rec {
name = "nix-rpm-${diskImage.name}";
src = tarball;
diskImage = diskImageFun vmTools.diskImages;
memSize = 1024;
meta = { schedulingPriority = toString prio; };
};
makeDeb_i686 = makeDeb "i686-linux";
makeDeb_x86_64 = makeDeb "x86_64-linux";
makeDeb =
system: diskImageFun: prio:
{ tarball ? jobs.tarball {}
}:
with import nixpkgs {inherit system;};
releaseTools.debBuild {
name = "nix-deb";
src = tarball;
diskImage = diskImageFun vmTools.diskImages;
memSize = 1024;
meta = { schedulingPriority = toString prio; };
configureFlags = "--sysconfdir=/etc";
};
in jobs

View File

@@ -3,7 +3,6 @@
use strict;
use Fcntl ':flock';
use English '-no_match_vars';
use IO::Handle;
# General operation:
#
@@ -24,12 +23,16 @@ use IO::Handle;
my $loadIncreased = 0;
my ($amWilling, $localSystem, $neededSystem, $drvPath, $maxSilentTime) = @ARGV;
$maxSilentTime = 0 unless defined $maxSilentTime;
my $amWilling = shift @ARGV;
my $localSystem = shift @ARGV;
my $neededSystem = shift @ARGV;
my $drvPath = shift @ARGV;
sub sendReply {
my $reply = shift;
print STDERR "# $reply\n";
open OUT, ">&3" or die;
print OUT "$reply\n";
close OUT;
}
sub decline {
@@ -44,11 +47,15 @@ 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);
# Decline if the local system can do the build.
decline if $amWilling && ($localSystem eq $neededSystem);
# Otherwise find a willing remote machine.
my @machines;
my %machines;
my %systemTypes;
my %sshKeys;
my %maxJobs;
my %curJobs;
@@ -60,12 +67,10 @@ while (<CONF>) {
s/\#.*$//g;
next if /^\s*$/;
/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s*$/ or die;
push @machines,
{ hostName => $1
, systemType => $2
, sshKeys => $3
, maxJobs => $4
};
$machines{$1} = "";
$systemTypes{$1} = $2;
$sshKeys{$1} = $3;
$maxJobs{$1} = $4;
}
close CONF;
@@ -80,26 +85,21 @@ flock(MAINLOCK, LOCK_EX) or die;
# Find a suitable system.
my $rightType = 0;
my $machine;
my $slotLock;
LOOP: foreach my $cur (@machines) {
if ($neededSystem eq $cur->{systemType}
|| ($neededSystem eq "i686-linux" && $cur->{systemType} eq "x86_64-linux"))
{
LOOP: foreach my $cur (keys %machines) {
if ($neededSystem eq $systemTypes{$cur}) {
$rightType = 1;
# We have a machine of the right type. Try to get a lock on
# one of the machine's lock files.
my $slot = 0;
while ($slot < $cur->{maxJobs}) {
my $slotLockFn = "$currentLoad/" . $cur->{systemType} . "-" . $cur->{hostName} . "-$slot";
$slotLock = new IO::Handle;
open $slotLock, ">>$slotLockFn" or die;
if (flock($slotLock, LOCK_EX | LOCK_NB)) {
utime undef, undef, $slotLock;
while ($slot < $maxJobs{$cur}) {
my $slotLock = "$currentLoad/$cur-$slot";
open SLOTLOCK, ">>$slotLock" or die;
if (flock(SLOTLOCK, LOCK_EX | LOCK_NB)) {
$machine = $cur;
last LOOP;
}
close $slotLock;
}
close SLOTLOCK;
$slot++;
}
}
@@ -108,11 +108,9 @@ LOOP: foreach my $cur (@machines) {
close MAINLOCK;
# Didn't find one? Then decline or postpone.
# Didn't find one?
if (!defined $machine) {
# 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) {
if ($rightType) {
sendReply "postpone";
exit 0;
} else {
@@ -122,8 +120,11 @@ if (!defined $machine) {
# Yes we did, accept.
sendReply "accept";
my $x = <STDIN>;
open IN, "<&4" or die;
my $x = <IN>;
chomp $x;
#print "got $x\n";
close IN;
if ($x ne "okay") {
exit 0;
@@ -131,8 +132,7 @@ if ($x ne "okay") {
# Do the actual job.
my $hostName = $machine->{hostName};
print STDERR "building `$drvPath' on `$hostName'\n";
print "BUILDING REMOTE: $drvPath on $machine\n";
# Make sure that we don't get any SSH passphrase or host key popups -
# if there is any problem it should fail, not do something
@@ -141,10 +141,10 @@ $ENV{"DISPLAY"} = "";
$ENV{"SSH_PASSWORD_FILE="} = "";
$ENV{"SSH_ASKPASS="} = "";
my $sshOpts = "-i " . $machine->{sshKeys} . " -x";
my $sshOpts = "-i $sshKeys{$machine} -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
# have exactly the same right as when we do. This causes the
# Microsoft C compiler to fail with certain flags:
#
# http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=99676
@@ -154,8 +154,8 @@ my $sshOpts = "-i " . $machine->{sshKeys} . " -x";
# 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};
if ($sshKeys{$machine} =~ /^password:/) {
my $passwordFile = $sshKeys{$machine};
$passwordFile =~ s/^password://;
$sshOpts = "ssh -x";
$ENV{"SSH_PASSWORD_FILE"} = $passwordFile;
@@ -173,40 +173,36 @@ $inputs =~ s/\n/ /g;
my $outputs = `cat outputs`; die if ($? != 0);
$outputs =~ s/\n/ /g;
print "copying inputs...\n";
print "COPYING INPUTS...\n";
my $maybeSign = "";
$maybeSign = "--sign" if -e "/nix/etc/nix/signing-key.sec";
system("NIX_SSHOPTS=\"$sshOpts\" @bindir@/nix-copy-closure --gzip $hostName $maybeSign $drvPath $inputs") == 0
or die "cannot copy inputs to $hostName: $?";
system("NIX_SSHOPTS=\"$sshOpts\" nix-copy-closure $machine $maybeSign $drvPath $inputs") == 0
or die "cannot copy inputs to $machine: $?";
print "building...\n";
print "BUILDING...\n";
my $buildFlags = "--max-silent-time $maxSilentTime";
system("ssh $sshOpts $machine 'nix-store -rvvK $drvPath'") == 0
or die "remote build on $machine failed: $?";
# `-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 -K $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 "REMOTE BUILD DONE: $drvPath on $machine\n";
foreach my $output (split '\n', $outputs) {
my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0;
system("ssh $sshOpts $hostName 'nix-store --export $maybeSignRemote $output | gzip' | gunzip | @bindir@/nix-store --import > /dev/null") == 0
or die "cannot copy $output from $hostName: $?";
system("ssh $sshOpts $machine 'nix-store --export $maybeSignRemote $output' > dump") == 0
or die "cannot copy $output from $machine: $?";
# This doesn't work yet, since the caller has a lock on the output
# path. We should move towards lock-free invocation of build
# hooks and substitutes.
#system("nix-store --import < dump") == 0
# or die "cannot import $output: $?";
# Hack: skip the first 8 bytes (the nix-store --export next
# archive marker). The archive follows.
system("(dd bs=1 count=8 of=/dev/null && cat) < dump | nix-store --restore $output") == 0
or die "cannot restore $output: $?";
}

View File

@@ -9,7 +9,7 @@ my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
STDOUT->autoflush(1);
my $manifestDir = ($ENV{"NIX_MANIFESTS_DIR"} or "@localstatedir@/nix/manifests");
my $manifestDir = "@localstatedir@/nix/manifests";
my $logFile = "@localstatedir@/log/nix/downloads";
@@ -19,15 +19,10 @@ my %localPaths;
my %patches;
for my $manifest (glob "$manifestDir/*.nixmanifest") {
my $version = readManifest($manifest, \%narFiles, \%localPaths, \%patches);
if ($version < 3) {
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
exit 1;
}
if ($version >= 10) {
print STDERR "manifest `$manifest' is too new; please delete it or upgrade Nix\n";
exit 1;
}
}
@@ -190,11 +185,13 @@ while ($queueFront < scalar @queue) {
$format = "" if $baseHashAlgo eq "md5";
my $hash = `$binDir/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`;
chomp $hash;
# print " MY HASH is $hash\n";
if ($hash ne $baseHash) {
print LOGFILE "$$ rejecting $patch->{basePath}\n";
next;
}
}
# print " PATCH from $patch->{basePath}\n";
addToQueue $patch->{basePath};
addEdge $patch->{basePath}, $u, $patch->{size}, "patch", $patch;
}
@@ -202,12 +199,10 @@ while ($queueFront < scalar @queue) {
# 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;
# print " NAR from $narFile->{url}\n";
addEdge "start", $u, $narFile->{size}, "narfile", $narFile;
if ($u eq $targetPath) {
my $size = $narFile->{size} || -1;
print LOGFILE "$$ full-download-would-be $size\n";
print LOGFILE "$$ full-download-would-be $narFile->{size}\n";
}
}
@@ -233,6 +228,8 @@ while (scalar @todo > 0) {
my $u_ = $graph{$u};
# print "IN $u $u_->{d}\n";
foreach my $edge (@{$u_->{edges}}) {
my $v_ = $graph{$edge->{end}};
if ($v_->{d} > $u_->{d} + $edge->{weight}) {
@@ -240,6 +237,7 @@ while (scalar @todo > 0) {
# Store the edge; to edge->start is actually the
# predecessor.
$v_->{pred} = $edge;
# print " RELAX $edge->{end} $v_->{d}\n";
}
}
}
@@ -261,18 +259,20 @@ while ($cur ne "start") {
my $curStep = 1;
my $maxStep = scalar @path;
sub downloadFile {
my $url = shift;
sub downloadFile {
my $url = shift;
my ($hashAlgo, $hash) = parseHash(shift);
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `$binDir/nix-prefetch-url '$url'`;
$ENV{"NIX_HASH_ALGO"} = $hashAlgo;
my ($hash2, $path) = `$binDir/nix-prefetch-url '$url' '$hash'`;
die "download of `$url' failed" unless $? == 0;
chomp $hash2;
chomp $path;
die "hash mismatch, expected $hash, got $hash2" if $hash ne $hash2;
return $path;
}
my $finalNarHash;
while (scalar @path > 0) {
my $edge = pop @path;
my $u = $edge->{start};
@@ -302,7 +302,7 @@ while (scalar @path > 0) {
# Download the patch.
print " downloading patch...\n";
my $patchPath = downloadFile "$patch->{url}";
my $patchPath = downloadFile "$patch->{url}", "$patch->{hash}";
# Apply the patch to the NAR archive produced in step 1 (for
# the already present path) or a later step (for patch sequences).
@@ -320,20 +320,17 @@ while (scalar @path > 0) {
system("$binDir/nix-store --restore $v < $tmpNar2") == 0
or die "cannot unpack $tmpNar2 into `$v'";
}
$finalNarHash = $patch->{narHash};
}
elsif ($edge->{type} eq "narfile") {
my $narFile = $edge->{info};
print "downloading `$narFile->{url}' into `$v'\n";
my $size = $narFile->{size} || -1;
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
print LOGFILE "$$ narfile $narFile->{url} $narFile->{size} $v\n";
# Download the archive.
print " downloading archive...\n";
my $narFilePath = downloadFile "$narFile->{url}";
my $narFilePath = downloadFile "$narFile->{url}", "$narFile->{hash}";
if ($curStep < $maxStep) {
# The archive will be used a base to a patch.
@@ -345,36 +342,11 @@ while (scalar @path > 0) {
system("@bunzip2@ < '$narFilePath' | $binDir/nix-store --restore '$v'") == 0
or die "cannot unpack `$narFilePath' into `$v'";
}
$finalNarHash = $narFile->{narHash};
}
$curStep++;
}
# Make sure that the hash declared in the manifest matches what we
# downloaded and unpacked.
if (defined $finalNarHash) {
my ($hashAlgo, $hash) = parseHash $finalNarHash;
# The hash in the manifest can be either in base-16 or base-32.
# Handle both.
my $extraFlag =
($hashAlgo eq "sha256" && length($hash) != 64)
? "--base32" : "";
my $hash2 = `@bindir@/nix-hash --type $hashAlgo $extraFlag $targetPath`
or die "cannot compute hash of path `$targetPath'";
chomp $hash2;
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2"
if $hash ne $hash2;
} else {
die "cannot check integrity of the downloaded path since its hash is not known";
}
print LOGFILE "$$ success\n";
close LOGFILE;

View File

@@ -77,7 +77,7 @@ EOF
elsif ($arg eq "--attr" or $arg eq "-A") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
die "$0: `--attr' requires an argument\n" unless $n < scalar @ARGV;
push @instArgs, ("--attr", $ARGV[$n]);
}
@@ -87,21 +87,7 @@ EOF
$n += 2;
}
elsif ($arg eq "--log-type") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @instArgs, ($arg, $ARGV[$n]);
push @buildArgs, ($arg, $ARGV[$n]);
}
elsif ($arg eq "--option") {
die "$0: `$arg' requires two arguments\n" unless $n + 2 < scalar @ARGV;
push @instArgs, ($arg, $ARGV[$n + 1], $ARGV[$n + 2]);
push @buildArgs, ($arg, $ARGV[$n + 1], $ARGV[$n + 2]);
$n += 2;
}
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type") {
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @buildArgs, ($arg, $ARGV[$n]);
@@ -142,10 +128,7 @@ foreach my $expr (@exprs) {
# !!! would prefer the perl 5.8.0 pipe open feature here.
my $pid = open(DRVPATHS, "-|") || exec "$binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
if (!close DRVPATHS) {
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
}
close DRVPATHS or exit 1;
foreach my $drvPath (@drvPaths) {
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
@@ -157,10 +140,7 @@ foreach my $expr (@exprs) {
$pid = open(OUTPATHS, "-|") || exec "$binDir/nix-store", "--add-root", $outLink, "--indirect", "-rv",
@buildArgs, @drvPaths;
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
if (!close OUTPATHS) {
die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
}
close OUTPATHS or exit 1;
next if $dryRun;

View File

@@ -125,13 +125,15 @@ sub update {
my $rootFile = "$rootsDir/per-user/$userName/channels";
# Build the Nix expression.
# Instantiate 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";
my $storeExpr = `@bindir@/nix-instantiate --add-root '$rootFile'.tmp @datadir@/nix/corepkgs/channels/unpack.nix --argstr system @system@ --arg inputs '$inputs'`
or die "cannot instantiate Nix expression";
chomp $storeExpr;
# Build the resulting derivation.
my $outPath = `@bindir@/nix-store --add-root '$rootFile' -r '$storeExpr'`
or die "cannot realise store expression";
chomp $outPath;
unlink "$rootFile.tmp";

View File

@@ -55,17 +55,29 @@ while (@ARGV) {
if ($toMode) { # Copy TO the remote machine.
my @allStorePaths;
my %storePathsSeen;
# Get the closure of this path.
my $pid = open(READ, "$binDir/nix-store --query --requisites @storePaths|") or die;
foreach my $storePath (@storePaths) {
# $arg might be a symlink to the store, so resolve it.
my $storePath2 = (`$binDir/nix-store --query --resolve '$storePath'`
or die "cannot resolve `$storePath'");
chomp $storePath2;
# Get the closure of this path.
my $pid = open(READ,
"$binDir/nix-store --query --requisites '$storePath2'|") or die;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
push @allStorePaths, $_;
}
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
if (!defined $storePathsSeen{$_}) {
push @allStorePaths, $_;
$storePathsSeen{$_} = 1;
}
}
close READ or die "nix-store failed: $?";
close READ or die "nix-store failed: $?";
}
# Ask the remote host which paths are invalid.
@@ -99,11 +111,15 @@ else { # Copy FROM the remote machine.
"ssh @sshOpts $sshHost nix-store --query --requisites @storePaths|") or die;
my @allStorePaths;
my %storePathsSeen;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
push @allStorePaths, $_;
if (!defined $storePathsSeen{$_}) {
push @allStorePaths, $_;
$storePathsSeen{$_} = 1;
}
}
close READ or die "nix-store on remote machine `$sshHost' failed: $?";

View File

@@ -12,8 +12,7 @@ needed_path="?$QUERY_STRING"
needed_path="${needed_path#*[?&]needed_path=}"
needed_path="${needed_path%%&*}"
#needed_path="$(echo $needed_path | ./unhttp)"
needed_path="${needed_path//%2B/+}"
needed_path="${needed_path//%3D/=}"
needed_path="$(echo $needed_path | sed -e 's/%2B/+/g; s/%3D/=/g')"
echo needed_path: "$needed_path" >&2

View File

@@ -123,11 +123,6 @@ if ($interactive) {
}
# Store the manifest in the temporary directory so that we don't
# pollute /nix/var/nix/manifests.
$ENV{NIX_MANIFESTS_DIR} = $tmpDir;
print "\nPulling manifests...\n";
system("$binDir/nix-pull", $manifestURL) == 0
or barf "nix-pull failed: $?";

View File

@@ -60,7 +60,7 @@ removeTempDir() {
doDownload() {
@curl@ $cacheFlags --fail --location --max-redirs 20 --disable-epsv \
@curl@ $cacheFlags --fail -# --location --max-redirs 20 --disable-epsv \
--cookie-jar $tmpPath/cookies "$url" -o $tmpFile
}

View File

@@ -8,10 +8,15 @@ my $tmpDir = tempdir("nix-pull.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
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");
my $libexecDir = $ENV{"NIX_LIBEXEC_DIR"};
$libexecDir = "@libexecdir@" unless defined $libexecDir;
my $stateDir = $ENV{"NIX_STATE_DIR"};
$stateDir = "@localstatedir@/nix" unless defined $stateDir;
my $storeDir = $ENV{"NIX_STORE_DIR"};
$storeDir = "@storedir@" unless defined $storeDir;
# Prevent access problems in shared-stored installations.
@@ -63,11 +68,10 @@ sub processURL {
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 (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
die "`$url' is not manifest or it is too old (i.e., for Nix <= 0.7)\n";
}
if ($skipWrongStore) {
foreach my $path (keys %narFiles) {
@@ -87,7 +91,7 @@ sub processURL {
or die "cannot hash `$manifest'";
chomp $hash;
my $finalPath = "$manifestDir/$baseName-$hash.nixmanifest";
my $finalPath = "$stateDir/manifests/$baseName-$hash.nixmanifest";
system("@coreutils@/ln", "-sfn", "$manifest", "$finalPath") == 0
or die "cannot link `$finalPath to `$manifest'";

View File

@@ -128,7 +128,7 @@ while (<READ>) {
close READ or die "nix-instantiate failed: $?";
# Build the derivations.
# Realise the store expressions.
print STDERR "creating archives...\n";
my @narPaths;
@@ -140,7 +140,12 @@ while (scalar @tmp > 0) {
my @tmp2 = @tmp[0..$n - 1];
@tmp = @tmp[$n..scalar @tmp - 1];
my $pid = open(READ, "$binDir/nix-store --realise @tmp2|")
# Note: we disable build hooks because of the impure path
# reference (see above). Even if that is fixed, using a hook
# probably wouldn't make that much sense; pumping lots of data
# around just to compress them won't gain that much.
$ENV{"NIX_BUILD_HOOK"} = "";
my $pid = open(READ, "$binDir/nix-store --no-build-hook --realise @tmp2|")
or die "cannot run nix-store";
while (<READ>) {
chomp;

View File

@@ -2,7 +2,10 @@ use strict;
sub addPatch {
my ($patches, $storePath, $patch) = @_;
my $patches = shift;
my $storePath = shift;
my $patch = shift;
my $allowConflicts = shift;
$$patches{$storePath} = []
unless defined $$patches{$storePath};
@@ -11,9 +14,15 @@ sub addPatch {
my $found = 0;
foreach my $patch2 (@{$patchList}) {
$found = 1 if
$patch2->{url} eq $patch->{url} &&
$patch2->{basePath} eq $patch->{basePath};
if ($patch2->{url} eq $patch->{url}) {
if ($patch2->{hash} eq $patch->{hash}) {
$found = 1 if ($patch2->{basePath} eq $patch->{basePath});
} else {
die "conflicting hashes for URL $patch->{url}, " .
"namely $patch2->{hash} and $patch->{hash}"
unless $allowConflicts;
}
}
}
push @{$patchList}, $patch if !$found;
@@ -23,7 +32,12 @@ sub addPatch {
sub readManifest {
my ($manifest, $narFiles, $localPaths, $patches) = @_;
my $manifest = shift;
my $narFiles = shift;
my $localPaths = shift;
my $patches = shift;
my $allowConflicts = shift;
$allowConflicts = 0 unless defined $allowConflicts;
open MANIFEST, "<$manifest"
or die "cannot open `$manifest': $!";
@@ -84,7 +98,15 @@ sub readManifest {
my $found = 0;
foreach my $narFile (@{$narFileList}) {
$found = 1 if $narFile->{url} eq $url;
if ($narFile->{url} eq $url) {
if ($narFile->{hash} eq $hash) {
$found = 1;
} else {
die "conflicting hashes for URL $url, " .
"namely $narFile->{hash} and $hash"
unless $allowConflicts;
}
}
}
if (!$found) {
push @{$narFileList},
@@ -102,7 +124,7 @@ sub readManifest {
, basePath => $basePath, baseHash => $baseHash
, narHash => $narHash, patchType => $patchType
, hashAlgo => $hashAlgo
};
}, $allowConflicts;
}
elsif ($type eq "localPath") {
@@ -149,8 +171,12 @@ sub readManifest {
}
sub writeManifest {
my ($manifest, $narFiles, $patches) = @_;
sub writeManifest
{
my $manifest = shift;
my $narFiles = shift;
my $patches = shift;
my $copySources = shift;
open MANIFEST, ">$manifest.tmp"; # !!! check exclusive
@@ -164,9 +190,9 @@ sub writeManifest {
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 " Hash: $narFile->{hash}\n";
print MANIFEST " NarHash: $narFile->{narHash}\n";
print MANIFEST " Size: $narFile->{size}\n" if defined $narFile->{size};
print MANIFEST " Size: $narFile->{size}\n";
print MANIFEST " References: $narFile->{references}\n"
if defined $narFile->{references} && $narFile->{references} ne "";
print MANIFEST " Deriver: $narFile->{deriver}\n"

View File

@@ -1,6 +1,6 @@
SUBDIRS = format
nobase_pkginclude_HEADERS = assert.hpp checked_delete.hpp format.hpp \
pkginclude_HEADERS = assert.hpp checked_delete.hpp format.hpp \
shared_ptr.hpp weak_ptr.hpp throw_exception.hpp \
enable_shared_from_this.hpp \
detail/shared_count.hpp detail/workaround.hpp

View File

@@ -3,12 +3,12 @@ pkglib_LTLIBRARIES = libexpr.la
libexpr_la_SOURCES = \
nixexpr.cc eval.cc primops.cc lexer-tab.cc parser-tab.cc \
get-drvs.cc attr-path.cc expr-to-xml.cc common-opts.cc \
names.cc normal-forms.cc
names.cc
pkginclude_HEADERS = \
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
get-drvs.hh attr-path.hh expr-to-xml.hh common-opts.hh \
names.hh nixexpr-ast.hh
names.hh
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
../boost/format/libformat.la

View File

@@ -16,23 +16,13 @@ namespace nix {
EvalState::EvalState()
: sessionNormalForms(32768), normalForms(32768), primOps(128)
: normalForms(32768), primOps(128)
{
nrEvaluated = nrCached = nrDepthAfterReset = 0;
nrEvaluated = nrCached = 0;
initNixExprHelpers();
addPrimOps();
allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == "";
safeCache = true;
loadNormalForms();
}
EvalState::~EvalState()
{
saveNormalForms();
}
@@ -476,10 +466,8 @@ LocalNoInline(Expr evalVar(EvalState & state, ATerm name))
if (arity == 0)
/* !!! backtrace for primop call */
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
else {
state.safeCache = false;
else
return makePrimOp(arity, fun, ATempty);
}
}
@@ -505,7 +493,6 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
for (ATermIterator i(args); i; ++i)
args2[--arity] = *i;
/* !!! backtrace for primop call */
state.safeCache = true;
return ((PrimOp) ATgetBlobData(funBlob))
(state, args2);
} else
@@ -657,48 +644,6 @@ LocalNoInline(Expr evalOpConcat(EvalState & state, Expr e1, Expr e2))
}
/* Implementation of the `==' and `!=' operators. */
LocalNoInline(bool areEqual(EvalState & state, Expr e1, Expr e2))
{
e1 = evalExpr(state, e1);
e2 = evalExpr(state, e2);
/* We cannot test functions/primops for equality, and we currently
don't support testing equality between attribute sets or lists
- that would have to be a deep equality test to be sound. */
AFun sym1 = ATgetAFun(e1);
AFun sym2 = ATgetAFun(e2);
if (sym1 != sym2) return false;
/* Functions are incomparable. */
if (sym1 == symFunction || sym1 == symPrimOp) return false;
if (!state.allowUnsafeEquality && sym1 == symAttrs)
throw EvalError("comparison of attribute sets is not implemented");
/* !!! This allows comparisons of infinite data structures to
succeed, such as `let x = [x]; in x == x'. This is
undesirable, since equivalent (?) terms such as `let x = [x]; y
= [y]; in x == y' don't terminate. */
if (e1 == e2) return true;
if (sym1 == symList) {
ATermList es1; matchList(e1, es1);
ATermList es2; matchList(e2, es2);
if (ATgetLength(es1) != ATgetLength(es2)) return false;
ATermIterator i(es1), j(es2);
while (*i) {
if (!areEqual(state, *i, *j)) return false;
++i; ++j;
}
return true;
}
return false;
}
static char * deepestStack = (char *) -1; /* for measuring stack usage */
@@ -762,10 +707,12 @@ Expr evalExpr2(EvalState & state, Expr e)
However, we don't want to make (==) strict, because that would
make operations like `big_derivation == null' very slow (unless
we were to evaluate them side-by-side). */
if (matchOpEq(e, e1, e2)) return makeBool(areEqual(state, e1, e2));
if (matchOpNEq(e, e1, e2)) return makeBool(!areEqual(state, e1, e2));
if (matchOpEq(e, e1, e2))
return makeBool(evalExpr(state, e1) == evalExpr(state, e2));
if (matchOpNEq(e, e1, e2))
return makeBool(evalExpr(state, e1) != evalExpr(state, e2));
/* Negation. */
if (matchOpNot(e, e1))
return makeBool(!evalBool(state, e1));
@@ -813,19 +760,11 @@ Expr evalExpr(EvalState & state, Expr e)
format("evaluating expression: %1%") % e);
#endif
const unsigned int hugeEvalExpr = 100;
unsigned int nrEvaluated = state.nrEvaluated++;
state.nrDepthAfterReset++;
state.nrEvaluated++;
/* Consult the memo table to quickly get the normal form of
previously evaluated expressions. */
Expr nf = state.normalForms.get(e);
if (nf) {
state.nrCached++;
return nf;
}
nf = state.sessionNormalForms.get(e);
if (nf) {
if (nf == makeBlackHole())
throwEvalError("infinite recursion encountered");
@@ -834,25 +773,14 @@ Expr evalExpr(EvalState & state, Expr e)
}
/* Otherwise, evaluate and memoize. */
state.sessionNormalForms.set(e, makeBlackHole());
state.normalForms.set(e, makeBlackHole());
try {
nf = evalExpr2(state, e);
} catch (Error & err) {
state.sessionNormalForms.remove(e);
state.normalForms.remove(e);
throw;
}
// session independent condition
if (state.nrDepthAfterReset && state.safeCache &&
// heuristic condition
state.nrEvaluated - nrEvaluated > hugeEvalExpr) {
state.sessionNormalForms.remove(e);
state.normalForms.set(e, nf);
state.nrDepthAfterReset--;
} else {
state.sessionNormalForms.set(e, nf);
}
state.normalForms.set(e, nf);
return nf;
}
@@ -860,7 +788,6 @@ Expr evalExpr(EvalState & state, Expr e)
Expr evalFile(EvalState & state, const Path & path)
{
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
state.nrDepthAfterReset = 0;
Expr e = parseExprFromFile(state, path);
try {
return evalExpr(state, e);
@@ -932,13 +859,11 @@ void printEvalStats(EvalState & state)
char x;
bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0";
printMsg(showStats ? lvlInfo : lvlDebug,
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space, %6% cached normal reduction, %7% session dependent reduction.")
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space")
% state.nrEvaluated % state.nrCached
% ((float) state.nrCached / (float) state.nrEvaluated * 100)
% AT_calcAllocatedSize()
% (&x - deepestStack)
% state.normalForms.size()
% state.sessionNormalForms.size());
% (&x - deepestStack));
if (showStats)
printATermMapStats();
}

View File

@@ -30,7 +30,6 @@ typedef Expr (* PrimOp) (EvalState &, const ATermVector & args);
struct EvalState
{
ATermMap normalForms;
ATermMap sessionNormalForms;
ATermMap primOps;
DrvRoots drvRoots;
DrvHashes drvHashes; /* normalised derivation hashes */
@@ -38,19 +37,12 @@ struct EvalState
unsigned int nrEvaluated;
unsigned int nrCached;
unsigned int nrDepthAfterReset;
bool allowUnsafeEquality;
bool safeCache;
EvalState();
~EvalState();
void addPrimOps();
void addPrimOp(const string & name,
unsigned int arity, PrimOp primOp);
void loadNormalForms();
void saveNormalForms();
};

View File

@@ -50,55 +50,31 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
Expr e = evalExpr(state, i->value);
string s;
PathSet context;
MetaValue value;
int n;
ATermList es;
if (matchStr(e, s, context)) {
value.type = MetaValue::tpString;
value.stringValue = s;
meta[aterm2String(i->key)] = value;
} else if (matchInt(e, n)) {
value.type = MetaValue::tpInt;
value.intValue = n;
meta[aterm2String(i->key)] = value;
} else if (matchList(e, es)) {
value.type = MetaValue::tpStrings;
for (ATermIterator j(es); j; ++j)
value.stringValues.push_back(evalStringNoCtx(state, *j));
meta[aterm2String(i->key)] = value;
}
if (matchStr(e, s, context))
meta[aterm2String(i->key)] = s;
/* For future compatibility, ignore attribute values that are
not strings. */
}
return meta;
}
MetaValue DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
string DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
{
/* !!! evaluates all meta attributes => inefficient */
return queryMetaInfo(state)[name];
MetaInfo meta = queryMetaInfo(state);
MetaInfo::iterator i = meta.find(name);
return i == meta.end() ? "" : i->second;
}
void DrvInfo::setMetaInfo(const MetaInfo & meta)
{
ATermMap metaAttrs;
foreach (MetaInfo::const_iterator, i, meta) {
Expr e;
switch (i->second.type) {
case MetaValue::tpInt: e = makeInt(i->second.intValue); break;
case MetaValue::tpString: e = makeStr(i->second.stringValue); break;
case MetaValue::tpStrings: {
ATermList es = ATempty;
foreach (Strings::const_iterator, j, i->second.stringValues)
es = ATinsert(es, makeStr(*j));
e = makeList(ATreverse(es));
break;
}
default: abort();
}
metaAttrs.set(toATerm(i->first), makeAttrRHS(e, makeNoPos()));
}
for (MetaInfo::const_iterator i = meta.begin(); i != meta.end(); ++i)
metaAttrs.set(toATerm(i->first),
makeAttrRHS(makeStr(i->second), makeNoPos()));
attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
}

View File

@@ -12,16 +12,7 @@
namespace nix {
struct MetaValue
{
enum { tpNone, tpString, tpStrings, tpInt } type;
string stringValue;
Strings stringValues;
int intValue;
};
typedef std::map<string, MetaValue> MetaInfo;
typedef std::map<string, string> MetaInfo;
struct DrvInfo
@@ -43,7 +34,7 @@ public:
string queryDrvPath(EvalState & state) const;
string queryOutPath(EvalState & state) const;
MetaInfo queryMetaInfo(EvalState & state) const;
MetaValue queryMetaInfo(EvalState & state, const string & name) const;
string queryMetaInfo(EvalState & state, const string & name) const;
void setDrvPath(const string & s)
{

View File

@@ -70,7 +70,6 @@ Bool | ATermBool | Expr |
Null | | Expr |
Bind | string Expr Pos | ATerm |
BindAttrPath | ATermList Expr Pos | ATerm | # desugared during parsing
Bind | string Expr | ATerm | ObsoleteBind
Inherit | Expr ATermList Pos | ATerm |

View File

@@ -19,7 +19,7 @@ string showPos(ATerm pos)
if (matchNoPos(pos)) return "undefined position";
if (!matchPos(pos, path, line, column))
throw badTerm("position expected", pos);
return (format("`%1%:%2%:%3%'") % aterm2String(path) % line % column).str();
return (format("`%1%', line %2%") % aterm2String(path) % line).str();
}

View File

@@ -11,7 +11,6 @@ namespace nix {
MakeError(EvalError, Error)
MakeError(ParseError, Error)
MakeError(AssertionError, EvalError)
MakeError(ThrownError, AssertionError)
MakeError(Abort, EvalError)

View File

@@ -1,64 +0,0 @@
#include "eval.hh"
#include "util.hh"
#include "globals.hh"
#include "serialise.hh"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
namespace nix {
void EvalState::loadNormalForms()
{
// nixCacheFile = getEnv("NIX_CACHE_FILE", nixStateDir + "/reduce-cache");
nixCacheFile = getEnv("NIX_CACHE_FILE");
string loadFlag = getEnv("NIX_CACHE_FILE_LOAD", "1");
if(nixCacheFile == "" || loadFlag == "")
return;
if(!pathExists(nixCacheFile))
return;
printMsg(lvlInfo, format("Load cache: ..."));
try {
int fd = open(nixCacheFile.c_str(), O_RDONLY);
if (fd == -1)
throw SysError(format("opening file `%1%'") % nixCacheFile);
AutoCloseFD auto_fd = fd;
FdSource source = fd;
normalForms = readATermMap(source);
} catch (Error & e) {
e.addPrefix(format("Cannot load cached reduce operations from %1%:\n") % nixCacheFile);
throw;
}
printMsg(lvlInfo, format("Load cache: end"));
}
void EvalState::saveNormalForms()
{
string saveFlag = getEnv("NIX_CACHE_FILE_SAVE", "");
if(nixCacheFile == "" || saveFlag == "")
return;
printMsg(lvlInfo, format("Save cache: ..."));
try {
int fd = open(nixCacheFile.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
if (fd == -1)
throw SysError(format("opening file `%1%'") % nixCacheFile);
AutoCloseFD auto_fd = fd;
FdSink sink = fd;
writeATermMap(normalForms, sink);
} catch (Error & e) {
e.addPrefix(format("Cannot save cached reduce operations to %1%:\n") % nixCacheFile);
throw;
}
printMsg(lvlInfo, format("Save cache: end"));
}
}

View File

@@ -25,7 +25,6 @@
#include "parser-tab.hh"
#include "lexer-tab.hh"
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
#include "nixexpr.hh"
#include "nixexpr-ast.hh"
@@ -44,128 +43,28 @@ struct ParseData
Path path;
string error;
};
static string showAttrPath(ATermList attrPath)
static Expr fixAttrs(int recursive, ATermList as)
{
string s;
for (ATermIterator i(attrPath); i; ++i) {
if (!s.empty()) s += '.';
s += aterm2String(*i);
}
return s;
}
struct Tree
{
Expr leaf; ATerm pos; bool recursive;
typedef std::map<ATerm, Tree> Children;
Children children;
Tree() { leaf = 0; recursive = true; }
};
static ATermList buildAttrs(const Tree & t, ATermList & nonrec)
{
ATermList res = ATempty;
for (Tree::Children::const_reverse_iterator i = t.children.rbegin();
i != t.children.rend(); ++i)
if (!i->second.recursive)
nonrec = ATinsert(nonrec, makeBind(i->first, i->second.leaf, i->second.pos));
else
res = ATinsert(res, i->second.leaf
? makeBind(i->first, i->second.leaf, i->second.pos)
: makeBind(i->first, makeAttrs(buildAttrs(i->second, nonrec)), makeNoPos()));
return res;
}
static Expr fixAttrs(bool recursive, ATermList as)
{
Tree attrs;
ATermList bs = ATempty, cs = ATempty;
ATermList * is = recursive ? &cs : &bs;
for (ATermIterator i(as); i; ++i) {
ATermList names, attrPath; Expr src, e; ATerm name, pos;
ATermList names;
Expr src;
ATerm pos;
if (matchInherit(*i, src, names, pos)) {
bool fromScope = matchScope(src);
for (ATermIterator j(names); j; ++j) {
if (attrs.children.find(*j) != attrs.children.end())
throw ParseError(format("duplicate definition of attribute `%1%' at %2%")
% showAttrPath(ATmakeList1(*j)) % showPos(pos));
Tree & t(attrs.children[*j]);
t.leaf = fromScope ? makeVar(*j) : makeSelect(src, *j);
t.pos = pos;
if (recursive && fromScope) t.recursive = false;
Expr rhs = fromScope ? makeVar(*j) : makeSelect(src, *j);
*is = ATinsert(*is, makeBind(*j, rhs, pos));
}
}
else if (matchBindAttrPath(*i, attrPath, e, pos)) {
Tree * t(&attrs);
for (ATermIterator j(attrPath); j; ) {
name = *j; ++j;
if (t->leaf) throw ParseError(format("attribute set containing `%1%' at %2% already defined at %3%")
% showAttrPath(attrPath) % showPos(pos) % showPos (t->pos));
t = &(t->children[name]);
}
if (t->leaf)
throw ParseError(format("duplicate definition of attribute `%1%' at %2% and %3%")
% showAttrPath(attrPath) % showPos(pos) % showPos (t->pos));
if (!t->children.empty())
throw ParseError(format("duplicate definition of attribute `%1%' at %2%")
% showAttrPath(attrPath) % showPos(pos));
t->leaf = e; t->pos = pos;
}
else abort(); /* can't happen */
} else bs = ATinsert(bs, *i);
}
ATermList nonrec = ATempty;
ATermList rec = buildAttrs(attrs, nonrec);
return recursive ? makeRec(rec, nonrec) : makeAttrs(rec);
}
static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat)
{
ATerm name;
ATermList formals;
Pattern pat1, pat2;
ATermBool ellipsis;
if (matchVarPat(pat, name)) {
if (map.get(name))
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
% aterm2String(name) % showPos(pos));
map.set(name, name);
}
else if (matchAttrsPat(pat, formals, ellipsis)) {
for (ATermIterator i(formals); i; ++i) {
ATerm d1;
if (!matchFormal(*i, name, d1)) abort();
if (map.get(name))
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
% aterm2String(name) % showPos(pos));
map.set(name, name);
}
}
else if (matchAtPat(pat, pat1, pat2)) {
checkPatternVars(pos, map, pat1);
checkPatternVars(pos, map, pat2);
}
else abort();
}
static void checkPatternVars(ATerm pos, Pattern pat)
{
ATermMap map;
checkPatternVars(pos, map, pat);
if (recursive)
return makeRec(bs, cs);
else
return makeAttrs(bs);
}
@@ -247,7 +146,7 @@ static Expr stripIndentation(ATermList es)
/* Remove the last line if it is empty and consists only of
spaces. */
if (n == 1) {
string::size_type p = s2.find_last_of('\n');
unsigned int p = s2.find_last_of('\n');
if (p != string::npos && s2.find_first_not_of(' ', p + 1) == string::npos)
s2 = string(s2, 0, p + 1);
}
@@ -318,7 +217,7 @@ static void freeAndUnprotect(void * p)
%type <t> start expr expr_function expr_if expr_op
%type <t> expr_app expr_select expr_simple bind inheritsrc formal
%type <t> pattern pattern2
%type <ts> binds ids attrpath expr_list string_parts ind_string_parts
%type <ts> binds ids expr_list string_parts ind_string_parts
%type <formals> formals
%token <t> ID INT STR IND_STR PATH URI
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL
@@ -345,13 +244,13 @@ expr: expr_function;
expr_function
: pattern ':' expr_function
{ checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); }
{ $$ = makeFunction($1, $3, CUR_POS); }
| ASSERT expr ';' expr_function
{ $$ = makeAssert($2, $4, CUR_POS); }
| WITH expr ';' expr_function
{ $$ = makeWith($2, $4, CUR_POS); }
| LET binds IN expr_function
{ $$ = makeSelect(fixAttrs(true, ATinsert($2, makeBindAttrPath(ATmakeList1(toATerm("<let-body>")), $4, CUR_POS))), toATerm("<let-body>")); }
{ $$ = makeSelect(fixAttrs(1, ATinsert($2, makeBind(toATerm("<let-body>"), $4, CUR_POS))), toATerm("<let-body>")); }
| expr_if
;
@@ -406,12 +305,12 @@ expr_simple
/* Let expressions `let {..., body = ...}' are just desugared
into `(rec {..., body = ...}).body'. */
| LET '{' binds '}'
{ $$ = makeSelect(fixAttrs(true, $3), toATerm("body")); }
{ $$ = makeSelect(fixAttrs(1, $3), toATerm("body")); }
| REC '{' binds '}'
{ $$ = fixAttrs(true, $3); }
{ $$ = fixAttrs(1, $3); }
| '{' binds '}'
{ $$ = fixAttrs(false, $2); }
| '[' expr_list ']' { $$ = makeList(ATreverse($2)); }
{ $$ = fixAttrs(0, $2); }
| '[' expr_list ']' { $$ = makeList($2); }
;
string_parts
@@ -442,8 +341,8 @@ binds
;
bind
: attrpath '=' expr ';'
{ $$ = makeBindAttrPath(ATreverse($1), $3, CUR_POS); }
: ID '=' expr ';'
{ $$ = makeBind($1, $3, CUR_POS); }
| INHERIT inheritsrc ids ';'
{ $$ = makeInherit($2, $3, CUR_POS); }
;
@@ -455,18 +354,16 @@ inheritsrc
ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; };
attrpath
: attrpath '.' ID { $$ = ATinsert($1, $3); }
| ID { $$ = ATmakeList1($1); }
;
expr_list
: expr_list expr_select { $$ = ATinsert($1, $2); }
: expr_select expr_list { $$ = ATinsert($2, $1); }
/* yes, this is right-recursive, but it doesn't matter since
otherwise we would need ATreverse which requires unbounded
stack space */
| { $$ = ATempty; }
;
formals
: formal ',' formals /* !!! right recursive */
: formal ',' formals /* idem - right recursive */
{ $$.formals = ATinsert($3.formals, $1); $$.ellipsis = $3.ellipsis; }
| formal
{ $$.formals = ATinsert(ATempty, $1); $$.ellipsis = false; }
@@ -495,6 +392,84 @@ formal
namespace nix {
static void checkAttrs(ATermMap & names, ATermList bnds)
{
for (ATermIterator i(bnds); i; ++i) {
ATerm name;
Expr e;
ATerm pos;
if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */
if (names.get(name))
throw EvalError(format("duplicate attribute `%1%' at %2%")
% aterm2String(name) % showPos(pos));
names.set(name, name);
}
}
static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat)
{
ATerm name;
ATermList formals;
Pattern pat1, pat2;
ATermBool ellipsis;
if (matchVarPat(pat, name)) {
if (map.get(name))
throw EvalError(format("duplicate formal function argument `%1%' at %2%")
% aterm2String(name) % showPos(pos));
map.set(name, name);
}
else if (matchAttrsPat(pat, formals, ellipsis)) {
for (ATermIterator i(formals); i; ++i) {
ATerm d1;
if (!matchFormal(*i, name, d1)) abort();
if (map.get(name))
throw EvalError(format("duplicate formal function argument `%1%' at %2%")
% aterm2String(name) % showPos(pos));
map.set(name, name);
}
}
else if (matchAtPat(pat, pat1, pat2)) {
checkPatternVars(pos, map, pat1);
checkPatternVars(pos, map, pat2);
}
else abort();
}
static void checkAttrSets(ATerm e)
{
ATerm pat, body, pos;
if (matchFunction(e, pat, body, pos)) {
ATermMap map(16);
checkPatternVars(pos, map, pat);
}
ATermList bnds;
if (matchAttrs(e, bnds)) {
ATermMap names(ATgetLength(bnds));
checkAttrs(names, bnds);
}
ATermList rbnds, nrbnds;
if (matchRec(e, rbnds, nrbnds)) {
ATermMap names(ATgetLength(rbnds) + ATgetLength(nrbnds));
checkAttrs(names, rbnds);
checkAttrs(names, nrbnds);
}
if (ATgetType(e) == AT_APPL) {
int arity = ATgetArity(ATgetAFun(e));
for (int i = 0; i < arity; ++i)
checkAttrSets(ATgetArgument(e, i));
}
else if (ATgetType(e) == AT_LIST)
for (ATermIterator i((ATermList) e); i; ++i)
checkAttrSets(*i);
}
static Expr parse(EvalState & state,
const char * text, const Path & path,
const Path & basePath)
@@ -509,14 +484,16 @@ static Expr parse(EvalState & state,
int res = yyparse(scanner, &data);
yylex_destroy(scanner);
if (res) throw ParseError(data.error);
if (res) throw EvalError(data.error);
try {
checkVarDefs(state.primOps, data.result);
} catch (Error & e) {
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
throw EvalError(format("%1%, in `%2%'") % e.msg() % path);
}
checkAttrSets(data.result);
return data.result;
}

View File

@@ -74,14 +74,12 @@ static Expr prim_null(EvalState & state, const ATermVector & args)
platforms. */
static Expr prim_currentSystem(EvalState & state, const ATermVector & args)
{
state.nrDepthAfterReset = 0;
return makeStr(thisSystem);
}
static Expr prim_currentTime(EvalState & state, const ATermVector & args)
{
state.nrDepthAfterReset = 0;
return ATmake("Int(<int>)", time(0));
}
@@ -127,27 +125,6 @@ static Expr prim_isFunction(EvalState & state, const ATermVector & args)
return makeBool(matchFunction(e, pat, body, pos));
}
/* Determine whether the argument is an Int. */
static Expr prim_isInt(EvalState & state, const ATermVector & args)
{
int i;
return makeBool(matchInt(evalExpr(state, args[0]), i));
}
/* Determine whether the argument is an String. */
static Expr prim_isString(EvalState & state, const ATermVector & args)
{
string s;
PathSet l;
return makeBool(matchStr(evalExpr(state, args[0]), s, l));
}
/* Determine whether the argument is an Bool. */
static Expr prim_isBool(EvalState & state, const ATermVector & args)
{
ATermBool b;
return makeBool(matchBool(evalExpr(state, args[0]), b));
}
static Expr prim_genericClosure(EvalState & state, const ATermVector & args)
{
@@ -208,29 +185,15 @@ static Expr prim_abort(EvalState & state, const ATermVector & args)
static Expr prim_throw(EvalState & state, const ATermVector & args)
{
PathSet context;
throw ThrownError(format("user-thrown exception: %1%") %
throw ThrownError(format("user-thrown exception: `%1%'") %
evalString(state, args[0], context));
}
static Expr prim_addErrorContext(EvalState & state, const ATermVector & args)
{
PathSet context;
try {
return evalExpr(state, args[1]);
} catch (Error & e) {
e.addPrefix(format("%1%\n") %
evalString(state, args[0], context));
throw;
}
}
/* Return an environment variable. Use with care. */
static Expr prim_getEnv(EvalState & state, const ATermVector & args)
{
string name = evalStringNoCtx(state, args[0]);
state.nrDepthAfterReset = 0;
return makeStr(getEnv(name));
}
@@ -252,14 +215,6 @@ static Expr prim_trace(EvalState & state, const ATermVector & args)
*************************************************************/
static bool isFixedOutput(const Derivation & drv)
{
return drv.outputs.size() == 1 &&
drv.outputs.begin()->first == "out" &&
drv.outputs.begin()->second.hash != "";
}
/* Returns the hash of a derivation modulo fixed-output
subderivations. A fixed-output derivation is a derivation with one
output (`out') for which an expected hash and hash algorithm are
@@ -272,29 +227,35 @@ static bool isFixedOutput(const Derivation & drv)
function, we do not want to rebuild everything depending on it
(after all, (the hash of) the file being downloaded is unchanged).
So the *output paths* should not change. On the other hand, the
*derivation paths* should change to reflect the new dependency
graph.
*derivation store expression paths* should change to reflect the
new dependency graph.
That's what this function does: it returns a hash which is just the
hash of the derivation ATerm, except that any input derivation
of the derivation ATerm, except that any input store expression
paths have been replaced by the result of a recursive call to this
function, and that for fixed-output derivations we return a hash of
its output path. */
function, and that for fixed-output derivations we return
(basically) its outputHash. */
static Hash hashDerivationModulo(EvalState & state, Derivation drv)
{
/* Return a fixed hash for fixed-output derivations. */
if (isFixedOutput(drv)) {
if (drv.outputs.size() == 1) {
DerivationOutputs::const_iterator i = drv.outputs.begin();
return hashString(htSHA256, "fixed:out:"
+ i->second.hashAlgo + ":"
+ i->second.hash + ":"
+ i->second.path);
if (i->first == "out" &&
i->second.hash != "")
{
return hashString(htSHA256, "fixed:out:"
+ i->second.hashAlgo + ":"
+ i->second.hash + ":"
+ i->second.path);
}
}
/* For other derivations, replace the inputs paths with recursive
calls to this function.*/
DerivationInputs inputs2;
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
i != drv.inputDrvs.end(); ++i)
{
Hash h = state.drvHashes[i->first];
if (h.type == htUnknown) {
Derivation drv2 = derivationFromPath(i->first);
@@ -319,7 +280,6 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv)
static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
{
startNest(nest, lvlVomit, "evaluating derivation");
state.nrDepthAfterReset = 0;
ATermMap attrs;
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
@@ -344,7 +304,8 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
PathSet context;
string outputHash, outputHashAlgo;
string outputHash;
string outputHashAlgo;
bool outputHashRecursive = false;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) {
@@ -403,32 +364,13 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
/* Everything in the context of the strings in the derivation
attributes should be added as dependencies of the resulting
derivation. */
foreach (PathSet::iterator, i, context) {
Path path = *i;
/* Paths marked with `=' denote that the path of a derivation
is explicitly passed to the builder. Since that allows the
builder to gain access to every path in the dependency
graph of the derivation (including all outputs), all paths
in the graph must be added to this derivation's list of
inputs to ensure that they are available when the builder
runs. */
if (path.at(0) == '=') {
path = string(path, 1);
PathSet refs; computeFSClosure(path, refs);
foreach (PathSet::iterator, j, refs) {
drv.inputSrcs.insert(*j);
if (isDerivation(*j))
drv.inputDrvs[*j] = singleton<StringSet>("out");
}
}
debug(format("derivation uses `%1%'") % path);
assert(isStorePath(path));
if (isDerivation(path))
drv.inputDrvs[path] = singleton<StringSet>("out");
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
debug(format("derivation uses `%1%'") % *i);
assert(isStorePath(*i));
if (isDerivation(*i))
drv.inputDrvs[*i] = singleton<StringSet>("out");
else
drv.inputSrcs.insert(path);
drv.inputSrcs.insert(*i);
}
/* Do we have all required attributes? */
@@ -438,7 +380,6 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
throw EvalError("required attribute `system' missing");
/* If an output hash was given, check it. */
Path outPath;
if (outputHash == "")
outputHashAlgo = "";
else {
@@ -457,7 +398,6 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
% outputHash % outputHashAlgo);
string s = outputHash;
outputHash = printHash(h);
outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
}
@@ -473,12 +413,13 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
have an empty value. This ensures that changes in the set of
output names do get reflected in the hash. */
drv.env["out"] = "";
drv.outputs["out"] = DerivationOutput("", outputHashAlgo, outputHash);
drv.outputs["out"] =
DerivationOutput("", outputHashAlgo, outputHash);
/* Use the masked derivation expression to compute the output
path. */
if (outPath == "")
outPath = makeStorePath("output:out", hashDerivationModulo(state, drv), drvName);
Path outPath = makeStorePath("output:out",
hashDerivationModulo(state, drv), drvName);
/* Construct the final derivation store expression. */
drv.env["out"] = outPath;
@@ -501,7 +442,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
outAttrs.set(toATerm("outPath"),
makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos()));
outAttrs.set(toATerm("drvPath"),
makeAttrRHS(makeStr(drvPath, singleton<PathSet>("=" + drvPath)), makeNoPos()));
makeAttrRHS(makeStr(drvPath, singleton<PathSet>(drvPath)), makeNoPos()));
return makeAttrs(outAttrs);
}
@@ -553,13 +494,11 @@ static Expr prim_storePath(EvalState & state, const ATermVector & args)
{
PathSet context;
Path path = canonPath(coerceToPath(state, args[0], context));
state.nrDepthAfterReset = 0;
if (!isInStore(path))
throw EvalError(format("path `%1%' is not in the Nix store") % path);
Path path2 = toStorePath(path);
if (!store->isValidPath(path2))
throw EvalError(format("store path `%1%' is not valid") % path2);
context.insert(path2);
if (!store->isValidPath(path))
throw EvalError(format("store path `%1%' is not valid") % path);
context.insert(toStorePath(path));
return makeStr(path, context);
}
@@ -570,7 +509,6 @@ static Expr prim_pathExists(EvalState & state, const ATermVector & args)
Path path = coerceToPath(state, args[0], context);
if (!context.empty())
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
state.nrDepthAfterReset = 0;
return makeBool(pathExists(path));
}
@@ -604,7 +542,6 @@ static Expr prim_readFile(EvalState & state, const ATermVector & args)
Path path = coerceToPath(state, args[0], context);
if (!context.empty())
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
state.nrDepthAfterReset = 0;
return makeStr(readFile(path));
}
@@ -637,14 +574,11 @@ static Expr prim_toFile(EvalState & state, const ATermVector & args)
PathSet refs;
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
Path path = *i;
if (path.at(0) == '=') path = string(path, 1);
if (isDerivation(path))
if (isDerivation(*i))
throw EvalError(format("in `toFile': the file `%1%' cannot refer to derivation outputs") % name);
refs.insert(path);
refs.insert(*i);
}
state.nrDepthAfterReset = 0;
Path storePath = readOnlyMode
? computeStorePathForText(name, contents, refs)
: store->addTextToStore(name, contents, refs);
@@ -697,10 +631,9 @@ static Expr prim_filterSource(EvalState & state, const ATermVector & args)
FilterFromExpr filter(state, args[0]);
state.nrDepthAfterReset = 0;
Path dstPath = readOnlyMode
? computeStorePathForPath(path, true, htSHA256, filter).first
: store->addToStore(path, true, htSHA256, filter);
? computeStorePathForPath(path, false, false, "", filter).first
: store->addToStore(path, false, false, "", filter);
return makeStr(dstPath, singleton<PathSet>(dstPath));
}
@@ -1022,16 +955,11 @@ void EvalState::addPrimOps()
addPrimOp("import", 1, prim_import);
addPrimOp("isNull", 1, prim_isNull);
addPrimOp("__isFunction", 1, prim_isFunction);
addPrimOp("__isString", 1, prim_isString);
addPrimOp("__isInt", 1, prim_isInt);
addPrimOp("__isBool", 1, prim_isBool);
addPrimOp("__genericClosure", 1, prim_genericClosure);
addPrimOp("abort", 1, prim_abort);
addPrimOp("throw", 1, prim_throw);
addPrimOp("__addErrorContext", 2, prim_addErrorContext);
addPrimOp("__getEnv", 1, prim_getEnv);
addPrimOp("__trace", 2, prim_trace);
// Expr <-> String
addPrimOp("__exprToString", 1, prim_exprToString);

View File

@@ -1,10 +1,6 @@
pkglib_LTLIBRARIES = libmain.la
libmain_la_SOURCES = shared.cc
libmain_la_LIBADD = ../libstore/libstore.la
pkginclude_HEADERS = shared.hh
libmain_la_SOURCES = shared.cc shared.hh
AM_CXXFLAGS = \
-DNIX_STORE_DIR=\"$(storedir)\" \

View File

@@ -125,9 +125,6 @@ RemoveTempRoots::~RemoveTempRoots()
}
static bool showTrace = false;
/* Initialize and reorder arguments, then call the actual argument
processor. */
static void initAndRun(int argc, char * * argv)
@@ -141,6 +138,7 @@ static void initAndRun(int argc, char * * argv)
nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR));
nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR));
nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR));
nixChrootsDir = canonPath(getEnv("NIX_CHROOTS_DIR", nixStateDir + "/chroots"));
string subs = getEnv("NIX_SUBSTITUTERS", "default");
if (subs == "default") {
@@ -246,15 +244,6 @@ static void initAndRun(int argc, char * * argv)
maxSilentTime = getIntArg(arg, i, args.end());
else if (arg == "--no-build-hook")
useBuildHook = false;
else if (arg == "--show-trace")
showTrace = true;
else if (arg == "--option") {
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
string name = *i;
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
string value = *i;
overrideSetting(name, tokenizeString(value));
}
else remaining.push_back(arg);
}
@@ -370,9 +359,7 @@ int main(int argc, char * * argv)
% e.what() % programId);
return 1;
} catch (BaseError & e) {
printMsg(lvlError, format("error: %1%%2%") % (showTrace ? e.prefix() : "") % e.msg());
if (e.prefix() != "" && !showTrace)
printMsg(lvlError, "(use `--show-trace' to show detailed location information)");
printMsg(lvlError, format("error: %1%") % e.msg());
return 1;
} catch (std::exception & e) {
printMsg(lvlError, format("error: %1%") % e.what());

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,8 @@ Path writeDerivation(const Derivation & drv, const string & name)
{
PathSet references;
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs)
for (DerivationInputs::const_iterator i = drv.inputDrvs.begin();
i != drv.inputDrvs.end(); ++i)
references.insert(i->first);
/* Note that the outputs of a derivation are *not* references
(that can be missing (of course) and should not necessarily be

View File

@@ -247,7 +247,9 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
Strings tempRootFiles = readDirectory(
(format("%1%/%2%") % nixStateDir % tempRootsDir).str());
foreach (Strings::iterator, i, tempRootFiles) {
for (Strings::iterator i = tempRootFiles.begin();
i != tempRootFiles.end(); ++i)
{
Path path = (format("%1%/%2%/%3%") % nixStateDir % tempRootsDir % *i).str();
debug(format("reading temporary root file `%1%'") % path);
@@ -326,7 +328,7 @@ static void findRoots(const Path & path, bool recurseSymlinks,
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
foreach (Strings::iterator, i, names)
for (Strings::iterator i = names.begin(); i != names.end(); ++i)
findRoots(path + "/" + *i, recurseSymlinks, deleteStale, roots);
}
@@ -397,7 +399,7 @@ static void addAdditionalRoots(PathSet & roots)
Strings paths = tokenizeString(result, "\n");
foreach (Strings::iterator, i, paths) {
for (Strings::iterator i = paths.begin(); i != paths.end(); ++i) {
if (isInStore(*i)) {
Path path = toStorePath(*i);
if (roots.find(path) == roots.end() && store->isValidPath(path)) {
@@ -419,7 +421,8 @@ static void dfsVisit(const PathSet & paths, const Path & path,
if (store->isValidPath(path))
store->queryReferences(path, references);
foreach (PathSet::iterator, i, references)
for (PathSet::iterator i = references.begin();
i != references.end(); ++i)
/* Don't traverse into paths that don't exist. That can
happen due to substitutes for non-existent paths. */
if (*i != path && paths.find(*i) != paths.end())
@@ -433,7 +436,7 @@ Paths topoSortPaths(const PathSet & paths)
{
Paths sorted;
PathSet visited;
foreach (PathSet::const_iterator, i, paths)
for (PathSet::const_iterator i = paths.begin(); i != paths.end(); ++i)
dfsVisit(paths, *i, visited, sorted);
return sorted;
}
@@ -450,7 +453,7 @@ static time_t lastFileAccessTime(const Path & path)
if (S_ISDIR(st.st_mode)) {
time_t last = 0;
Strings names = readDirectory(path);
foreach (Strings::iterator, i, names) {
for (Strings::iterator i = names.begin(); i != names.end(); ++i) {
time_t t = lastFileAccessTime(path + "/" + *i);
if (t > last) last = t;
}
@@ -473,13 +476,30 @@ void LocalStore::gcPath(const GCOptions & options, GCResults & results,
if (!pathExists(path)) return;
#ifndef __CYGWIN__
AutoCloseFD fdLock;
/* Only delete a lock file if we can acquire a write lock on it.
That means that it's either stale, or the process that created
it hasn't locked it yet. In the latter case the other process
will detect that we deleted the lock, and retry (see
pathlocks.cc). */
if (path.size() >= 5 && string(path, path.size() - 5) == ".lock") {
fdLock = openLockFile(path, false);
if (fdLock != -1 && !lockFile(fdLock, ltWrite, false)) {
debug(format("skipping active lock `%1%'") % path);
return;
}
}
#endif
/* Okay, it's safe to delete. */
unsigned long long bytesFreed, blocksFreed;
deleteFromStore(path, bytesFreed, blocksFreed);
results.bytesFreed += bytesFreed;
results.blocksFreed += blocksFreed;
if (options.maxFreed && results.bytesFreed > options.maxFreed) {
if (results.bytesFreed > options.maxFreed) {
printMsg(lvlInfo, format("deleted more than %1% bytes; stopping") % options.maxFreed);
throw GCLimitReached();
}
@@ -493,6 +513,12 @@ void LocalStore::gcPath(const GCOptions & options, GCResults & results,
throw GCLimitReached();
}
}
#ifndef __CYGWIN__
if (fdLock != -1)
/* Write token to stale (deleted) lock file. */
writeFull(fdLock, (const unsigned char *) "d", 1);
#endif
}
@@ -543,7 +569,7 @@ struct CachingAtimeComparator : public std::binary_function<Path, Path, bool>
};
static string showTime(const string & format, time_t t)
string showTime(const string & format, time_t t)
{
char s[128];
strftime(s, sizeof s, format.c_str(), localtime(&t));
@@ -551,26 +577,6 @@ static string showTime(const string & format, time_t t)
}
static bool isLive(const Path & path, const PathSet & livePaths,
const PathSet & tempRoots, const PathSet & tempRootsClosed)
{
if (livePaths.find(path) != livePaths.end() ||
tempRootsClosed.find(path) != tempRootsClosed.end()) return true;
/* A lock file belonging to a path that we're building right
now isn't garbage. */
if (hasSuffix(path, ".lock") && tempRoots.find(string(path, 0, path.size() - 5)) != tempRoots.end())
return true;
/* Don't delete .chroot directories for derivations that are
currently being built. */
if (hasSuffix(path, ".chroot") && tempRoots.find(string(path, 0, path.size() - 7)) != tempRoots.end())
return true;
return false;
}
void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
{
bool gcKeepOutputs =
@@ -591,7 +597,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
Roots rootMap = options.ignoreLiveness ? Roots() : nix::findRoots(true);
PathSet roots;
foreach (Roots::iterator, i, rootMap) roots.insert(i->second);
for (Roots::iterator i = rootMap.begin(); i != rootMap.end(); ++i)
roots.insert(i->second);
/* Add additional roots returned by the program specified by the
NIX_ROOT_FINDER environment variable. This is typically used
@@ -609,11 +616,13 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
roots under the `references' relation. */
printMsg(lvlError, format("computing live paths..."));
PathSet livePaths;
foreach (PathSet::const_iterator, i, roots)
for (PathSet::const_iterator i = roots.begin(); i != roots.end(); ++i)
computeFSClosure(canonPath(*i), livePaths);
if (gcKeepDerivations) {
foreach (PathSet::iterator, i, livePaths) {
for (PathSet::iterator i = livePaths.begin();
i != livePaths.end(); ++i)
{
/* Note that the deriver need not be valid (e.g., if we
previously ran the collector with `gcKeepDerivations'
turned off). */
@@ -625,7 +634,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (gcKeepOutputs) {
/* Hmz, identical to storePathRequisites in nix-store. */
foreach (PathSet::iterator, i, livePaths)
for (PathSet::iterator i = livePaths.begin();
i != livePaths.end(); ++i)
if (isDerivation(*i)) {
Derivation drv = derivationFromPath(*i);
@@ -635,7 +645,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
gcLevel = defaultGcLevel;
if (gcLevel >= gcKeepOutputsThreshold)
foreach (DerivationOutputs::iterator, j, drv.outputs)
for (DerivationOutputs::iterator j = drv.outputs.begin();
j != drv.outputs.end(); ++j)
if (isValidPath(j->second.path))
computeFSClosure(j->second.path, livePaths);
}
@@ -660,7 +671,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
(and computeFSClosure() assumes that the presence of a path
means that it has already been closed). */
PathSet tempRootsClosed;
foreach (PathSet::iterator, i, tempRoots)
for (PathSet::iterator i = tempRoots.begin(); i != tempRoots.end(); ++i)
if (isValidPath(*i))
computeFSClosure(*i, tempRootsClosed);
else
@@ -680,7 +691,9 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
Paths entries = readDirectory(nixStore);
foreach (Paths::iterator, i, entries) {
Path path = canonPath(nixStore + "/" + *i);
if (!isLive(path, livePaths, tempRoots, tempRootsClosed)) storePaths.insert(path);
if (livePaths.find(path) == livePaths.end() &&
tempRootsClosed.find(path) == tempRootsClosed.end())
storePaths.insert(path);
}
}
@@ -688,8 +701,10 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
foreach (PathSet::iterator, i, options.pathsToDelete) {
assertStorePath(*i);
storePaths.insert(*i);
if (isLive(*i, livePaths, tempRoots, tempRootsClosed))
if (livePaths.find(*i) != livePaths.end())
throw Error(format("cannot delete path `%1%' since it is still alive") % *i);
if (tempRootsClosed.find(*i) != tempRootsClosed.end())
throw Error(format("cannot delete path `%1%' since it is temporarily in use") % *i);
}
}

View File

@@ -13,10 +13,10 @@ string nixDataDir = "/UNINIT";
string nixLogDir = "/UNINIT";
string nixStateDir = "/UNINIT";
string nixDBPath = "/UNINIT";
string nixCacheFile = "/UNINIT";
string nixConfDir = "/UNINIT";
string nixLibexecDir = "/UNINIT";
string nixBinDir = "/UNINIT";
string nixChrootsDir = "/UNINIT";
bool keepFailed = false;
bool keepGoing = false;
@@ -25,7 +25,7 @@ Verbosity buildVerbosity = lvlInfo;
unsigned int maxBuildJobs = 1;
bool readOnlyMode = false;
string thisSystem = "unset";
time_t maxSilentTime = 0;
unsigned int maxSilentTime = 0;
Paths substituters;
bool useBuildHook = true;
bool printBuildTrace = false;
@@ -35,9 +35,6 @@ static bool settingsRead = false;
static std::map<string, Strings> settings;
/* Overriden settings. */
std::map<string, Strings> settingsCmdline;
string & at(Strings & ss, unsigned int n)
{
@@ -77,8 +74,6 @@ static void readSettings()
advance(i, 2);
settings[name] = Strings(i, tokens.end());
};
settings.insert(settingsCmdline.begin(), settingsCmdline.end());
settingsRead = true;
}
@@ -124,13 +119,6 @@ unsigned int queryIntSetting(const string & name, unsigned int def)
}
void overrideSetting(const string & name, const Strings & value)
{
if (settingsRead) settings[name] = value;
settingsCmdline[name] = value;
}
void reloadSettings()
{
settingsRead = false;

View File

@@ -24,9 +24,6 @@ extern string nixStateDir;
/* nixDBPath is the path name of our Berkeley DB environment. */
extern string nixDBPath;
/* nixCacheFile is the path name of the normal form cache. */
extern string nixCacheFile;
/* nixConfDir is the directory where configuration files are
stored. */
extern string nixConfDir;
@@ -38,6 +35,12 @@ extern string nixLibexecDir;
/* nixBinDir is the directory where the main programs are stored. */
extern string nixBinDir;
/* nixChrootsDir is the directory where we create chroot environments
(when chroot builds are enabled). We don't put these under /tmp to
prevent "rm -rf /tmp" from recursing into /nix/store via the bind
mounts in the chroots. */
extern string nixChrootsDir;
/* Misc. global flags. */
@@ -68,7 +71,7 @@ extern string thisSystem;
/* The maximum time in seconds that a builer can go without producing
any output on stdout/stderr before it is killed. 0 means
infinity. */
extern time_t maxSilentTime;
extern unsigned int maxSilentTime;
/* The substituters. There are programs that can somehow realise a
store path without building, e.g., by downloading it or copying it
@@ -104,8 +107,6 @@ bool queryBoolSetting(const string & name, bool def);
unsigned int queryIntSetting(const string & name, unsigned int def);
void overrideSetting(const string & name, const Strings & value);
void reloadSettings();

View File

@@ -47,8 +47,6 @@ LocalStore::LocalStore()
if (readOnlyMode) return;
createDirs(nixStore);
checkStoreNotSymlink();
try {
@@ -67,7 +65,6 @@ LocalStore::LocalStore()
createDirs(nixDBPath + "/info");
createDirs(nixDBPath + "/referrer");
createDirs(nixDBPath + "/failed");
int curSchema = getSchema();
if (curSchema > nixSchemaVersion)
@@ -88,8 +85,8 @@ LocalStore::~LocalStore()
flushDelayedUpdates();
foreach (RunningSubstituters::iterator, i, runningSubstituters) {
i->second.to.close();
i->second.from.close();
i->second.toBuf.reset();
i->second.to.reset();
i->second.pid.wait(true);
}
@@ -111,6 +108,23 @@ int LocalStore::getSchema()
}
void copyPath(const Path & src, const Path & dst, PathFilter & filter)
{
debug(format("copying `%1%' to `%2%'") % src % dst);
/* Dump an archive of the path `src' into a string buffer, then
restore the archive to `dst'. This is not a very good method
for very large paths, but `copyPath' is mainly used for small
files. */
StringSink sink;
dumpPath(src, sink, filter);
StringSource source(sink.s);
restorePath(dst, source);
}
void canonicalisePathMetaData(const Path & path, bool recurse)
{
checkInterrupt();
@@ -153,7 +167,7 @@ void canonicalisePathMetaData(const Path & path, bool recurse)
if (st.st_mtime != 0) {
struct utimbuf utimbuf;
utimbuf.actime = st.st_atime;
utimbuf.modtime = 1; /* 1 second into the epoch */
utimbuf.modtime = 0;
if (utime(path.c_str(), &utimbuf) == -1)
throw SysError(format("changing modification time of `%1%'") % path);
}
@@ -162,7 +176,7 @@ void canonicalisePathMetaData(const Path & path, bool recurse)
if (recurse && S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
foreach (Strings::iterator, i, names)
for (Strings::iterator i = names.begin(); i != names.end(); ++i)
canonicalisePathMetaData(path + "/" + *i, true);
}
}
@@ -199,13 +213,6 @@ static Path referrersFileFor(const Path & path)
}
static Path failedFileFor(const Path & path)
{
string baseName = baseNameOf(path);
return (format("%1%/failed/%2%") % nixDBPath % baseName).str();
}
static Path tmpFileForAtomicUpdate(const Path & path)
{
return (format("%1%/.%2%.%3%") % dirOf(path) % getpid() % baseNameOf(path)).str();
@@ -325,8 +332,6 @@ void LocalStore::registerValidPath(const ValidPathInfo & info, bool ignoreValidi
appendReferrer(*i, info.path, false);
}
assert(info.hash.type == htSHA256);
string s = (format(
"Hash: sha256:%1%\n"
"References: %2%\n"
@@ -345,20 +350,6 @@ void LocalStore::registerValidPath(const ValidPathInfo & info, bool ignoreValidi
}
void LocalStore::registerFailedPath(const Path & path)
{
/* Write an empty file in the .../failed directory to denote the
failure of the builder for `path'. */
writeFile(failedFileFor(path), "");
}
bool LocalStore::hasPathFailed(const Path & path)
{
return pathExists(failedFileFor(path));
}
Hash parseHashField(const Path & path, const string & s)
{
string::size_type colon = s.find(':');
@@ -373,7 +364,7 @@ Hash parseHashField(const Path & path, const string & s)
}
ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
ValidPathInfo LocalStore::queryPathInfo(const Path & path)
{
ValidPathInfo res;
res.path = path;
@@ -392,8 +383,8 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
/* Parse it. */
Strings lines = tokenizeString(info, "\n");
foreach (Strings::iterator, i, lines) {
string::size_type p = i->find(':');
for (Strings::iterator i = lines.begin(); i != lines.end(); ++i) {
unsigned int p = i->find(':');
if (p == string::npos) continue; /* bad line */
string name(*i, 0, p);
string value(*i, p + 2);
@@ -403,12 +394,7 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
} else if (name == "Deriver") {
res.deriver = value;
} else if (name == "Hash") {
try {
res.hash = parseHashField(path, value);
} catch (Error & e) {
if (!ignoreErrors) throw;
printMsg(lvlError, format("cannot parse hash field in `%1%': %2%") % infoFile % e.msg());
}
res.hash = parseHashField(path, value);
} else if (name == "Registered-At") {
int n = 0;
string2Int(value, n);
@@ -433,7 +419,7 @@ PathSet LocalStore::queryValidPaths()
{
PathSet paths;
Strings entries = readDirectory(nixDBPath + "/info");
foreach (Strings::iterator, i, entries)
for (Strings::iterator i = entries.begin(); i != entries.end(); ++i)
if (i->at(0) != '.') paths.insert(nixStore + "/" + *i);
return paths;
}
@@ -468,7 +454,7 @@ bool LocalStore::queryReferrersInternal(const Path & path, PathSet & referrers)
Paths refs = tokenizeString(readFile(fd), " ");
foreach (Paths::iterator, i, refs)
for (Paths::iterator i = refs.begin(); i != refs.end(); ++i)
/* Referrers can be invalid (see registerValidPath() for the
invariant), so we only return one if it is valid. */
if (isStorePath(*i) && isValidPath(*i)) referrers.insert(*i); else allValid = false;
@@ -526,16 +512,23 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
/* Parent. */
run.to = toPipe.writeSide.borrow();
run.from = fromPipe.readSide.borrow();
toPipe.readSide.close();
fromPipe.writeSide.close();
run.toBuf = boost::shared_ptr<stdio_filebuf>(new stdio_filebuf(toPipe.writeSide.borrow(), std::ios_base::out));
run.to = boost::shared_ptr<std::ostream>(new std::ostream(&*run.toBuf));
run.fromBuf = boost::shared_ptr<stdio_filebuf>(new stdio_filebuf(fromPipe.readSide.borrow(), std::ios_base::in));
run.from = boost::shared_ptr<std::istream>(new std::istream(&*run.fromBuf));
}
template<class T> T getIntLine(int fd)
template<class T> T getIntLine(std::istream & str)
{
string s = readLine(fd);
string s;
T res;
if (!string2Int(s, res)) throw Error("integer expected from stream");
getline(str, s);
if (!str || !string2Int(s, res)) throw Error("integer expected from stream");
return res;
}
@@ -545,8 +538,10 @@ bool LocalStore::hasSubstitutes(const Path & path)
foreach (Paths::iterator, i, substituters) {
RunningSubstituter & run(runningSubstituters[*i]);
startSubstituter(*i, run);
writeLine(run.to, "have\n" + path);
if (getIntLine<int>(run.from)) return true;
*run.to << "have\n" << path << "\n" << std::flush;
if (getIntLine<int>(*run.from)) return true;
}
return false;
@@ -559,19 +554,19 @@ bool LocalStore::querySubstitutablePathInfo(const Path & substituter,
RunningSubstituter & run(runningSubstituters[substituter]);
startSubstituter(substituter, run);
writeLine(run.to, "info\n" + path);
if (!getIntLine<int>(run.from)) return false;
*run.to << "info\n" << path << "\n" << std::flush;
if (!getIntLine<int>(*run.from)) return false;
info.deriver = readLine(run.from);
getline(*run.from, info.deriver);
if (info.deriver != "") assertStorePath(info.deriver);
int nrRefs = getIntLine<int>(run.from);
int nrRefs = getIntLine<int>(*run.from);
while (nrRefs--) {
Path p = readLine(run.from);
Path p; getline(*run.from, p);
assertStorePath(p);
info.references.insert(p);
}
info.downloadSize = getIntLine<long long>(run.from);
info.downloadSize = getIntLine<long long>(*run.from);
return true;
}
@@ -600,7 +595,8 @@ static void dfsVisit(std::map<Path, ValidPathInfo> & infos,
ValidPathInfo & info(infos[path]);
foreach (PathSet::iterator, i, info.references)
for (PathSet::iterator i = info.references.begin();
i != info.references.end(); ++i)
if (infos.find(*i) != infos.end())
dfsVisit(infos, *i, visited, sorted);
@@ -615,15 +611,15 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
/* Sort the paths topologically under the references relation, so
that if path A is referenced by B, then A is registered before
B. */
foreach (ValidPathInfos::const_iterator, i, infos)
for (ValidPathInfos::const_iterator i = infos.begin(); i != infos.end(); ++i)
infosMap[i->path] = *i;
PathSet visited;
Paths sorted;
foreach (ValidPathInfos::const_iterator, i, infos)
for (ValidPathInfos::const_iterator i = infos.begin(); i != infos.end(); ++i)
dfsVisit(infosMap, i->path, visited, sorted);
foreach (Paths::iterator, i, sorted)
for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i)
registerValidPath(infosMap[*i]);
}
@@ -674,12 +670,16 @@ void LocalStore::invalidatePath(const Path & path)
}
Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
bool recursive, HashType hashAlgo)
Path LocalStore::addToStore(const Path & _srcPath, bool fixed,
bool recursive, string hashAlgo, PathFilter & filter)
{
Hash h = hashString(hashAlgo, dump);
Path srcPath(absPath(_srcPath));
debug(format("adding `%1%' to the store") % srcPath);
Path dstPath = makeFixedOutputPath(recursive, hashAlgo, h, name);
std::pair<Path, Hash> pr =
computeStorePathForPath(srcPath, fixed, recursive, hashAlgo, filter);
Path & dstPath(pr.first);
Hash & h(pr.second);
addTempRoot(dstPath);
@@ -694,22 +694,16 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
if (pathExists(dstPath)) deletePathWrapped(dstPath);
if (recursive) {
StringSource source(dump);
restorePath(dstPath, source);
} else
writeStringToFile(dstPath, dump);
copyPath(srcPath, dstPath, filter);
Hash h2 = hashPath(htSHA256, dstPath, filter);
if (h != h2)
throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)")
% srcPath % dstPath % printHash(h) % printHash(h2));
canonicalisePathMetaData(dstPath);
/* Register the SHA-256 hash of the NAR serialisation of
the path in the database. We may just have computed it
above (if called with recursive == true and hashAlgo ==
sha256); otherwise, compute it here. */
registerValidPath(dstPath,
(recursive && hashAlgo == htSHA256) ? h :
(recursive ? hashString(htSHA256, dump) : hashPath(htSHA256, dstPath)),
PathSet(), "");
registerValidPath(dstPath, h, PathSet(), "");
}
outputLock.setDeletion(true);
@@ -719,29 +713,10 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
}
Path LocalStore::addToStore(const Path & _srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter)
{
Path srcPath(absPath(_srcPath));
debug(format("adding `%1%' to the store") % srcPath);
/* Read the whole path into memory. This is not a very scalable
method for very large paths, but `copyPath' is mainly used for
small files. */
StringSink sink;
if (recursive)
dumpPath(srcPath, sink, filter);
else
sink.s = readFile(srcPath);
return addToStoreFromDump(sink.s, baseNameOf(srcPath), recursive, hashAlgo);
}
Path LocalStore::addTextToStore(const string & name, const string & s,
Path LocalStore::addTextToStore(const string & suffix, const string & s,
const PathSet & references)
{
Path dstPath = computeStorePathForText(name, s, references);
Path dstPath = computeStorePathForText(suffix, s, references);
addTempRoot(dstPath);
@@ -879,7 +854,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
store path follows the archive data proper), and besides, we
don't know yet whether the signature is valid. */
Path tmpDir = createTempDir(nixStore);
AutoDelete delTmp(tmpDir); /* !!! could be GC'ed! */
AutoDelete delTmp(tmpDir);
Path unpacked = tmpDir + "/unpacked";
restorePath(unpacked, hashAndReadSource);
@@ -938,14 +913,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
if (!isValidPath(dstPath)) {
PathLocks outputLock;
/* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a
lock on this path). */
Strings locksHeld = tokenizeString(getEnv("NIX_HELD_LOCKS"));
if (find(locksHeld.begin(), locksHeld.end(), dstPath) == locksHeld.end())
outputLock.lockPaths(singleton<PathSet, Path>(dstPath));
PathLocks outputLock(singleton<PathSet, Path>(dstPath));
if (!isValidPath(dstPath)) {
@@ -1003,7 +971,7 @@ void LocalStore::verifyStore(bool checkContents)
PathSet validPaths2 = queryValidPaths(), validPaths;
foreach (PathSet::iterator, i, validPaths2) {
for (PathSet::iterator i = validPaths2.begin(); i != validPaths2.end(); ++i) {
checkInterrupt();
if (!isStorePath(*i)) {
printMsg(lvlError, format("path `%1%' is not in the Nix store") % *i);
@@ -1021,25 +989,26 @@ void LocalStore::verifyStore(bool checkContents)
std::map<Path, PathSet> referrersCache;
foreach (PathSet::iterator, i, validPaths) {
for (PathSet::iterator i = validPaths.begin(); i != validPaths.end(); ++i) {
bool update = false;
ValidPathInfo info = queryPathInfo(*i, true);
ValidPathInfo info = queryPathInfo(*i);
/* Check the references: each reference should be valid, and
it should have a matching referrer. */
foreach (PathSet::iterator, j, info.references) {
for (PathSet::iterator j = info.references.begin();
j != info.references.end(); ++j)
{
if (referrersCache.find(*j) == referrersCache.end())
queryReferrers(*j, referrersCache[*j]);
if (referrersCache[*j].find(*i) == referrersCache[*j].end()) {
printMsg(lvlError, format("adding missing referrer mapping from `%1%' to `%2%'")
% *j % *i);
appendReferrer(*j, *i, true);
}
if (validPaths.find(*j) == validPaths.end()) {
printMsg(lvlError, format("incomplete closure: `%1%' needs missing `%2%'")
% *i % *j);
/* nothing we can do about it... */
} else {
if (referrersCache.find(*j) == referrersCache.end())
queryReferrers(*j, referrersCache[*j]);
if (referrersCache[*j].find(*i) == referrersCache[*j].end()) {
printMsg(lvlError, format("adding missing referrer mapping from `%1%' to `%2%'")
% *j % *i);
appendReferrer(*j, *i, true);
}
}
}
@@ -1051,11 +1020,7 @@ void LocalStore::verifyStore(bool checkContents)
}
/* Check the content hash (optionally - slow). */
if (info.hash.hashSize == 0) {
printMsg(lvlError, format("re-hashing `%1%'") % *i);
info.hash = hashPath(htSHA256, *i);
update = true;
} else if (checkContents) {
if (checkContents) {
debug(format("checking contents of `%1%'") % *i);
Hash current = hashPath(info.hash.type, *i);
if (current != info.hash) {
@@ -1077,12 +1042,10 @@ void LocalStore::verifyStore(bool checkContents)
std::map<Path, PathSet> referencesCache;
Strings entries = readDirectory(nixDBPath + "/referrer");
foreach (Strings::iterator, i, entries) {
for (Strings::iterator i = entries.begin(); i != entries.end(); ++i) {
Path from = nixStore + "/" + *i;
if (validPaths.find(from) == validPaths.end()) {
/* !!! This removes lock files as well. Need to check
whether that's okay. */
printMsg(lvlError, format("removing referrers file for invalid `%1%'") % from);
Path p = referrersFileFor(from);
if (unlink(p.c_str()) == -1)
@@ -1101,7 +1064,7 @@ void LocalStore::verifyStore(bool checkContents)
/* Each referrer should have a matching reference. */
PathSet referrersNew;
foreach (PathSet::iterator, j, referrers) {
for (PathSet::iterator j = referrers.begin(); j != referrers.end(); ++j) {
if (referencesCache.find(*j) == referencesCache.end())
queryReferences(*j, referencesCache[*j]);
if (referencesCache[*j].find(from) == referencesCache[*j].end()) {

View File

@@ -3,6 +3,8 @@
#include <string>
#include <ext/stdio_filebuf.h>
#include "store-api.hh"
#include "util.hh"
@@ -34,10 +36,15 @@ struct OptimiseStats
};
typedef __gnu_cxx::stdio_filebuf<char> stdio_filebuf;
struct RunningSubstituter
{
Pid pid;
AutoCloseFD to, from;
boost::shared_ptr<stdio_filebuf> toBuf, fromBuf;
boost::shared_ptr<std::ostream> to;
boost::shared_ptr<std::istream> from;
};
@@ -82,18 +89,11 @@ public:
bool querySubstitutablePathInfo(const Path & substituter,
const Path & path, SubstitutablePathInfo & info);
Path addToStore(const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256,
Path addToStore(const Path & srcPath, bool fixed = false,
bool recursive = false, string hashAlgo = "",
PathFilter & filter = defaultPathFilter);
/* Like addToStore(), but the contents of the path are contained
in `dump', which is either a NAR serialisation (if recursive ==
true) or simply the contents of a regular file (if recursive ==
false). */
Path addToStoreFromDump(const string & dump, const string & name,
bool recursive = true, HashType hashAlgo = htSHA256);
Path addTextToStore(const string & name, const string & s,
Path addTextToStore(const string & suffix, const string & s,
const PathSet & references);
void exportPath(const Path & path, bool sign,
@@ -137,13 +137,6 @@ public:
void registerValidPaths(const ValidPathInfos & infos);
/* Register that the build of a derivation with output `path' has
failed. */
void registerFailedPath(const Path & path);
/* Query whether `path' previously failed to build. */
bool hasPathFailed(const Path & path);
private:
Path schemaPath;
@@ -162,7 +155,7 @@ private:
void registerValidPath(const ValidPathInfo & info, bool ignoreValidity = false);
ValidPathInfo queryPathInfo(const Path & path, bool ignoreErrors = false);
ValidPathInfo queryPathInfo(const Path & path);
void rewriteReferrers(const Path & path, bool purge, PathSet referrers);
@@ -190,8 +183,8 @@ void copyPath(const Path & src, const Path & dst);
/* "Fix", or canonicalise, the meta-data of the files in a store path
after it has been built. In particular:
- the last modification date on each file is set to 1 (i.e.,
00:00:01 1/1/1970 UTC)
- the last modification date on each file is set to 0 (i.e.,
00:00:00 1/1/1970 UTC)
- the permissions are set of 444 or 555 (i.e., read-only with or
without execute permission; setuid bits etc. are cleared)
- the owner and group are set to the Nix user and group, if we're

View File

@@ -30,14 +30,16 @@ void computeFSClosure(const Path & storePath,
else
store->queryReferences(storePath, references);
foreach (PathSet::iterator, i, references)
for (PathSet::iterator i = references.begin();
i != references.end(); ++i)
computeFSClosure(*i, paths, flipDirection);
}
Path findOutput(const Derivation & drv, string id)
{
foreach (DerivationOutputs::const_iterator, i, drv.outputs)
for (DerivationOutputs::const_iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
if (i->first == id) return i->second.path;
throw Error(format("derivation has no output `%1%'") % id);
}
@@ -65,17 +67,20 @@ void queryMissing(const PathSet & targets,
Derivation drv = derivationFromPath(p);
bool mustBuild = false;
foreach (DerivationOutputs::iterator, i, drv.outputs)
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
if (!store->isValidPath(i->second.path) && !store->hasSubstitutes(i->second.path))
mustBuild = true;
if (mustBuild) {
willBuild.insert(p);
todo.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
foreach (DerivationInputs::iterator, i, drv.inputDrvs)
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
i != drv.inputDrvs.end(); ++i)
todo.insert(i->first);
} else
foreach (DerivationOutputs::iterator, i, drv.outputs)
for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i)
todo.insert(i->second.path);
}

View File

@@ -131,7 +131,7 @@ static void hashAndLink(bool dryRun, HashToPath & hashToPath,
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
foreach (Strings::iterator, i, names)
for (Strings::iterator i = names.begin(); i != names.end(); ++i)
hashAndLink(dryRun, hashToPath, stats, path + "/" + *i);
}
}
@@ -143,7 +143,7 @@ void LocalStore::optimiseStore(bool dryRun, OptimiseStats & stats)
PathSet paths = queryValidPaths();
foreach (PathSet::iterator, i, paths) {
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
addTempRoot(*i);
if (!isValidPath(*i)) continue; /* path was GC'ed, probably */
startNest(nest, lvlChatty, format("hashing files in `%1%'") % *i);

View File

@@ -141,9 +141,9 @@ PathLocks::PathLocks(const PathSet & paths, const string & waitMsg)
}
bool PathLocks::lockPaths(const PathSet & _paths,
const string & waitMsg, bool wait)
void PathLocks::lockPaths(const PathSet & _paths, const string & waitMsg)
{
/* May be called only once! */
assert(fds.empty());
/* Note that `fds' is built incrementally so that the destructor
@@ -155,7 +155,7 @@ bool PathLocks::lockPaths(const PathSet & _paths,
paths.sort();
/* Acquire the lock for each path. */
foreach (Paths::iterator, i, paths) {
for (Paths::iterator i = paths.begin(); i != paths.end(); i++) {
checkInterrupt();
Path path = *i;
Path lockPath = path + ".lock";
@@ -174,15 +174,8 @@ bool PathLocks::lockPaths(const PathSet & _paths,
/* Acquire an exclusive lock. */
if (!lockFile(fd, ltWrite, false)) {
if (wait) {
if (waitMsg != "") printMsg(lvlError, waitMsg);
lockFile(fd, ltWrite, true);
} else {
/* Failed to lock this path; release all other
locks. */
unlock();
return false;
}
if (waitMsg != "") printMsg(lvlError, waitMsg);
lockFile(fd, ltWrite, true);
}
debug(format("lock acquired on `%1%'") % lockPath);
@@ -206,20 +199,12 @@ bool PathLocks::lockPaths(const PathSet & _paths,
fds.push_back(FDPair(fd.borrow(), lockPath));
lockedPaths.insert(lockPath);
}
return true;
}
PathLocks::~PathLocks()
{
unlock();
}
void PathLocks::unlock()
{
foreach (list<FDPair>::iterator, i, fds) {
for (list<FDPair>::iterator i = fds.begin(); i != fds.end(); i++) {
if (deletePaths) deleteLockFilePreClose(i->second, i->first);
lockedPaths.erase(i->second);
@@ -231,8 +216,6 @@ void PathLocks::unlock()
debug(format("lock released on `%1%'") % i->second);
}
fds.clear();
}

View File

@@ -33,11 +33,9 @@ public:
PathLocks();
PathLocks(const PathSet & paths,
const string & waitMsg = "");
bool lockPaths(const PathSet & _paths,
const string & waitMsg = "",
bool wait = true);
void lockPaths(const PathSet & _paths,
const string & waitMsg = "");
~PathLocks();
void unlock();
void setDeletion(bool deletePaths);
};

View File

@@ -1,10 +1,17 @@
#include "references.hh"
#include "hash.hh"
#include "util.hh"
#include "archive.hh"
#include <map>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <map>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
namespace nix {
@@ -13,8 +20,8 @@ namespace nix {
static unsigned int refLength = 32; /* characters */
static void search(const unsigned char * s, unsigned int len,
StringSet & hashes, StringSet & seen)
static void search(size_t len, const unsigned char * s,
StringSet & ids, StringSet & seen)
{
static bool initialised = false;
static bool isBase32[256];
@@ -36,60 +43,93 @@ static void search(const unsigned char * s, unsigned int len,
}
if (!match) continue;
string ref((const char *) s + i, refLength);
if (hashes.find(ref) != hashes.end()) {
if (ids.find(ref) != ids.end()) {
debug(format("found reference to `%1%' at offset `%2%'")
% ref % i);
seen.insert(ref);
hashes.erase(ref);
ids.erase(ref);
}
++i;
}
}
struct RefScanSink : Sink
void checkPath(const string & path,
StringSet & ids, StringSet & seen)
{
HashSink hashSink;
StringSet hashes;
StringSet seen;
string tail;
RefScanSink() : hashSink(htSHA256) { }
checkInterrupt();
void operator () (const unsigned char * data, unsigned int len);
};
debug(format("checking `%1%'") % path);
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path `%1%'") % path);
void RefScanSink::operator () (const unsigned char * data, unsigned int len)
{
hashSink(data, len);
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
for (Strings::iterator i = names.begin(); i != names.end(); i++) {
search(i->size(), (const unsigned char *) i->c_str(), ids, seen);
checkPath(path + "/" + *i, ids, seen);
}
}
/* It's possible that a reference spans the previous and current
fragment, so search in the concatenation of the tail of the
previous fragment and the start of the current fragment. */
string s = tail + string((const char *) data, len > refLength ? refLength : len);
search((const unsigned char *) s.c_str(), s.size(), hashes, seen);
else if (S_ISREG(st.st_mode)) {
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
if (fd == -1) throw SysError(format("opening file `%1%'") % path);
search(data, len, hashes, seen);
size_t bufSize = 1024 * 1024;
assert(refLength <= bufSize);
unsigned char * buf = new unsigned char[bufSize];
unsigned int tailLen = len <= refLength ? len : refLength;
tail =
string(tail, tail.size() < refLength - tailLen ? 0 : tail.size() - (refLength - tailLen)) +
string((const char *) data + len - tailLen, tailLen);
size_t left = st.st_size;
bool firstBlock = true;
while (left > 0) {
checkInterrupt();
size_t read = left > bufSize ? bufSize : left;
size_t copiedBytes = 0;
if (!firstBlock) {
/* Move the last (refLength - 1) bytes from the last
block to the start of the buffer to deal with
references that cross block boundaries. */
copiedBytes = refLength - 1;
if (read + copiedBytes > bufSize)
read -= copiedBytes;
memcpy(buf, buf + (bufSize - copiedBytes), copiedBytes);
}
firstBlock = false;
readFull(fd, buf + copiedBytes, read);
left -= read;
search(copiedBytes + read, buf, ids, seen);
}
delete[] buf; /* !!! autodelete */
}
else if (S_ISLNK(st.st_mode)) {
string target = readLink(path);
search(target.size(), (const unsigned char *) target.c_str(), ids, seen);
}
else throw Error(format("unknown file type: %1%") % path);
}
PathSet scanForReferences(const string & path,
const PathSet & refs, Hash & hash)
PathSet scanForReferences(const string & path, const PathSet & paths)
{
RefScanSink sink;
std::map<string, Path> backMap;
StringSet ids;
StringSet seen;
/* For efficiency (and a higher hit rate), just search for the
hash part of the file name. (This assumes that all references
have the form `HASH-bla'). */
foreach (PathSet::const_iterator, i, refs) {
for (PathSet::const_iterator i = paths.begin(); i != paths.end(); i++) {
string baseName = baseNameOf(*i);
string::size_type pos = baseName.find('-');
if (pos == string::npos)
@@ -98,25 +138,21 @@ PathSet scanForReferences(const string & path,
assert(s.size() == refLength);
assert(backMap.find(s) == backMap.end());
// parseHash(htSHA256, s);
sink.hashes.insert(s);
ids.insert(s);
backMap[s] = *i;
}
/* Look for the hashes in the NAR dump of the path. */
dumpPath(path, sink);
checkPath(path, ids, seen);
/* Map the hashes found back to their store paths. */
PathSet found;
foreach (StringSet::iterator, i, sink.seen) {
for (StringSet::iterator i = seen.begin(); i != seen.end(); i++) {
std::map<string, Path>::iterator j;
if ((j = backMap.find(*i)) == backMap.end()) abort();
found.insert(j->second);
}
hash = sink.hashSink.finish();
return found;
}
}

View File

@@ -2,12 +2,10 @@
#define __REFERENCES_H
#include "types.hh"
#include "hash.hh"
namespace nix {
PathSet scanForReferences(const Path & path, const PathSet & refs,
Hash & hash);
PathSet scanForReferences(const Path & path, const PathSet & refs);
}

View File

@@ -29,22 +29,14 @@ Path readStorePath(Source & from)
PathSet readStorePaths(Source & from)
{
PathSet paths = readStringSet(from);
foreach (PathSet::iterator, i, paths) assertStorePath(*i);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
assertStorePath(*i);
return paths;
}
RemoteStore::RemoteStore()
{
initialised = false;
}
void RemoteStore::openConnection()
{
if (initialised) return;
initialised = true;
string remoteMode = getEnv("NIX_REMOTE");
if (remoteMode == "slave")
@@ -72,8 +64,8 @@ void RemoteStore::openConnection()
throw Error("Nix daemon protocol version not supported");
writeInt(PROTOCOL_VERSION, to);
processStderr();
}
catch (Error & e) {
} catch (Error & e) {
throw Error(format("cannot start worker (%1%)")
% e.msg());
}
@@ -202,7 +194,6 @@ void RemoteStore::setOptions()
bool RemoteStore::isValidPath(const Path & path)
{
openConnection();
writeInt(wopIsValidPath, to);
writeString(path, to);
processStderr();
@@ -213,14 +204,12 @@ bool RemoteStore::isValidPath(const Path & path)
PathSet RemoteStore::queryValidPaths()
{
openConnection();
throw Error("not implemented");
}
bool RemoteStore::hasSubstitutes(const Path & path)
{
openConnection();
writeInt(wopHasSubstitutes, to);
writeString(path, to);
processStderr();
@@ -232,7 +221,6 @@ bool RemoteStore::hasSubstitutes(const Path & path)
bool RemoteStore::querySubstitutablePathInfo(const Path & path,
SubstitutablePathInfo & info)
{
openConnection();
if (GET_PROTOCOL_MINOR(daemonVersion) < 3) return false;
writeInt(wopQuerySubstitutablePathInfo, to);
writeString(path, to);
@@ -249,7 +237,6 @@ bool RemoteStore::querySubstitutablePathInfo(const Path & path,
Hash RemoteStore::queryPathHash(const Path & path)
{
openConnection();
writeInt(wopQueryPathHash, to);
writeString(path, to);
processStderr();
@@ -261,7 +248,6 @@ Hash RemoteStore::queryPathHash(const Path & path)
void RemoteStore::queryReferences(const Path & path,
PathSet & references)
{
openConnection();
writeInt(wopQueryReferences, to);
writeString(path, to);
processStderr();
@@ -273,7 +259,6 @@ void RemoteStore::queryReferences(const Path & path,
void RemoteStore::queryReferrers(const Path & path,
PathSet & referrers)
{
openConnection();
writeInt(wopQueryReferrers, to);
writeString(path, to);
processStderr();
@@ -284,7 +269,6 @@ void RemoteStore::queryReferrers(const Path & path,
Path RemoteStore::queryDeriver(const Path & path)
{
openConnection();
writeInt(wopQueryDeriver, to);
writeString(path, to);
processStderr();
@@ -294,31 +278,27 @@ Path RemoteStore::queryDeriver(const Path & path)
}
Path RemoteStore::addToStore(const Path & _srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter)
Path RemoteStore::addToStore(const Path & _srcPath, bool fixed,
bool recursive, string hashAlgo, PathFilter & filter)
{
openConnection();
Path srcPath(absPath(_srcPath));
writeInt(wopAddToStore, to);
writeString(baseNameOf(srcPath), to);
/* backwards compatibility hack */
writeInt((hashAlgo == htSHA256 && recursive) ? 0 : 1, to);
writeInt(fixed ? 1 : 0, to);
writeInt(recursive ? 1 : 0, to);
writeString(printHashType(hashAlgo), to);
writeString(hashAlgo, to);
dumpPath(srcPath, to, filter);
processStderr();
return readStorePath(from);
}
Path RemoteStore::addTextToStore(const string & name, const string & s,
Path RemoteStore::addTextToStore(const string & suffix, const string & s,
const PathSet & references)
{
openConnection();
writeInt(wopAddTextToStore, to);
writeString(name, to);
writeString(suffix, to);
writeString(s, to);
writeStringSet(references, to);
@@ -330,7 +310,6 @@ Path RemoteStore::addTextToStore(const string & name, const string & s,
void RemoteStore::exportPath(const Path & path, bool sign,
Sink & sink)
{
openConnection();
writeInt(wopExportPath, to);
writeString(path, to);
writeInt(sign ? 1 : 0, to);
@@ -341,10 +320,10 @@ void RemoteStore::exportPath(const Path & path, bool sign,
Path RemoteStore::importPath(bool requireSignature, Source & source)
{
openConnection();
writeInt(wopImportPath, to);
/* We ignore requireSignature, since the worker forces it to true
anyway. */
anyway. */
processStderr(0, &source);
return readStorePath(from);
}
@@ -352,7 +331,6 @@ Path RemoteStore::importPath(bool requireSignature, Source & source)
void RemoteStore::buildDerivations(const PathSet & drvPaths)
{
openConnection();
writeInt(wopBuildDerivations, to);
writeStringSet(drvPaths, to);
processStderr();
@@ -362,7 +340,6 @@ void RemoteStore::buildDerivations(const PathSet & drvPaths)
void RemoteStore::ensurePath(const Path & path)
{
openConnection();
writeInt(wopEnsurePath, to);
writeString(path, to);
processStderr();
@@ -372,7 +349,6 @@ void RemoteStore::ensurePath(const Path & path)
void RemoteStore::addTempRoot(const Path & path)
{
openConnection();
writeInt(wopAddTempRoot, to);
writeString(path, to);
processStderr();
@@ -382,7 +358,6 @@ void RemoteStore::addTempRoot(const Path & path)
void RemoteStore::addIndirectRoot(const Path & path)
{
openConnection();
writeInt(wopAddIndirectRoot, to);
writeString(path, to);
processStderr();
@@ -392,7 +367,6 @@ void RemoteStore::addIndirectRoot(const Path & path)
void RemoteStore::syncWithGC()
{
openConnection();
writeInt(wopSyncWithGC, to);
processStderr();
readInt(from);
@@ -401,7 +375,6 @@ void RemoteStore::syncWithGC()
Roots RemoteStore::findRoots()
{
openConnection();
writeInt(wopFindRoots, to);
processStderr();
unsigned int count = readInt(from);
@@ -417,18 +390,12 @@ Roots RemoteStore::findRoots()
void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
{
openConnection();
writeInt(wopCollectGarbage, to);
writeInt(options.action, to);
writeStringSet(options.pathsToDelete, to);
writeInt(options.ignoreLiveness, to);
writeLongLong(options.maxFreed, to);
writeInt(options.maxLinks, to);
if (GET_PROTOCOL_MINOR(daemonVersion) >= 5) {
writeInt(options.useAtime, to);
writeInt(options.maxAtime, to);
}
processStderr();

View File

@@ -42,11 +42,11 @@ public:
bool querySubstitutablePathInfo(const Path & path,
SubstitutablePathInfo & info);
Path addToStore(const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256,
Path addToStore(const Path & srcPath, bool fixed = false,
bool recursive = false, string hashAlgo = "",
PathFilter & filter = defaultPathFilter);
Path addTextToStore(const string & name, const string & s,
Path addTextToStore(const string & suffix, const string & s,
const PathSet & references);
void exportPath(const Path & path, bool sign,
@@ -74,9 +74,6 @@ private:
FdSource from;
Pid child;
unsigned int daemonVersion;
bool initialised;
void openConnection();
void processStderr(Sink * sink = 0, Source * source = 0);

View File

@@ -5,6 +5,12 @@
#include <limits.h>
/* Needed for some ancient environments. */
#ifndef ULLONG_MAX
#define ULLONG_MAX 18446744073709551615
#endif
namespace nix {
@@ -12,7 +18,7 @@ GCOptions::GCOptions()
{
action = gcDeleteDead;
ignoreLiveness = false;
maxFreed = 0;
maxFreed = ULLONG_MAX;
maxLinks = 0;
useAtime = false;
maxAtime = (time_t) -1;
@@ -81,7 +87,7 @@ void checkStoreName(const string & name)
reasons (e.g., "." and ".."). */
if (string(name, 0, 1) == ".")
throw Error(format("illegal name: `%1%'") % name);
foreach (string::const_iterator, i, name)
for (string::const_iterator i = name.begin(); i != name.end(); ++i)
if (!((*i >= 'A' && *i <= 'Z') ||
(*i >= 'a' && *i <= 'z') ||
(*i >= '0' && *i <= '9') ||
@@ -93,113 +99,55 @@ void checkStoreName(const string & name)
}
/* Store paths have the following form:
<store>/<h>-<name>
where
<store> = the location of the Nix store, usually /nix/store
<name> = a human readable name for the path, typically obtained
from the name attribute of the derivation, or the name of the
source file from which the store path is created
<h> = base-32 representation of the first 160 bits of a SHA-256
hash of <s>; the hash part of the store name
<s> = the string "<type>:sha256:<h2>:<store>:<name>";
note that it includes the location of the store as well as the
name to make sure that changes to either of those are reflected
in the hash (e.g. you won't get /nix/store/<h>-name1 and
/nix/store/<h>-name2 with equal hash parts).
<type> = one of:
"text:<r1>:<r2>:...<rN>"
for plain text files written to the store using
addTextToStore(); <r1> ... <rN> are the references of the
path.
"source"
for paths copied to the store using addToStore() when recursive
= true and hashAlgo = "sha256"
"output:out"
for either the outputs created by derivations, OR paths copied
to the store using addToStore() with recursive != true or
hashAlgo != "sha256" (in that case "source" is used; it's
silly, but it's done that way for compatibility).
<h2> = base-16 representation of a SHA-256 hash of:
if <type> = "text:...":
the string written to the resulting store path
if <type> = "source":
the serialisation of the path from which this store path is
copied, as returned by hashPath()
if <type> = "output:out":
for non-fixed derivation outputs:
the derivation (see hashDerivationModulo() in
primops.cc)
for paths copied by addToStore() or produced by fixed-output
derivations:
the string "fixed:out:<rec><algo>:<hash>:", where
<rec> = "r:" for recursive (path) hashes, or "" or flat
(file) hashes
<algo> = "md5", "sha1" or "sha256"
<hash> = base-16 representation of the path or flat hash of
the contents of the path (or expected contents of the
path for fixed-output derivations)
It would have been nicer to handle fixed-output derivations under
"source", e.g. have something like "source:<rec><algo>", but we're
stuck with this for now...
The main reason for this way of computing names is to prevent name
collisions (for security). For instance, it shouldn't be feasible
to come up with a derivation whose output path collides with the
path for a copied source. The former would have a <s> starting with
"output:out:", while the latter would have a <2> starting with
"source:".
*/
Path makeStorePath(const string & type,
const Hash & hash, const string & name)
const Hash & hash, const string & suffix)
{
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
string s = type + ":sha256:" + printHash(hash) + ":"
+ nixStore + ":" + name;
+ nixStore + ":" + suffix;
checkStoreName(name);
checkStoreName(suffix);
return nixStore + "/"
+ printHash32(compressHash(hashString(htSHA256, s), 20))
+ "-" + name;
+ "-" + suffix;
}
Path makeFixedOutputPath(bool recursive,
HashType hashAlgo, Hash hash, string name)
string hashAlgo, Hash hash, string name)
{
return hashAlgo == htSHA256 && recursive
? makeStorePath("source", hash, name)
: makeStorePath("output:out", hashString(htSHA256,
"fixed:out:" + (recursive ? (string) "r:" : "") +
printHashType(hashAlgo) + ":" + printHash(hash) + ":"),
name);
/* !!! copy/paste from primops.cc */
Hash h = hashString(htSHA256, "fixed:out:"
+ (recursive ? (string) "r:" : "") + hashAlgo + ":"
+ printHash(hash) + ":"
+ "");
return makeStorePath("output:out", h, name);
}
std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter)
bool fixed, bool recursive, string hashAlgo, PathFilter & filter)
{
HashType ht(hashAlgo);
Hash h = recursive ? hashPath(ht, srcPath, filter) : hashFile(ht, srcPath);
string name = baseNameOf(srcPath);
Path dstPath = makeFixedOutputPath(recursive, hashAlgo, h, name);
Hash h = hashPath(htSHA256, srcPath, filter);
string baseName = baseNameOf(srcPath);
Path dstPath;
if (fixed) {
HashType ht(parseHashType(hashAlgo));
Hash h2 = recursive ? hashPath(ht, srcPath, filter) : hashFile(ht, srcPath);
dstPath = makeFixedOutputPath(recursive, hashAlgo, h2, baseName);
}
else dstPath = makeStorePath("source", h, baseName);
return std::pair<Path, Hash>(dstPath, h);
}
Path computeStorePathForText(const string & name, const string & s,
Path computeStorePathForText(const string & suffix, const string & s,
const PathSet & references)
{
Hash hash = hashString(htSHA256, s);
@@ -207,11 +155,11 @@ Path computeStorePathForText(const string & name, const string & s,
hacky, but we can't put them in `s' since that would be
ambiguous. */
string type = "text";
foreach (PathSet::const_iterator, i, references) {
for (PathSet::const_iterator i = references.begin(); i != references.end(); ++i) {
type += ":";
type += *i;
}
return makeStorePath(type, hash, name);
return makeStorePath(type, hash, suffix);
}
@@ -223,7 +171,7 @@ string makeValidityRegistration(const PathSet & paths,
{
string s = "";
foreach (PathSet::iterator, i, paths) {
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
s += *i + "\n";
if (showHash)
@@ -237,7 +185,8 @@ string makeValidityRegistration(const PathSet & paths,
s += (format("%1%\n") % references.size()).str();
foreach (PathSet::iterator, j, references)
for (PathSet::iterator j = references.begin();
j != references.end(); ++j)
s += *j + "\n";
}
@@ -271,7 +220,9 @@ ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
string showPaths(const PathSet & paths)
{
string s;
foreach (PathSet::const_iterator, i, paths) {
for (PathSet::const_iterator i = paths.begin();
i != paths.end(); ++i)
{
if (s.size() != 0) s += ", ";
s += "`" + *i + "'";
}

View File

@@ -56,8 +56,7 @@ struct GCOptions
/* For `gcDeleteSpecific', the paths to delete. */
PathSet pathsToDelete;
/* Stop after at least `maxFreed' bytes have been freed. 0 means
no limit. */
/* Stop after at least `maxFreed' bytes have been freed. */
unsigned long long maxFreed;
/* Stop after the number of hard links to the Nix store directory
@@ -174,13 +173,13 @@ public:
derivation is pre-loaded into the Nix store. The function
object `filter' can be used to exclude files (see
libutil/archive.hh). */
virtual Path addToStore(const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256,
virtual Path addToStore(const Path & srcPath, bool fixed = false,
bool recursive = false, string hashAlgo = "",
PathFilter & filter = defaultPathFilter) = 0;
/* Like addToStore, but the contents written to the output path is
a regular file containing the given string. */
virtual Path addTextToStore(const string & name, const string & s,
virtual Path addTextToStore(const string & suffix, const string & s,
const PathSet & references) = 0;
/* Export a store path, that is, create a NAR dump of the store
@@ -275,10 +274,10 @@ Path followLinksToStorePath(const Path & path);
/* Constructs a unique store path name. */
Path makeStorePath(const string & type,
const Hash & hash, const string & name);
const Hash & hash, const string & suffix);
Path makeFixedOutputPath(bool recursive,
HashType hashAlgo, Hash hash, string name);
string hashAlgo, Hash hash, string name);
/* This is the preparatory part of addToStore() and addToStoreFixed();
@@ -286,7 +285,7 @@ Path makeFixedOutputPath(bool recursive,
Returns the store path and the cryptographic hash of the
contents of srcPath. */
std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256,
bool fixed = false, bool recursive = false, string hashAlgo = "",
PathFilter & filter = defaultPathFilter);
/* Preparatory part of addTextToStore().
@@ -303,7 +302,7 @@ std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
simply yield a different store path, so other users wouldn't be
affected), but it has some backwards compatibility issues (the
hashing scheme changes), so I'm not doing that for now. */
Path computeStorePathForText(const string & name, const string & s,
Path computeStorePathForText(const string & suffix, const string & s,
const PathSet & references);

View File

@@ -73,7 +73,7 @@ void LocalStore::upgradeStore12()
Paths paths;
nixDB.enumTable(noTxn, dbValidPaths, paths);
foreach (Paths::iterator, i, paths) {
for (Paths::iterator i = paths.begin(); i != paths.end(); ++i) {
ValidPathInfo info;
info.path = *i;

View File

@@ -8,7 +8,7 @@ namespace nix {
#define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f
#define PROTOCOL_VERSION 0x105
#define PROTOCOL_VERSION 0x104
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)

View File

@@ -2,7 +2,6 @@
#include <algorithm>
#include <vector>
#define _XOPEN_SOURCE 600
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -12,8 +11,6 @@
#include "archive.hh"
#include "util.hh"
#include "config.h"
namespace nix {
@@ -50,17 +47,17 @@ static void dumpEntries(const Path & path, Sink & sink, PathFilter & filter)
}
static void dumpContents(const Path & path, size_t size,
static void dumpContents(const Path & path, unsigned int size,
Sink & sink)
{
writeString("contents", sink);
writeLongLong(size, sink);
writeInt(size, sink);
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
if (fd == -1) throw SysError(format("opening file `%1%'") % path);
unsigned char buf[65536];
size_t left = size;
unsigned int left = size;
while (left > 0) {
size_t n = left > sizeof(buf) ? sizeof(buf) : left;
@@ -88,7 +85,7 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
writeString("executable", sink);
writeString("", sink);
}
dumpContents(path, (size_t) st.st_size, sink);
dumpContents(path, st.st_size, sink);
}
else if (S_ISDIR(st.st_mode)) {
@@ -104,7 +101,7 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
writeString(readLink(path), sink);
}
else throw Error(format("file `%1%' has an unknown type") % path);
else throw Error("unknown file type: " + path);
writeString(")", sink);
}
@@ -117,9 +114,9 @@ void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
}
static SerialisationError badArchive(string s)
static Error badArchive(string s)
{
return SerialisationError("bad archive: " + s);
return Error("bad archive: " + s);
}
@@ -132,11 +129,10 @@ static void skipGeneric(Source & source)
}
static void parse(ParseSink & sink, Source & source, const Path & path);
static void restore(const Path & path, Source & source);
static void parseEntry(ParseSink & sink, Source & source, const Path & path)
static void restoreEntry(const Path & path, Source & source)
{
string s, name;
@@ -154,7 +150,7 @@ static void parseEntry(ParseSink & sink, Source & source, const Path & path)
name = readString(source);
} else if (s == "node") {
if (s == "") throw badArchive("entry name missing");
parse(sink, source, path + "/" + name);
restore(path + "/" + name, source);
} else {
throw badArchive("unknown field " + s);
skipGeneric(source);
@@ -163,31 +159,26 @@ static void parseEntry(ParseSink & sink, Source & source, const Path & path)
}
static void parseContents(ParseSink & sink, Source & source, const Path & path)
static void restoreContents(int fd, const Path & path, Source & source)
{
unsigned long long size = readLongLong(source);
sink.preallocateContents(size);
unsigned long long left = size;
unsigned int size = readInt(source);
unsigned int left = size;
unsigned char buf[65536];
while (left) {
checkInterrupt();
unsigned int n = sizeof(buf);
if ((unsigned long long) n > left) n = left;
if (n > left) n = left;
source(buf, n);
sink.receiveContents(buf, n);
writeFull(fd, buf, n);
left -= n;
}
sink.finalizeContents(size);
readPadding(size, source);
}
static void parse(ParseSink & sink, Source & source, const Path & path)
static void restore(const Path & path, Source & source)
{
string s;
@@ -195,6 +186,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
if (s != "(") throw badArchive("expected open tag");
enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;
AutoCloseFD fd;
while (1) {
checkInterrupt();
@@ -212,12 +204,15 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
if (t == "regular") {
type = tpRegular;
sink.createRegularFile(path);
fd = open(path.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd == -1)
throw SysError("creating file " + path);
}
else if (t == "directory") {
sink.createDirectory(path);
type = tpDirectory;
if (mkdir(path.c_str(), 0777) == -1)
throw SysError("creating directory " + path);
}
else if (t == "symlink") {
@@ -229,109 +224,42 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
}
else if (s == "contents" && type == tpRegular) {
parseContents(sink, source, path);
restoreContents(fd, path, source);
}
else if (s == "executable" && type == tpRegular) {
readString(source);
sink.isExecutable();
struct stat st;
if (fstat(fd, &st) == -1)
throw SysError("fstat");
if (fchmod(fd, st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
throw SysError("fchmod");
}
else if (s == "entry" && type == tpDirectory) {
parseEntry(sink, source, path);
restoreEntry(path, source);
}
else if (s == "target" && type == tpSymlink) {
string target = readString(source);
sink.createSymlink(path, target);
if (symlink(target.c_str(), path.c_str()) == -1)
throw SysError("creating symlink " + path);
}
else {
throw badArchive("unknown field " + s);
skipGeneric(source);
}
}
}
void parseDump(ParseSink & sink, Source & source)
{
string version;
try {
version = readString(source);
} catch (SerialisationError & e) {
/* This generally means the integer at the start couldn't be
decoded. Ignore and throw the exception below. */
}
if (version != archiveVersion1)
throw badArchive("input doesn't look like a Nix archive");
parse(sink, source, "");
}
struct RestoreSink : ParseSink
{
Path dstPath;
AutoCloseFD fd;
void createDirectory(const Path & path)
{
Path p = dstPath + path;
if (mkdir(p.c_str(), 0777) == -1)
throw SysError(format("creating directory `%1%'") % p);
};
void createRegularFile(const Path & path)
{
Path p = dstPath + path;
fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd == -1) throw SysError(format("creating file `%1%'") % p);
}
void isExecutable()
{
struct stat st;
if (fstat(fd, &st) == -1)
throw SysError("fstat");
if (fchmod(fd, st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
throw SysError("fchmod");
}
void preallocateContents(unsigned long long len)
{
#if HAVE_POSIX_FALLOCATE
if (len) {
errno = posix_fallocate(fd, 0, len);
if (errno) throw SysError(format("preallocating file of %1% bytes") % len);
}
#endif
}
void receiveContents(unsigned char * data, unsigned int len)
{
writeFull(fd, data, len);
}
void finalizeContents(unsigned long long size)
{
errno = ftruncate(fd, size);
if (errno) throw SysError(format("truncating file to its allocated length of %1% bytes") % size);
}
void createSymlink(const Path & path, const string & target)
{
Path p = dstPath + path;
if (symlink(target.c_str(), p.c_str()) == -1)
throw SysError(format("creating symlink `%1%'") % p);
}
};
void restorePath(const Path & path, Source & source)
{
RestoreSink sink;
sink.dstPath = path;
parseDump(sink, source);
if (readString(source) != archiveVersion1)
throw badArchive("expected Nix archive");
restore(path, source);
}

View File

@@ -56,21 +56,6 @@ extern PathFilter defaultPathFilter;
void dumpPath(const Path & path, Sink & sink,
PathFilter & filter = defaultPathFilter);
struct ParseSink
{
virtual void createDirectory(const Path & path) { };
virtual void createRegularFile(const Path & path) { };
virtual void isExecutable() { };
virtual void preallocateContents(unsigned long long size) { };
virtual void receiveContents(unsigned char * data, unsigned int len) { };
virtual void finalizeContents(unsigned long long size) { };
virtual void createSymlink(const Path & path, const string & target) { };
};
void parseDump(ParseSink & sink, Source & source);
void restorePath(const Path & path, Source & source);

View File

@@ -215,7 +215,7 @@ void ATermMap::remove(ATerm key)
}
unsigned int ATermMap::size() const
unsigned int ATermMap::size()
{
return count; /* STL nomenclature */
}

View File

@@ -59,7 +59,7 @@ public:
void remove(ATerm key);
unsigned int size() const;
unsigned int size();
struct const_iterator
{

View File

@@ -335,13 +335,4 @@ HashType parseHashType(const string & s)
}
string printHashType(HashType ht)
{
if (ht == htMD5) return "md5";
else if (ht == htSHA1) return "sha1";
else if (ht == htSHA256) return "sha256";
else throw Error("cannot print unknown hash type");
}
}

View File

@@ -82,9 +82,6 @@ Hash compressHash(const Hash & hash, unsigned int newSize);
/* Parse a string representing a hash type. */
HashType parseHashType(const string & s);
/* And the reverse. */
string printHashType(HashType ht);
union Ctx;

View File

@@ -1,9 +1,9 @@
#include "serialise.hh"
#include "util.hh"
#include "aterm.hh"
#include <cstring>
namespace nix {
@@ -73,67 +73,6 @@ void writeStringSet(const StringSet & ss, Sink & sink)
}
void writeATerm(ATerm t, Sink & sink)
{
int len;
unsigned char *buf = (unsigned char *) ATwriteToBinaryString(t, &len);
AutoDeleteArray<unsigned char> d(buf);
writeInt(len, sink);
sink(buf, len);
}
/* convert the ATermMap to a list of couple because many terms are shared
between the keys and between the values. Thus the BAF stored by
writeATerm consume less memory space. The list of couples is saved
inside a tree structure of /treedepth/ height because the serialiasation
of ATerm cause a tail recurssion on list tails. */
void writeATermMap(const ATermMap & tm, Sink & sink)
{
const unsigned int treedepth = 5;
const unsigned int maxarity = 128; // 2 < maxarity < MAX_ARITY (= 255)
const unsigned int bufsize = treedepth * maxarity;
AFun map = ATmakeAFun("map", 2, ATfalse);
AFun node = ATmakeAFun("node", maxarity, ATfalse);
ATerm empty = (ATerm) ATmakeAppl0(ATmakeAFun("empty", 0, ATfalse));
unsigned int c[treedepth];
ATerm *buf = new ATerm[bufsize];
AutoDeleteArray<ATerm> d(buf);
memset(buf, 0, bufsize * sizeof(ATerm));
ATprotectArray(buf, bufsize);
for (unsigned int j = 0; j < treedepth; j++)
c[j] = 0;
for (ATermMap::const_iterator i = tm.begin(); i != tm.end(); ++i) {
unsigned int depth = treedepth - 1;
ATerm term = (ATerm) ATmakeAppl2(map, i->key, i->value);
buf[depth * maxarity + c[depth]++] = term;
while (c[depth] % maxarity == 0) {
c[depth] = 0;
term = (ATerm) ATmakeApplArray(node, &buf[depth * maxarity]);
depth--;
buf[depth * maxarity + c[depth]++] = term;
}
}
unsigned int depth = treedepth;
ATerm last_node = empty;
while (depth--) {
buf[depth * maxarity + c[depth]++] = last_node;
while (c[depth] % maxarity)
buf[depth * maxarity + c[depth]++] = empty;
last_node = (ATerm) ATmakeApplArray(node, &buf[depth * maxarity]);
}
writeATerm(last_node, sink);
ATunprotectArray(buf);
}
void readPadding(unsigned int len, Source & source)
{
if (len % 8) {
@@ -141,7 +80,7 @@ void readPadding(unsigned int len, Source & source)
unsigned int n = 8 - (len % 8);
source(zero, n);
for (unsigned int i = 0; i < n; i++)
if (zero[i]) throw SerialisationError("non-zero padding");
if (zero[i]) throw Error("non-zero padding");
}
}
@@ -151,7 +90,7 @@ unsigned int readInt(Source & source)
unsigned char buf[8];
source(buf, sizeof(buf));
if (buf[4] || buf[5] || buf[6] || buf[7])
throw SerialisationError("implementation cannot deal with > 32-bit integers");
throw Error("implementation cannot deal with > 32-bit integers");
return
buf[0] |
(buf[1] << 8) |
@@ -197,48 +136,4 @@ StringSet readStringSet(Source & source)
}
ATerm readATerm(Source & source)
{
unsigned int len = readInt(source);
unsigned char * buf = new unsigned char[len];
AutoDeleteArray<unsigned char> d(buf);
source(buf, len);
ATerm t = ATreadFromBinaryString((char *) buf, len);
if (t == 0)
throw SerialisationError("cannot read a valid ATerm.");
return t;
}
static void recursiveInitATermMap(ATermMap &tm, bool &stop, ATermAppl node)
{
const unsigned int arity = ATgetArity(ATgetAFun(node));
ATerm key, value;
switch (arity) {
case 0:
stop = true;
return;
case 2:
key = ATgetArgument(node, 0);
value = ATgetArgument(node, 1);
tm.set(key, value);
return;
default:
for (unsigned int i = 0; i < arity && !stop; i++)
recursiveInitATermMap(tm, stop, (ATermAppl) ATgetArgument(node, i));
return;
}
}
ATermMap readATermMap(Source & source)
{
ATermMap tm;
bool stop = false;
recursiveInitATermMap(tm, stop, (ATermAppl) readATerm(source));
return tm;
}
}

View File

@@ -2,7 +2,7 @@
#define __SERIALISE_H
#include "types.hh"
#include "aterm-map.hh"
namespace nix {
@@ -35,7 +35,7 @@ struct FdSink : Sink
FdSink()
{
fd = -1;
fd = 0;
}
FdSink(int fd)
@@ -54,7 +54,7 @@ struct FdSource : Source
FdSource()
{
fd = -1;
fd = 0;
}
FdSource(int fd)
@@ -80,9 +80,9 @@ struct StringSink : Sink
/* A source that reads data from a string. */
struct StringSource : Source
{
const string & s;
string & s;
unsigned int pos;
StringSource(const string & _s) : s(_s), pos(0) { }
StringSource(string & _s) : s(_s), pos(0) { }
virtual void operator () (unsigned char * data, unsigned int len)
{
s.copy((char *) data, len, pos);
@@ -98,19 +98,12 @@ void writeInt(unsigned int n, Sink & sink);
void writeLongLong(unsigned long long n, Sink & sink);
void writeString(const string & s, Sink & sink);
void writeStringSet(const StringSet & ss, Sink & sink);
void writeATerm(ATerm t, Sink & sink);
void writeATermMap(const ATermMap & tm, Sink & sink);
void readPadding(unsigned int len, Source & source);
unsigned int readInt(Source & source);
unsigned long long readLongLong(Source & source);
string readString(Source & source);
StringSet readStringSet(Source & source);
ATerm readATerm(Source & source);
ATermMap readATermMap(Source & source);
MakeError(SerialisationError, Error)
}

View File

@@ -24,14 +24,12 @@ using boost::format;
class BaseError : public std::exception
{
protected:
string prefix_; // used for location traces etc.
string err;
public:
BaseError(const format & f);
~BaseError() throw () { };
const char * what() const throw () { return err.c_str(); }
const string & msg() const throw () { return err; }
const string & prefix() const throw () { return prefix_; }
BaseError & addPrefix(const format & f);
};

View File

@@ -33,7 +33,7 @@ BaseError::BaseError(const format & f)
BaseError & BaseError::addPrefix(const format & f)
{
prefix_ = f.str() + prefix_;
err = f.str() + err;
return *this;
}
@@ -229,33 +229,6 @@ void writeFile(const Path & path, const string & s)
}
string readLine(int fd)
{
string s;
while (1) {
checkInterrupt();
char ch;
ssize_t rd = read(fd, &ch, 1);
if (rd == -1) {
if (errno != EINTR)
throw SysError("reading a line");
} else if (rd == 0)
throw Error("unexpected EOF reading a line");
else {
if (ch == '\n') return s;
s += ch;
}
}
}
void writeLine(int fd, string s)
{
s += '\n';
writeFull(fd, (const unsigned char *) s.c_str(), s.size());
}
static void _computePathSize(const Path & path,
unsigned long long & bytes, unsigned long long & blocks)
{
@@ -496,7 +469,11 @@ void warnOnce(bool & haveWarned, const format & f)
static void defaultWriteToStderr(const unsigned char * buf, size_t count)
{
writeFull(STDERR_FILENO, buf, count);
try {
writeFull(STDERR_FILENO, buf, count);
} catch (SysError & e) {
/* ignore EPIPE etc. */
}
}

View File

@@ -60,12 +60,6 @@ string readFile(const Path & path);
/* Write a string to a file. */
void writeFile(const Path & path, const string & s);
/* Read a line from a file descriptor. */
string readLine(int fd);
/* Write a line to a file descriptor. */
void writeLine(int fd, string s);
/* Compute the sum of the sizes of all files in `path'. */
void computePathSize(const Path & path,
unsigned long long & bytes, unsigned long long & blocks);

View File

@@ -251,14 +251,15 @@ static string optimisticLockProfile(const Path & profile)
}
static bool createUserEnv(EvalState & state, DrvInfos & elems,
static bool createUserEnv(EvalState & state, const DrvInfos & elems,
const Path & profile, bool keepDerivations,
const string & lockToken)
{
/* Build the components in the user environment, if they don't
exist already. */
PathSet drvsToBuild;
foreach (DrvInfos::const_iterator, i, elems)
for (DrvInfos::const_iterator i = elems.begin();
i != elems.end(); ++i)
/* Call to `isDerivation' is for compatibility with Nix <= 0.7
user environments. */
if (i->queryDrvPath(state) != "" &&
@@ -276,16 +277,19 @@ static bool createUserEnv(EvalState & state, DrvInfos & elems,
PathSet references;
ATermList manifest = ATempty;
ATermList inputs = ATempty;
foreach (DrvInfos::iterator, i, elems) {
for (DrvInfos::const_iterator i = elems.begin();
i != elems.end(); ++i)
{
/* Create a pseudo-derivation containing the name, system,
output path, and optionally the derivation path, as well as
the meta attributes. */
Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
/* Round trip to get rid of "bad" meta values (like
functions). */
MetaInfo meta = i->queryMetaInfo(state);
i->setMetaInfo(meta);
ATermList metaList = ATempty;
foreach (MetaInfo::iterator, j, meta)
metaList = ATinsert(metaList,
makeBind(toATerm(j->first), makeStr(j->second), makeNoPos()));
ATermList as = ATmakeList5(
makeBind(toATerm("type"),
@@ -296,8 +300,7 @@ static bool createUserEnv(EvalState & state, DrvInfos & elems,
makeStr(i->system), makeNoPos()),
makeBind(toATerm("outPath"),
makeStr(i->queryOutPath(state)), makeNoPos()),
makeBind(toATerm("meta"),
i->attrs->get(toATerm("meta")), makeNoPos()));
makeBind(toATerm("meta"), makeAttrs(metaList), makeNoPos()));
if (drvPath != "") as = ATinsert(as,
makeBind(toATerm("drvPath"),
@@ -358,23 +361,13 @@ static bool createUserEnv(EvalState & state, DrvInfos & elems,
}
static int getPriority(EvalState & state, const DrvInfo & drv)
{
MetaValue value = drv.queryMetaInfo(state, "priority");
int prio = 0;
if (value.type == MetaValue::tpInt) prio = value.intValue;
else if (value.type == MetaValue::tpString)
/* Backwards compatibility. Priorities used to be strings
before we had support for integer meta field. */
string2Int(value.stringValue, prio);
return prio;
}
static int comparePriorities(EvalState & state,
const DrvInfo & drv1, const DrvInfo & drv2)
{
return getPriority(state, drv2) - getPriority(state, drv1);
int prio1, prio2;
if (!string2Int(drv1.queryMetaInfo(state, "priority"), prio1)) prio1 = 0;
if (!string2Int(drv2.queryMetaInfo(state, "priority"), prio2)) prio2 = 0;
return prio2 - prio1; /* higher number = lower priority, so negate */
}
@@ -601,13 +594,6 @@ static void printMissing(EvalState & state, const DrvInfos & elems)
}
static bool keep(MetaInfo & meta)
{
MetaValue value = meta["keep"];
return value.type == MetaValue::tpString && value.stringValue == "true";
}
static void installDerivations(Globals & globals,
const Strings & args, const Path & profile)
{
@@ -642,7 +628,7 @@ static void installDerivations(Globals & globals,
MetaInfo meta = i->queryMetaInfo(globals.state);
if (!globals.preserveInstalled &&
newNames.find(drvName.name) != newNames.end() &&
!keep(meta))
meta["keep"] != "true")
printMsg(lvlInfo,
format("replacing old `%1%'") % i->name);
else
@@ -705,7 +691,7 @@ static void upgradeDerivations(Globals & globals,
DrvName drvName(i->name);
MetaInfo meta = i->queryMetaInfo(globals.state);
if (keep(meta)) {
if (meta["keep"] == "true") {
newElems.push_back(*i);
continue;
}
@@ -723,9 +709,9 @@ static void upgradeDerivations(Globals & globals,
if (newName.name == drvName.name) {
int d = comparePriorities(globals.state, *i, *j);
if (d == 0) d = compareVersions(drvName.version, newName.version);
if ((upgradeType == utLt && d < 0) ||
(upgradeType == utLeq && d <= 0) ||
(upgradeType == utEq && d == 0) ||
if (upgradeType == utLt && d < 0 ||
upgradeType == utLeq && d <= 0 ||
upgradeType == utEq && d == 0 ||
upgradeType == utAlways)
{
int d2 = -1;
@@ -784,10 +770,7 @@ static void setMetaFlag(EvalState & state, DrvInfo & drv,
const string & name, const string & value)
{
MetaInfo meta = drv.queryMetaInfo(state);
MetaValue v;
v.type = MetaValue::tpString;
v.stringValue = value;
meta[name] = v;
meta[name] = value;
drv.setMetaInfo(meta);
}
@@ -930,7 +913,7 @@ void printTable(Table & table)
vector<unsigned int> widths;
widths.resize(nrColumns);
foreach (Table::iterator, i, table) {
for (Table::iterator i = table.begin(); i != table.end(); ++i) {
assert(i->size() == nrColumns);
Strings::iterator j;
unsigned int column;
@@ -938,15 +921,14 @@ void printTable(Table & table)
if (j->size() > widths[column]) widths[column] = j->size();
}
foreach (Table::iterator, i, table) {
for (Table::iterator i = table.begin(); i != table.end(); ++i) {
Strings::iterator j;
unsigned int column;
for (j = i->begin(), column = 0; j != i->end(); ++j, ++column) {
string s = *j;
replace(s.begin(), s.end(), '\n', ' ');
cout << s;
for (j = i->begin(), column = 0; j != i->end(); ++j, ++column)
{
cout << *j;
if (column < nrColumns - 1)
cout << string(widths[column] - s.size() + 2, ' ');
cout << string(widths[column] - j->size() + 2, ' ');
}
cout << std::endl;
}
@@ -1093,7 +1075,9 @@ static void opQuery(Globals & globals,
XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
XMLOpenElement xmlRoot(xml, "items");
foreach (vector<DrvInfo>::iterator, i, elems2) {
for (vector<DrvInfo>::iterator i = elems2.begin();
i != elems2.end(); ++i)
{
try {
/* For table output. */
@@ -1180,8 +1164,7 @@ static void opQuery(Globals & globals,
if (printDescription) {
MetaInfo meta = i->queryMetaInfo(globals.state);
MetaValue value = meta["description"];
string descr = value.type == MetaValue::tpString ? value.stringValue : "";
string descr = meta["description"];
if (xmlOutput) {
if (descr != "") attrs["description"] = descr;
} else
@@ -1195,23 +1178,8 @@ static void opQuery(Globals & globals,
for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) {
XMLAttrs attrs2;
attrs2["name"] = j->first;
if (j->second.type == MetaValue::tpString) {
attrs2["type"] = "string";
attrs2["value"] = j->second.stringValue;
xml.writeEmptyElement("meta", attrs2);
} else if (j->second.type == MetaValue::tpInt) {
attrs2["type"] = "int";
attrs2["value"] = (format("%1%") % j->second.intValue).str();
xml.writeEmptyElement("meta", attrs2);
} else if (j->second.type == MetaValue::tpStrings) {
attrs2["type"] = "strings";
XMLOpenElement m(xml, "meta", attrs2);
foreach (Strings::iterator, k, j->second.stringValues) {
XMLAttrs attrs3;
attrs3["value"] = *k;
xml.writeEmptyElement("string", attrs3);
}
}
attrs2["value"] = j->second;
xml.writeEmptyElement("meta", attrs2);
}
}
else
@@ -1262,13 +1230,12 @@ static void switchGeneration(Globals & globals, int dstGen)
(dstGen >= 0 && i->number == dstGen))
dst = *i;
if (!dst) {
if (!dst)
if (dstGen == prevGen)
throw Error(format("no generation older than the current (%1%) exists")
% curGen);
else
throw Error(format("generation %1% does not exist") % dstGen);
}
printMsg(lvlInfo, format("switching from generation %1% to %2%")
% curGen % dst.number);

View File

@@ -34,8 +34,6 @@ struct Decoder
void pushChar(char c);
void finishLine();
void decodeFile(istream & st);
};
@@ -124,7 +122,6 @@ void Decoder::finishLine()
if (line[i] == '<') cout << "&lt;";
else if (line[i] == '&') cout << "&amp;";
else if (line[i] == '\r') ; /* ignore carriage return */
else if (line[i] < 32 && line[i] != 9) cout << "&#xfffd;";
else if (i + sz + 33 < line.size() &&
string(line, i, sz) == storeDir &&
@@ -161,26 +158,16 @@ void Decoder::finishLine()
}
void Decoder::decodeFile(istream & st)
{
int c;
cout << "<logfile>" << endl;
while ((c = st.get()) != EOF) {
pushChar(c);
}
if (line.size()) finishLine();
while (level--) cout << "</nest>" << endl;
cout << "</logfile>" << endl;
}
int main(int argc, char * * argv)
{
Decoder dec;
dec.decodeFile(cin);
int c;
cout << "<logfile>" << endl;
while ((c = getchar()) != EOF) {
dec.pushChar(c);
}
cout << "</logfile>" << endl;
}

View File

@@ -96,7 +96,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
if (isDerivation(*i)) drvPaths.insert(*i);
store->buildDerivations(drvPaths);
foreach (Strings::iterator, i, opArgs)
foreach (Strings::iterator, i,opArgs)
cout << format("%1%\n") % realisePath(*i);
}
@@ -125,11 +125,11 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
if (opArgs.empty())
throw UsageError("first argument must be hash algorithm");
HashType hashAlgo = parseHashType(opArgs.front());
string hashAlgo = opArgs.front();
opArgs.pop_front();
for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i)
cout << format("%1%\n") % store->addToStore(*i, recursive, hashAlgo);
cout << format("%1%\n") % store->addToStore(*i, true, recursive, hashAlgo);
}
@@ -151,17 +151,14 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
if (*i == "--recursive") recursive = true;
else throw UsageError(format("unknown flag `%1%'") % *i);
if (opArgs.size() != 3)
throw UsageError(format("`--print-fixed-path' requires three arguments"));
Strings::iterator i = opArgs.begin();
HashType hashAlgo = parseHashType(*i++);
string hashAlgo = *i++;
string hash = *i++;
string name = *i++;
cout << format("%1%\n") %
makeFixedOutputPath(recursive, hashAlgo,
parseHash16or32(hashAlgo, hash), name);
parseHash16or32(parseHashType(hashAlgo), hash), name);
}
@@ -531,10 +528,7 @@ static void opGC(Strings opFlags, Strings opArgs)
else if (*i == "--print-live") options.action = GCOptions::gcReturnLive;
else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead;
else if (*i == "--delete") options.action = GCOptions::gcDeleteDead;
else if (*i == "--max-freed") {
options.maxFreed = getIntArg(*i, i, opFlags.end());
if (options.maxFreed == 0) options.maxFreed = 1;
}
else if (*i == "--max-freed") options.maxFreed = getIntArg(*i, i, opFlags.end());
else if (*i == "--max-links") options.maxLinks = getIntArg(*i, i, opFlags.end());
else if (*i == "--use-atime") options.useAtime = true;
else if (*i == "--max-atime") {
@@ -620,19 +614,16 @@ static void opExport(Strings opFlags, Strings opArgs)
static void opImport(Strings opFlags, Strings opArgs)
{
bool requireSignature = false;
foreach (Strings::iterator, i, opFlags)
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--require-signature") requireSignature = true;
else throw UsageError(format("unknown flag `%1%'") % *i);
if (!opArgs.empty()) throw UsageError("no arguments expected");
FdSource source(STDIN_FILENO);
while (true) {
unsigned long long n = readLongLong(source);
if (n == 0) break;
if (n != 1) throw Error("input doesn't look like something created by `nix-store --export'");
while (readInt(source) == 1)
cout << format("%1%\n") % store->importPath(requireSignature, source) << std::flush;
}
}

View File

@@ -112,12 +112,12 @@ static void sigPollHandler(int sigNo)
_isInterrupted = 1;
blockInt = 1;
canSendStderr = false;
const char * s = "SIGPOLL\n";
write(STDERR_FILENO, s, strlen(s));
string s = "SIGPOLL\n";
write(STDERR_FILENO, s.c_str(), s.size());
}
} else {
const char * s = "spurious SIGPOLL\n";
write(STDERR_FILENO, s, strlen(s));
string s = "spurious SIGPOLL\n";
write(STDERR_FILENO, s.c_str(), s.size());
}
}
catch (Error & e) {
@@ -223,43 +223,6 @@ struct TunnelSource : Source
};
/* If the NAR archive contains a single file at top-level, then save
the contents of the file to `s'. Otherwise barf. */
struct RetrieveRegularNARSink : ParseSink
{
string s;
void createDirectory(const Path & path)
{
throw Error("regular file expected");
}
void receiveContents(unsigned char * data, unsigned int len)
{
s.append((const char *) data, len);
}
void createSymlink(const Path & path, const string & target)
{
throw Error("regular file expected");
}
};
/* Adapter class of a Source that saves all data read to `s'. */
struct SavingSourceAdapter : Source
{
Source & orig;
string s;
SavingSourceAdapter(Source & orig) : orig(orig) { }
void operator () (unsigned char * data, unsigned int len)
{
orig(data, len);
s.append((const char *) data, len);
}
};
static void performOp(unsigned int clientVersion,
Source & from, Sink & to, unsigned int op)
{
@@ -325,33 +288,19 @@ static void performOp(unsigned int clientVersion,
}
case wopAddToStore: {
/* !!! uberquick hack */
string baseName = readString(from);
bool fixed = readInt(from) == 1; /* obsolete */
bool fixed = readInt(from) == 1;
bool recursive = readInt(from) == 1;
string s = readString(from);
/* Compatibility hack. */
if (!fixed) {
s = "sha256";
recursive = true;
}
HashType hashAlgo = parseHashType(s);
SavingSourceAdapter savedNAR(from);
RetrieveRegularNARSink savedRegular;
string hashAlgo = readString(from);
if (recursive) {
/* Get the entire NAR dump from the client and save it to
a string so that we can pass it to
addToStoreFromDump(). */
ParseSink sink; /* null sink; just parse the NAR */
parseDump(sink, savedNAR);
} else {
parseDump(savedRegular, from);
}
Path tmp = createTempDir();
AutoDelete delTmp(tmp);
Path tmp2 = tmp + "/" + baseName;
restorePath(tmp2, from);
startWork();
Path path = dynamic_cast<LocalStore *>(store.get())
->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo);
Path path = store->addToStore(tmp2, fixed, recursive, hashAlgo);
stopWork();
writeString(path, to);
@@ -452,10 +401,6 @@ static void performOp(unsigned int clientVersion,
options.ignoreLiveness = readInt(from);
options.maxFreed = readLongLong(from);
options.maxLinks = readInt(from);
if (GET_PROTOCOL_MINOR(clientVersion) >= 5) {
options.useAtime = readInt(from);
options.maxAtime = readInt(from);
}
GCResults results;

View File

@@ -1,35 +1,46 @@
TESTS_ENVIRONMENT = $(bash) -e
TESTS_ENVIRONMENT = $(SHELL) -e
extra1 = $(shell pwd)/test-tmp/shared
simple.sh substitutes.sh substitutes2.sh fallback.sh: simple.nix
dependencies.sh gc.sh nix-push.sh nix-pull.in logging.sh nix-build.sh install-package.sh check-refs.sh: dependencies.nix
locking.sh: locking.nix
parallel.sh: parallel.nix
build-hook.sh: build-hook.nix
gc-concurrent.sh: gc-concurrent.nix gc-concurrent2.nix
user-envs.sh: user-envs.nix
fixed.sh: fixed.nix
gc-runtime.sh: gc-runtime.nix
check-refs.sh: check-refs.nix
filter-source.sh: filter-source.nix
TESTS = init.sh hash.sh lang.sh add.sh simple.sh dependencies.sh \
parallel.sh build-hook.sh substitutes.sh substitutes2.sh \
locking.sh parallel.sh build-hook.sh substitutes.sh substitutes2.sh \
fallback.sh nix-push.sh gc.sh gc-concurrent.sh verify.sh nix-pull.sh \
referrers.sh user-envs.sh logging.sh nix-build.sh misc.sh fixed.sh \
gc-runtime.sh install-package.sh check-refs.sh filter-source.sh \
remote-store.sh export.sh export-graph.sh negative-caching.sh
remote-store.sh export.sh
XFAIL_TESTS =
include ../substitute.mk
$(TESTS): common.sh config.nix
$(TESTS): common.sh
EXTRA_DIST = $(TESTS) \
config.nix.in \
simple.nix simple.builder.sh \
simple.nix.in simple.builder.sh \
hash-check.nix \
dependencies.nix dependencies.builder*.sh \
parallel.nix parallel.builder.sh \
build-hook.nix build-hook.hook.sh \
dependencies.nix.in dependencies.builder*.sh \
locking.nix.in locking.builder.sh \
parallel.nix.in parallel.builder.sh \
build-hook.nix.in build-hook.hook.sh \
substituter.sh substituter2.sh \
gc-concurrent.nix gc-concurrent.builder.sh gc-concurrent2.builder.sh \
user-envs.nix user-envs.builder.sh \
fixed.nix fixed.builder1.sh fixed.builder2.sh \
gc-runtime.nix \
check-refs.nix \
filter-source.nix \
export-graph.nix \
negative-caching.nix \
gc-concurrent.nix.in gc-concurrent.builder.sh \
gc-concurrent2.nix.in gc-concurrent2.builder.sh \
user-envs.nix.in user-envs.builder.sh \
fixed.nix.in fixed.builder1.sh fixed.builder2.sh \
gc-runtime.nix.in \
check-refs.nix.in \
filter-source.nix.in \
$(wildcard lang/*.nix) $(wildcard lang/*.exp) $(wildcard lang/*.exp.xml) $(wildcard lang/*.flags) \
common.sh.in

View File

@@ -1,28 +1,13 @@
source common.sh
path1=$($nixstore --add ./dummy)
echo $path1
file=./add.sh
path2=$($nixstore --add-fixed sha256 --recursive ./dummy)
echo $path2
path=$($nixstore --add $file)
if test "$path1" != "$path2"; then
echo "nix-store --add and --add-fixed mismatch"
exit 1
fi
echo $path
path3=$($nixstore --add-fixed sha256 ./dummy)
echo $path3
test "$path1" != "$path3" || exit 1
hash=$($nixstore -q --hash $path)
path4=$($nixstore --add-fixed sha1 --recursive ./dummy)
echo $path4
test "$path1" != "$path4" || exit 1
echo $hash
hash1=$($nixstore -q --hash $path1)
echo $hash1
hash2=$($nixhash --type sha256 --base32 ./dummy)
echo $hash2
test "$hash1" = "sha256:$hash2"
test "$hash" = "sha256:$($nixhash --type sha256 --base32 $file)"

View File

@@ -11,11 +11,11 @@ outPath=$(sed 's/Derive(\[("out",\"\([^\"]*\)\".*/\1/' $drv)
echo "output path is $outPath" >&2
if $(echo $outPath | grep -q input-1); then
echo "# accept" >&2
read x
echo "accept" >&3
read x <&4
echo "got $x"
mkdir $outPath
echo "BAR" > $outPath/foo
else
echo "# decline" >&2
echo "decline" >&3
fi

View File

@@ -1,21 +0,0 @@
with import ./config.nix;
let
input1 = mkDerivation {
name = "build-hook-input-1";
builder = ./dependencies.builder1.sh;
};
input2 = mkDerivation {
name = "build-hook-input-2";
builder = ./dependencies.builder2.sh;
};
in
mkDerivation {
name = "build-hook";
builder = ./dependencies.builder0.sh;
inherit input1 input2;
}

28
tests/build-hook.nix.in Normal file
View File

@@ -0,0 +1,28 @@
let {
input1 = derivation {
name = "build-hook-input-1";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder1.sh];
PATH = "@testPath@";
};
input2 = derivation {
name = "build-hook-input-2";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder2.sh];
PATH = "@testPath@";
};
body = derivation {
name = "build-hook";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder0.sh];
PATH = "@testPath@";
inherit input1 input2;
};
}

View File

@@ -2,7 +2,11 @@ source common.sh
export NIX_BUILD_HOOK="build-hook.hook.sh"
outPath=$($nixbuild build-hook.nix)
drvPath=$($nixinstantiate build-hook.nix)
echo "derivation is $drvPath"
outPath=$($nixstore -quf "$drvPath")
echo "output path is $outPath"

View File

@@ -1,58 +0,0 @@
with import ./config.nix;
rec {
dep = import ./dependencies.nix;
makeTest = nr: args: mkDerivation ({
name = "check-refs-" + toString nr;
} // args);
src = builtins.toFile "aux-ref" "bla bla";
test1 = makeTest 1 {
builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link";
inherit dep;
};
test2 = makeTest 2 {
builder = builtins.toFile "builder.sh" "mkdir $out; ln -s ${src} $out/link";
inherit dep;
};
test3 = makeTest 3 {
builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link";
allowedReferences = [];
inherit dep;
};
test4 = makeTest 4 {
builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link";
allowedReferences = [dep];
inherit dep;
};
test5 = makeTest 5 {
builder = builtins.toFile "builder.sh" "mkdir $out";
allowedReferences = [];
inherit dep;
};
test6 = makeTest 6 {
builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link";
allowedReferences = [];
inherit dep;
};
test7 = makeTest 7 {
builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link";
allowedReferences = ["out"];
inherit dep;
};
test8 = makeTest 8 {
builder = builtins.toFile "builder.sh" "mkdir $out; ln -s ${test1} $out/link";
inherit dep;
};
}

59
tests/check-refs.nix.in Normal file
View File

@@ -0,0 +1,59 @@
rec {
dep = import ./dependencies.nix;
makeTest = nr: args: derivation ({
name = "check-refs-" + toString nr;
system = "@system@";
builder = "@shell@";
PATH = "@testPath@";
} // args);
src = builtins.toFile "aux-ref" "bla bla";
test1 = makeTest 1 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link")];
inherit dep;
};
test2 = makeTest 2 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out; ln -s ${src} $out/link")];
inherit dep;
};
test3 = makeTest 3 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link")];
allowedReferences = [];
inherit dep;
};
test4 = makeTest 4 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link")];
allowedReferences = [dep];
inherit dep;
};
test5 = makeTest 5 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out")];
allowedReferences = [];
inherit dep;
};
test6 = makeTest 6 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link")];
allowedReferences = [];
inherit dep;
};
test7 = makeTest 7 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link")];
allowedReferences = ["out"];
inherit dep;
};
test8 = makeTest 8 {
args = ["-e" "-x" (builtins.toFile "builder.sh" "mkdir $out; ln -s ${test1} $out/link")];
inherit dep;
};
}

View File

@@ -39,11 +39,6 @@ export dot=@dot@
export xmllint="@xmllint@"
export xmlflags="@xmlflags@"
export xsltproc="@xsltproc@"
export SHELL="@shell@"
# Hack to get "atdiff" to run on Cygwin (Windows looks for
# DLLs in $PATH).
export PATH=$aterm_bin/../lib:$PATH
export version=@version@
export system=@system@
@@ -59,11 +54,6 @@ readLink() {
ls -l "$1" | sed 's/.*->\ //'
}
clearProfiles() {
profiles="$NIX_STATE_DIR"/profiles
rm -f $profiles/*
}
clearStore() {
echo "clearing store..."
chmod -R +w "$NIX_STORE_DIR"
@@ -72,16 +62,13 @@ clearStore() {
rm -rf "$NIX_DB_DIR"
mkdir "$NIX_DB_DIR"
$nixstore --init
clearProfiles
rm -f "$NIX_STATE_DIR"/gcroots/auto/*
rm -f "$NIX_STATE_DIR"/gcroots/ref
}
clearProfiles() {
profiles="$NIX_STATE_DIR"/profiles
rm -f $profiles/*
}
clearManifests() {
rm -f $NIX_STATE_DIR/manifests/*
}
fail() {
echo "$1"
exit 1
}

View File

@@ -1,17 +0,0 @@
rec {
shell = "@shell@";
path = "@testPath@";
system = "@system@";
shared = "@extra1@";
mkDerivation = args:
derivation ({
inherit system;
builder = shell;
args = ["-e" args.builder];
PATH = path;
} // removeAttrs args ["builder"]);
}

View File

@@ -5,5 +5,3 @@ ln -s $input2 $out/input-2
# Self-reference.
ln -s $out $out/self
echo FOO

View File

@@ -1,22 +0,0 @@
with import ./config.nix;
let {
input1 = mkDerivation {
name = "dependencies-input-1";
builder = ./dependencies.builder1.sh;
};
input2 = mkDerivation {
name = "dependencies-input-2";
builder = ./. ~ "dependencies.builder2.sh";
};
body = mkDerivation {
name = "dependencies";
builder = ./dependencies.builder0.sh + "/FOOBAR/../.";
input1 = input1 + "/.";
inherit input2;
};
}

29
tests/dependencies.nix.in Normal file
View File

@@ -0,0 +1,29 @@
let {
input1 = derivation {
name = "dependencies-input-1";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder1.sh];
PATH = "@testPath@";
};
input2 = derivation {
name = "dependencies-input-2";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" (./. ~ "dependencies.builder2.sh")];
PATH = "@testPath@";
};
body = derivation {
name = "dependencies";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" (./dependencies.builder0.sh + "/FOOBAR/../.")];
PATH = "@testPath@";
input1 = input1 + "/.";
inherit input2;
};
}

View File

@@ -1,7 +1,5 @@
source common.sh
clearStore
drvPath=$($nixinstantiate dependencies.nix)
echo "derivation is $drvPath"
@@ -15,7 +13,7 @@ if test -n "$dot"; then
$dot < $TEST_ROOT/graph
fi
outPath=$($nixstore -rvv "$drvPath") || fail "build failed"
outPath=$($nixstore -rvv "$drvPath")
# Test Graphviz graph generation.
$nixstore -q --graph "$outPath" > $TEST_ROOT/graph

View File

@@ -1,29 +0,0 @@
with import ./config.nix;
rec {
printRefs =
''
echo $exportReferencesGraph
while read path; do
read drv
read nrRefs
echo "$path has $nrRefs references"
echo "$path" >> $out
for ((n = 0; n < $nrRefs; n++)); do read ref; echo "ref $ref"; test -e "$ref"; done
done < refs
'';
runtimeGraph = mkDerivation {
name = "dependencies";
builder = builtins.toFile "build-graph-builder" "${printRefs}";
exportReferencesGraph = ["refs" (import ./dependencies.nix)];
};
buildGraph = mkDerivation {
name = "dependencies";
builder = builtins.toFile "build-graph-builder" "${printRefs}";
exportReferencesGraph = ["refs" (import ./dependencies.nix).drvPath];
};
}

View File

@@ -1,30 +0,0 @@
source common.sh
clearStore
clearProfiles
checkRef() {
$nixstore -q --references ./result | grep -q "$1" || fail "missing reference $1"
}
# Test the export of the runtime dependency graph.
outPath=$($nixbuild ./export-graph.nix -A runtimeGraph)
test $($nixstore -q --references ./result | wc -l) = 2 || fail "bad nr of references"
checkRef input-2
for i in $(cat $outPath); do checkRef $i; done
# Test the export of the build-time dependency graph.
$nixstore --gc # should force rebuild of input-1
outPath=$($nixbuild ./export-graph.nix -A buildGraph)
checkRef input-1
checkRef input-1.drv
checkRef input-2
checkRef input-2.drv
for i in $(cat $outPath); do checkRef $i; done

View File

@@ -2,7 +2,7 @@ source common.sh
clearStore
outPath=$($nixbuild dependencies.nix)
outPath=$($nixstore -r $($nixinstantiate dependencies.nix))
$nixstore --export $outPath > $TEST_ROOT/exp

View File

@@ -1,8 +1,8 @@
with import ./config.nix;
mkDerivation {
derivation {
name = "filter";
builder = builtins.toFile "builder" "ln -s $input $out";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" (builtins.toFile "builder" "PATH=@testPath@; ln -s $input $out")];
input =
let filter = path: type:
type != "symlink"

View File

@@ -1,13 +1,14 @@
with import ./config.nix;
rec {
f2 = dummy: builder: mode: algo: hash: mkDerivation {
f2 = dummy: builder: mode: algo: hash: derivation {
name = "fixed";
inherit builder;
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" builder];
outputHashMode = mode;
outputHashAlgo = algo;
outputHash = hash;
PATH = "@testPath@";
inherit dummy;
impureEnvVars = ["IMPURE_VAR1" "IMPURE_VAR2"];
};
@@ -19,6 +20,7 @@ rec {
(f ./fixed.builder1.sh "flat" "sha1" "a0b65939670bc2c010f4d5d6a0b3e4e4590fb92b")
(f ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42")
(f ./fixed.builder2.sh "recursive" "sha1" "vw46m23bizj4n8afrc0fj19wrp7mj3c0")
(f ./fixed.builder2.sh "recursive" "sha256" "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik")
];
good2 = [
@@ -28,9 +30,6 @@ rec {
(f ./fixed.builder2.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858")
];
sameAsAdd =
f ./fixed.builder2.sh "recursive" "sha256" "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik";
bad = [
(f ./fixed.builder1.sh "flat" "md5" "0ddd8be4b179a529afa5f2ffae4b9858")
];

View File

@@ -6,16 +6,22 @@ export IMPURE_VAR1=foo
export IMPURE_VAR2=bar
echo 'testing good...'
$nixbuild fixed.nix -A good
drvs=$($nixinstantiate fixed.nix -A good)
echo $drvs
$nixstore -r $drvs
echo 'testing good2...'
$nixbuild fixed.nix -A good2
drvs=$($nixinstantiate fixed.nix -A good2)
echo $drvs
$nixstore -r $drvs
echo 'testing bad...'
$nixbuild fixed.nix -A bad && fail "should fail"
drvs=$($nixinstantiate fixed.nix -A bad)
echo $drvs
if $nixstore -r $drvs; then false; fi
echo 'testing reallyBad...'
$nixinstantiate fixed.nix -A reallyBad && fail "should fail"
if $nixinstantiate fixed.nix -A reallyBad; then false; fi
# While we're at it, check attribute selection a bit more.
echo 'testing attribute selection...'
@@ -25,28 +31,6 @@ test $($nixinstantiate fixed.nix -A good.1 | wc -l) = 1
# Only one should run at the same time.
echo 'testing parallelSame...'
clearStore
$nixbuild fixed.nix -A parallelSame -j2
# Fixed-output derivations with a recursive SHA-256 hash should
# produce the same path as "nix-store --add".
echo 'testing sameAsAdd...'
out=$($nixbuild fixed.nix -A sameAsAdd)
# This is what fixed.builder2 produces...
rm -rf $TEST_ROOT/fixed
mkdir $TEST_ROOT/fixed
mkdir $TEST_ROOT/fixed/bla
echo "Hello World!" > $TEST_ROOT/fixed/foo
ln -s foo $TEST_ROOT/fixed/bar
out2=$($nixstore --add $TEST_ROOT/fixed)
echo $out2
test "$out" = "$out2" || exit 1
out3=$($nixstore --add-fixed --recursive sha256 $TEST_ROOT/fixed)
echo $out3
test "$out" = "$out3" || exit 1
out4=$($nixstore --print-fixed-path --recursive sha256 "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik" fixed)
echo $out4
test "$out" = "$out4" || exit 1
drvs=$($nixinstantiate fixed.nix -A parallelSame)
echo $drvs
$nixstore -r $drvs -j2

View File

@@ -1,27 +0,0 @@
with import ./config.nix;
rec {
input1 = mkDerivation {
name = "dependencies-input-1";
builder = ./dependencies.builder1.sh;
};
input2 = mkDerivation {
name = "dependencies-input-2";
builder = ./dependencies.builder2.sh;
};
test1 = mkDerivation {
name = "gc-concurrent";
builder = ./gc-concurrent.builder.sh;
inherit input1 input2;
};
test2 = mkDerivation {
name = "gc-concurrent2";
builder = ./gc-concurrent2.builder.sh;
inherit input1 input2;
};
}

View File

@@ -0,0 +1,28 @@
let {
input1 = derivation {
name = "dependencies-input-1";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder1.sh];
PATH = "@testPath@";
};
input2 = derivation {
name = "dependencies-input-2";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder2.sh];
PATH = "@testPath@";
};
body = derivation {
name = "gc-concurrent";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./gc-concurrent.builder.sh];
PATH = "@testPath@";
inherit input1 input2;
};
}

View File

@@ -1,34 +1,27 @@
source common.sh
clearStore
$NIX_BIN_DIR/nix-collect-garbage -vvvvv
drvPath1=$($nixinstantiate gc-concurrent.nix -A test1)
drvPath1=$($nixinstantiate gc-concurrent.nix)
outPath1=$($nixstore -q $drvPath1)
drvPath2=$($nixinstantiate gc-concurrent.nix -A test2)
drvPath2=$($nixinstantiate gc-concurrent2.nix)
outPath2=$($nixstore -q $drvPath2)
drvPath3=$($nixinstantiate simple.nix)
outPath3=$($nixstore -r $drvPath3)
! test -e $outPath3.lock
touch $outPath3.lock
rm -f "$NIX_STATE_DIR"/gcroots/foo*
rm -f "$NIX_STATE_DIR"/gcroots/foo
ln -s $drvPath2 "$NIX_STATE_DIR"/gcroots/foo
ln -s $outPath3 "$NIX_STATE_DIR"/gcroots/foo2
# Start build #1 in the background. It starts immediately.
$nixstore -rvv "$drvPath1" &
pid1=$!
# Start build #2 in the background after 10 seconds.
(sleep 10 && $nixstore -rvv "$drvPath2") &
# Start build #2 in the background after 6 seconds.
(sleep 6 && $nixstore -rvv "$drvPath2") &
pid2=$!
# Run the garbage collector while the build is running.
sleep 6
$NIX_BIN_DIR/nix-collect-garbage
sleep 4
$NIX_BIN_DIR/nix-collect-garbage -vvvvv
# Wait for build #1/#2 to finish.
echo waiting for pid $pid1 to finish...
@@ -46,13 +39,4 @@ cat $outPath1/input-2/bar
# derivation is a GC root.
cat $outPath2/foobar
rm -f "$NIX_STATE_DIR"/gcroots/foo*
# The collector should have deleted lock files for paths that have
# been built previously.
! test -e $outPath3.lock
# If we run the collector now, it should delete outPath1/2.
$NIX_BIN_DIR/nix-collect-garbage
! test -e $outPath1
! test -e $outPath2
rm "$NIX_STATE_DIR"/gcroots/foo

View File

@@ -0,0 +1,28 @@
let {
input1 = derivation {
name = "dependencies-input-1";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder1.sh];
PATH = "@testPath@";
};
input2 = derivation {
name = "dependencies-input-2";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./dependencies.builder2.sh];
PATH = "@testPath@";
};
body = derivation {
name = "gc-concurrent2";
system = "@system@";
builder = "@shell@";
args = ["-e" "-x" ./gc-concurrent2.builder.sh];
PATH = "@testPath@";
inherit input1 input2;
};
}

View File

@@ -1,17 +0,0 @@
with import ./config.nix;
mkDerivation {
name = "gc-runtime";
builder =
# Test inline source file definitions.
builtins.toFile "builder.sh" ''
mkdir $out
cat > $out/program <<EOF
#! ${shell}
sleep 10000
EOF
chmod +x $out/program
'';
}

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