Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e85d1b5ba | ||
|
|
3a0cc43ac8 | ||
|
|
be0b9dda31 | ||
|
|
78206f06ec | ||
|
|
2ee9da9e22 | ||
|
|
6eba05613a | ||
|
|
7a03cbf09d | ||
|
|
69b8f9980f | ||
|
|
e93acab852 | ||
|
|
806970349b | ||
|
|
ea019e9a26 | ||
|
|
cc837e2458 | ||
|
|
28034bfa49 | ||
|
|
93f4fa8a15 | ||
|
|
c51b6a893c | ||
|
|
e6c44d166a | ||
|
|
7391533ea5 | ||
|
|
5cc2fc46ec | ||
|
|
3628b61ce0 | ||
|
|
470553bd05 | ||
|
|
4ddd077bfa | ||
|
|
0374d94437 | ||
|
|
00f698eb8b | ||
|
|
938092a213 | ||
|
|
772b70952f | ||
|
|
f9974f856e | ||
|
|
6955d41f2b | ||
|
|
934cf2d1f4 | ||
|
|
08d96ffad0 | ||
|
|
a9b4e26b5c | ||
|
|
c642441beb | ||
|
|
05420e7883 | ||
|
|
258897c265 | ||
|
|
239841787b | ||
|
|
cc63db1dd5 | ||
|
|
2c9cf50746 | ||
|
|
c3fc60d936 | ||
|
|
f72ed36025 | ||
|
|
78d777ca15 | ||
|
|
a68ebf8e37 | ||
|
|
804709706c | ||
|
|
c56bc3d81c | ||
|
|
4b07476848 | ||
|
|
bdd4646338 | ||
|
|
e73d9e9488 | ||
|
|
28bba8c44f | ||
|
|
8057a192e3 | ||
|
|
9fa1bee575 | ||
|
|
f45c731cd7 | ||
|
|
88936411bc | ||
|
|
0111ba98ea | ||
|
|
b008674e46 | ||
|
|
826dc0d07d | ||
|
|
97c6009c47 |
@@ -106,6 +106,7 @@ AC_LANG_POP(C++)
|
||||
# Check for chroot support (requires chroot() and bind mounts).
|
||||
AC_CHECK_FUNCS([chroot])
|
||||
AC_CHECK_FUNCS([unshare])
|
||||
AC_CHECK_FUNCS([statvfs])
|
||||
AC_CHECK_HEADERS([sched.h])
|
||||
AC_CHECK_HEADERS([sys/param.h])
|
||||
AC_CHECK_HEADERS([sys/mount.h], [], [],
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
To produce a `stable' release from the trunk:
|
||||
|
||||
-1. Update the release notes; make sure that the release date is
|
||||
correct.
|
||||
|
||||
0. Make sure that the trunk builds in the release supervisor.
|
||||
|
||||
1. Branch the trunk, e.g., `svn cp .../trunk
|
||||
.../branches/0.5-release'.
|
||||
|
||||
2. Switch to the branch, e.g., `svn switch .../branches/0.5-release'.
|
||||
|
||||
3. In `configure.ac', change `STABLE=0' into `STABLE=1' and commit.
|
||||
|
||||
4. In the release supervisor, add a one-time job to build
|
||||
`.../branches/0.5-release'.
|
||||
|
||||
5. Make sure that the release succeeds.
|
||||
|
||||
6. Move the branch to a tag, e.g., `svn mv .../branches/0.5-release
|
||||
.../tags/0.5'.
|
||||
|
||||
Note that the branch should not be used for maintenance; it should
|
||||
be deleted after the release has been created. A maintenance
|
||||
branch (e.g., `.../branches/0.5') should be created from the
|
||||
original revision of the trunk (since maintenance releases should
|
||||
also be tested first; hence, we cannot have `STABLE=1'). The same
|
||||
procedure can then be followed to produce maintenance releases;
|
||||
just substitute `.../branches/VERSION' for the trunk.
|
||||
|
||||
7. Switch back to the trunk.
|
||||
|
||||
8. Bump the version number in `configure.ac' (in AC_INIT).
|
||||
@@ -350,13 +350,25 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
|
||||
whitespace. These are not used by default, but can be enabled by
|
||||
users of the Nix daemon by specifying <literal>--option
|
||||
binary-caches <replaceable>urls</replaceable></literal> on the
|
||||
command line. Daemon users are only allowed to pass a subset of
|
||||
the URLs listed in <literal>binary-caches</literal> and
|
||||
command line. Unprivileged users are only allowed to pass a
|
||||
subset of the URLs listed in <literal>binary-caches</literal> and
|
||||
<literal>trusted-binary-caches</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>extra-binary-caches</literal></term>
|
||||
|
||||
<listitem><para>Additional binary caches appended to those
|
||||
specified in <option>binary-caches</option> and
|
||||
<option>binary-caches-files</option>. When used by unprivileged
|
||||
users, untrusted binary caches (i.e. those not listed in
|
||||
<option>trusted-binary-caches</option>) are silently
|
||||
ignored.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>binary-caches-parallel-connections</literal></term>
|
||||
|
||||
<listitem><para>The maximum number of parallel HTTP connections
|
||||
|
||||
@@ -166,11 +166,10 @@ a source distribution.</para>
|
||||
|
||||
<listitem><para>Recent versions of Bison and Flex to build the
|
||||
parser. (This is because Nix needs GLR support in Bison and
|
||||
reentrancy support in Flex.) For Bison, you need version 2.3 or
|
||||
higher (1.875 does <emphasis>not</emphasis> work), which can be
|
||||
obtained from the <link
|
||||
reentrancy support in Flex.) For Bison, you need version 2.6, which
|
||||
can be obtained from the <link
|
||||
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP
|
||||
server</link>. For Flex, you need version 2.5.33, which is
|
||||
server</link>. For Flex, you need version 2.5.35, which is
|
||||
available on <link
|
||||
xlink:href="http://lex.sourceforge.net/">SourceForge</link>.
|
||||
Slightly older versions may also work, but ancient versions like the
|
||||
|
||||
@@ -17,6 +17,7 @@ distributions using the regular sequence:
|
||||
|
||||
<screen>
|
||||
$ tar xvfj nix-<replaceable>version</replaceable>.tar.bz2
|
||||
$ cd nix-<replaceable>version</replaceable>
|
||||
$ ./configure
|
||||
$ make
|
||||
$ make install <lineannotation>(as root)</lineannotation></screen>
|
||||
|
||||
@@ -6,6 +6,36 @@
|
||||
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-1.5.2"><title>Release 1.5.2 (May 13, 2013)</title>
|
||||
|
||||
<para>This is primarily a bug fix release. It has contributions from
|
||||
Eelco Dolstra, Lluís Batlle i Rossell and Shea Levy.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-1.5.1"><title>Release 1.5.1 (February 28, 2013)</title>
|
||||
|
||||
<para>The bug fix to the bug fix had a bug itself, of course. But
|
||||
this time it will work for sure!</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-1.5"><title>Release 1.5 (February 27, 2013)</title>
|
||||
|
||||
<para>This is a brown paper bag release to fix a regression introduced
|
||||
by the hard link security fix in 1.4.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-1.4"><title>Release 1.4 (February 26, 2013)</title>
|
||||
|
||||
@@ -3,16 +3,13 @@ package Nix::CopyClosure;
|
||||
use strict;
|
||||
use Nix::Config;
|
||||
use Nix::Store;
|
||||
use List::Util qw(sum);
|
||||
|
||||
|
||||
sub copyTo {
|
||||
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor,
|
||||
$includeOutputs, $dryRun, $sign, $progressViewer, $useSubstitutes) = @_;
|
||||
|
||||
$compressor = "$compressor |" if $compressor ne "";
|
||||
$decompressor = "$decompressor |" if $decompressor ne "";
|
||||
$progressViewer = "$progressViewer |" if $progressViewer ne "";
|
||||
|
||||
# Get the closure of this path.
|
||||
my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,
|
||||
map { followLinksToStorePath $_ } @{$storePaths})));
|
||||
@@ -28,21 +25,28 @@ sub copyTo {
|
||||
# we'll want to use ‘--from-stdin’, but we can't rely on the
|
||||
# target having this option yet.
|
||||
my @missing = ();
|
||||
my $missingSize = 0;
|
||||
while (scalar(@closure) > 0) {
|
||||
my @ps = splice(@closure, 0, 1500);
|
||||
open(READ, "set -f; ssh $sshHost @{$sshOpts} nix-store --check-validity --print-invalid @ps|");
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
push @missing, $_;
|
||||
my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($_, 1);
|
||||
$missingSize += $narSize;
|
||||
}
|
||||
close READ or die;
|
||||
}
|
||||
|
||||
$compressor = "$compressor |" if $compressor ne "";
|
||||
$decompressor = "$decompressor |" if $decompressor ne "";
|
||||
$progressViewer = "$progressViewer -s $missingSize |" if $progressViewer ne "";
|
||||
|
||||
# Export the store paths and import them on the remote machine.
|
||||
if (scalar @missing > 0) {
|
||||
print STDERR "copying ", scalar @missing, " missing paths to ‘$sshHost’...\n";
|
||||
unless ($dryRun) {
|
||||
open SSH, "| $compressor $progressViewer ssh $sshHost @{$sshOpts} '$decompressor nix-store --import' > /dev/null" or die;
|
||||
open SSH, "| $progressViewer $compressor ssh $sshHost @{$sshOpts} '$decompressor nix-store --import' > /dev/null" or die;
|
||||
exportPaths(fileno(SSH), $sign, @missing);
|
||||
close SSH or die "copying store paths to remote machine `$sshHost' failed: $?";
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ sub closeSSHConnection {
|
||||
if ($sshStarted) {
|
||||
system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0
|
||||
or warn "unable to stop SSH master: $?";
|
||||
$sshStarted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -42,50 +42,50 @@ if ($Nix::Config::useBindings) {
|
||||
use File::Temp;
|
||||
use Fcntl qw/F_SETFD/;
|
||||
|
||||
sub hashFile {
|
||||
*hashFile = sub {
|
||||
my ($algo, $base32, $path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
};
|
||||
|
||||
sub hashPath {
|
||||
*hashPath = sub {
|
||||
my ($algo, $base32, $path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
};
|
||||
|
||||
sub hashString {
|
||||
*hashString = sub {
|
||||
my ($algo, $base32, $s) = @_;
|
||||
my $fh = File::Temp->new();
|
||||
print $fh $s;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
};
|
||||
|
||||
sub addToStore {
|
||||
*addToStore = sub {
|
||||
my ($srcPath, $recursive, $algo) = @_;
|
||||
die "not implemented" if $recursive || $algo ne "sha256";
|
||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
};
|
||||
|
||||
sub isValidPath {
|
||||
*isValidPath = sub {
|
||||
my ($path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);
|
||||
chomp $res;
|
||||
return $res ne $path;
|
||||
}
|
||||
};
|
||||
|
||||
sub queryPathHash {
|
||||
*queryPathHash = sub {
|
||||
my ($path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
+27
-20
@@ -1,15 +1,19 @@
|
||||
{ nixpkgs ? <nixpkgs>
|
||||
, nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
|
||||
{ nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
|
||||
, officialRelease ? false
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
pkgs = import <nixpkgs> {};
|
||||
|
||||
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "x86_64-freebsd" "i686-freebsd" "i686-cygwin" "i686-solaris" ];
|
||||
|
||||
|
||||
jobs = rec {
|
||||
|
||||
|
||||
tarball =
|
||||
with import nixpkgs {};
|
||||
with pkgs;
|
||||
|
||||
releaseTools.sourceTarball {
|
||||
name = "nix-tarball";
|
||||
@@ -19,7 +23,7 @@ let
|
||||
inherit officialRelease;
|
||||
|
||||
buildInputs =
|
||||
[ curl bison25 flex2535 perl libxml2 libxslt w3m bzip2
|
||||
[ curl bison flex2535 perl libxml2 libxslt w3m bzip2
|
||||
tetex dblatex nukeReferences pkgconfig sqlite git
|
||||
];
|
||||
|
||||
@@ -72,10 +76,9 @@ let
|
||||
};
|
||||
|
||||
|
||||
build =
|
||||
{ system ? "x86_64-linux" }:
|
||||
build = pkgs.lib.genAttrs systems (system:
|
||||
|
||||
with import nixpkgs { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
releaseTools.nixBuild {
|
||||
name = "nix";
|
||||
@@ -99,15 +102,15 @@ let
|
||||
installFlags = "sysconfdir=$(out)/etc";
|
||||
|
||||
doInstallCheck = true;
|
||||
};
|
||||
});
|
||||
|
||||
binaryTarball =
|
||||
{ system ? "x86_64-linux" }:
|
||||
|
||||
with import nixpkgs { inherit system; };
|
||||
binaryTarball = pkgs.lib.genAttrs systems (system:
|
||||
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
let
|
||||
toplevel = build { inherit system; };
|
||||
toplevel = builtins.getAttr system jobs.build;
|
||||
version = toplevel.src.version;
|
||||
in
|
||||
|
||||
@@ -130,11 +133,11 @@ let
|
||||
--transform "s,$TMPDIR/install,/usr/bin/nix-finish-install," \
|
||||
--transform "s,$TMPDIR/reginfo,/nix/store/reginfo," \
|
||||
$TMPDIR/install $TMPDIR/reginfo $storePaths
|
||||
'';
|
||||
'');
|
||||
|
||||
|
||||
coverage =
|
||||
with import nixpkgs { system = "x86_64-linux"; };
|
||||
with import <nixpkgs> { system = "x86_64-linux"; };
|
||||
|
||||
releaseTools.coverageAnalysis {
|
||||
name = "nix-build";
|
||||
@@ -166,14 +169,16 @@ let
|
||||
};
|
||||
|
||||
|
||||
rpm_fedora13i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora13i386) 50;
|
||||
rpm_fedora13x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora13x86_64) 50;
|
||||
rpm_fedora16i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora16i386) 50;
|
||||
rpm_fedora16x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora16x86_64) 50;
|
||||
rpm_fedora18i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora18i386) 60;
|
||||
rpm_fedora18x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora18x86_64) 60;
|
||||
|
||||
|
||||
deb_debian60i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian60i386) 50;
|
||||
deb_debian60x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian60x86_64) 50;
|
||||
deb_debian70i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian70i386) 60;
|
||||
deb_debian70x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian70x86_64) 60;
|
||||
|
||||
deb_ubuntu1004i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1004i386) 50;
|
||||
deb_ubuntu1004x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1004x86_64) 50;
|
||||
@@ -185,15 +190,17 @@ let
|
||||
deb_ubuntu1204x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1204x86_64) 60;
|
||||
deb_ubuntu1210i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1210i386) 70;
|
||||
deb_ubuntu1210x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1210x86_64) 70;
|
||||
deb_ubuntu1304i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1304i386) 80;
|
||||
deb_ubuntu1304x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1304x86_64) 80;
|
||||
|
||||
|
||||
# System tests.
|
||||
tests.remote_builds = (import ./tests/remote-builds.nix rec {
|
||||
nix = build { inherit system; }; system = "x86_64-linux";
|
||||
nix = build.x86_64-linux; system = "x86_64-linux";
|
||||
}).test;
|
||||
|
||||
tests.nix_copy_closure = (import ./tests/nix-copy-closure.nix rec {
|
||||
nix = build { inherit system; }; system = "x86_64-linux";
|
||||
nix = build.x86_64-linux; system = "x86_64-linux";
|
||||
}).test;
|
||||
|
||||
};
|
||||
@@ -205,7 +212,7 @@ let
|
||||
makeRPM =
|
||||
system: diskImageFun: prio:
|
||||
|
||||
with import nixpkgs { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
releaseTools.rpmBuild rec {
|
||||
name = "nix-rpm";
|
||||
@@ -224,7 +231,7 @@ let
|
||||
makeDeb =
|
||||
system: diskImageFun: prio:
|
||||
|
||||
with import nixpkgs { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
releaseTools.debBuild {
|
||||
name = "nix-deb";
|
||||
|
||||
@@ -46,7 +46,7 @@ sub all { $_ || return 0 for @_; 1 }
|
||||
# Initialisation.
|
||||
my $loadIncreased = 0;
|
||||
|
||||
my ($localSystem, $maxSilentTime, $printBuildTrace, $buildTimeout) = @ARGV;
|
||||
my ($localSystem, $printBuildTrace) = @ARGV;
|
||||
|
||||
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
|
||||
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
|
||||
@@ -195,7 +195,10 @@ REQ: while (1) {
|
||||
# Connect to the selected machine.
|
||||
@sshOpts = ("-i", $machine->{sshKeys}, "-x");
|
||||
$hostName = $machine->{hostName};
|
||||
last REQ if openSSHConnection $hostName;
|
||||
if (openSSHConnection($hostName)) {
|
||||
last REQ if system("ssh $hostName @sshOpts nix-builds-inhibited < /dev/null > /dev/null 2>&1") != 0;
|
||||
closeSSHConnection;
|
||||
}
|
||||
|
||||
warn "unable to open SSH connection to $hostName, trying other available machines...\n";
|
||||
$machine->{enabled} = 0;
|
||||
@@ -258,8 +261,7 @@ close UPLOADLOCK;
|
||||
|
||||
# Perform the build.
|
||||
my $buildFlags =
|
||||
"--max-silent-time $maxSilentTime --option build-timeout $buildTimeout"
|
||||
. " --fallback --add-root $rootsDir/\$PPID.out --quiet"
|
||||
" --fallback --add-root $rootsDir/\$PPID.out --quiet"
|
||||
. " --option build-keep-log false";
|
||||
|
||||
# We let the remote side kill its process group when the connection is
|
||||
@@ -270,7 +272,7 @@ my $buildFlags =
|
||||
# in which case every child receives SIGHUP; however, `-tt' doesn't
|
||||
# work on some platforms when connection sharing is used.)
|
||||
pipe STDIN, DUMMY; # make sure we have a readable STDIN
|
||||
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
|
||||
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & exec nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
|
||||
# Note that if we get exit code 100 from `nix-store -r', it
|
||||
# denotes a permanent build failure (as opposed to an SSH problem
|
||||
# or a temporary Nix problem). We propagate this to the caller to
|
||||
|
||||
@@ -27,6 +27,8 @@ my $didExpiration = 0;
|
||||
my $debug = ($ENV{"NIX_DEBUG_SUBST"} // "") eq 1;
|
||||
open(STDERR, ">>/dev/tty") if $debug;
|
||||
|
||||
my $cacheFileURLs = ($ENV{"_NIX_CACHE_FILE_URLS"} // "") eq 1; # for testing
|
||||
|
||||
my ($dbh, $queryCache, $insertNAR, $queryNAR, $insertNARExistence, $queryNARExistence, $expireNARExistence);
|
||||
|
||||
my $curlm = WWW::Curl::Multi->new;
|
||||
@@ -206,12 +208,15 @@ sub getAvailableCaches {
|
||||
push @urls, strToList($url);
|
||||
}
|
||||
|
||||
push @urls, strToList($Nix::Config::config{"extra-binary-caches"} // "");
|
||||
|
||||
# Allow Nix daemon users to override the binary caches to a subset
|
||||
# of those listed in the config file. Note that ‘untrusted-*’
|
||||
# denotes options passed by the client.
|
||||
my @trustedUrls = uniq(@urls, strToList($Nix::Config::config{"trusted-binary-caches"} // ""));
|
||||
|
||||
if (defined $Nix::Config::config{"untrusted-binary-caches"}) {
|
||||
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-binary-caches"};
|
||||
my @trustedUrls = uniq(@urls, strToList($Nix::Config::config{"trusted-binary-caches"} // ""));
|
||||
@urls = ();
|
||||
foreach my $url (@untrustedUrls) {
|
||||
die "binary cache ‘$url’ is not trusted (please add it to ‘trusted-binary-caches’ [@trustedUrls] in $Nix::Config::confDir/nix.conf)\n"
|
||||
@@ -220,6 +225,12 @@ sub getAvailableCaches {
|
||||
}
|
||||
}
|
||||
|
||||
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-extra-binary-caches"};
|
||||
foreach my $url (@untrustedUrls) {
|
||||
next unless scalar(grep { $url eq $_ } @trustedUrls) > 0;
|
||||
push @urls, $url;
|
||||
}
|
||||
|
||||
foreach my $url (uniq @urls) {
|
||||
|
||||
# FIXME: not atomic.
|
||||
@@ -267,6 +278,12 @@ sub getAvailableCaches {
|
||||
}
|
||||
|
||||
|
||||
sub shouldCache {
|
||||
my ($url) = @_;
|
||||
return $cacheFileURLs || $url !~ /^file:/;
|
||||
}
|
||||
|
||||
|
||||
sub processNARInfo {
|
||||
my ($storePath, $cache, $request) = @_;
|
||||
|
||||
@@ -276,7 +293,7 @@ sub processNARInfo {
|
||||
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
|
||||
} else {
|
||||
$insertNARExistence->execute($cache->{id}, basename($storePath), 0, time())
|
||||
unless $request->{url} =~ /^file:/;
|
||||
if shouldCache $request->{url};
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
@@ -289,7 +306,7 @@ sub processNARInfo {
|
||||
$cache->{id}, basename($storePath), $narInfo->{url}, $narInfo->{compression},
|
||||
$narInfo->{fileHash}, $narInfo->{fileSize}, $narInfo->{narHash}, $narInfo->{narSize},
|
||||
join(" ", @{$narInfo->{refs}}), $narInfo->{deriver}, $narInfo->{system}, time())
|
||||
unless $request->{url} =~ /^file:/;
|
||||
if shouldCache $request->{url};
|
||||
|
||||
return $narInfo;
|
||||
}
|
||||
@@ -455,12 +472,12 @@ sub printSubstitutablePaths {
|
||||
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
|
||||
} else {
|
||||
$insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 0, time())
|
||||
unless $request->{url} =~ /^file:/;
|
||||
if shouldCache $request->{url};
|
||||
}
|
||||
push @left2, $request->{storePath};
|
||||
} else {
|
||||
$insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 1, time())
|
||||
unless $request->{url} =~ /^file:/;
|
||||
if shouldCache $request->{url};
|
||||
print "$request->{storePath}\n";
|
||||
}
|
||||
}
|
||||
@@ -508,6 +525,7 @@ sub downloadBinary {
|
||||
}
|
||||
|
||||
print STDERR "could not download ‘$storePath’ from any binary cache\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#! @perl@ -w
|
||||
#! @perl@ -w @perlFlags@
|
||||
|
||||
use strict;
|
||||
|
||||
my $procDir = "/proc";
|
||||
use Nix::Utils;
|
||||
use Nix::Config;
|
||||
|
||||
|
||||
sub readProc {
|
||||
return unless -d $procDir;
|
||||
return unless -d "/proc";
|
||||
|
||||
opendir DIR, $procDir or return;
|
||||
opendir DIR, "/proc" or return;
|
||||
|
||||
foreach my $name (readdir DIR) {
|
||||
next unless $name =~ /^\d+$/;
|
||||
|
||||
my $process = "$procDir/$name";
|
||||
my $process = "/proc/$name";
|
||||
|
||||
#print STDERR "=== $process\n";
|
||||
|
||||
@@ -36,6 +36,13 @@ sub readProc {
|
||||
}
|
||||
close MAP;
|
||||
}
|
||||
|
||||
# Get all store paths that appear in the environment of this process.
|
||||
eval {
|
||||
my $env = Nix::Utils::readFile "$process/environ";
|
||||
my @matches = $env =~ /\Q$Nix::Config::storeDir\E\/[0-9a-z]+[0-9a-zA-Z\+\-\._\?=]*/g;
|
||||
print "$_\n" foreach @matches;
|
||||
}
|
||||
}
|
||||
|
||||
closedir DIR;
|
||||
@@ -58,18 +65,15 @@ readProc;
|
||||
lsof;
|
||||
|
||||
|
||||
sub readFile {
|
||||
my $path = shift;
|
||||
if (-e $path) {
|
||||
if (open FILE, "$path") {
|
||||
while (<FILE>) {
|
||||
print;
|
||||
}
|
||||
close FILE;
|
||||
}
|
||||
sub printFile {
|
||||
my ($fn) = @_;
|
||||
if (-e $fn) {
|
||||
print Nix::Utils::readFile($fn), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# This is rather NixOS-specific, so it probably shouldn't be here.
|
||||
readFile "/proc/sys/kernel/modprobe";
|
||||
readFile "/proc/sys/kernel/fbsplash";
|
||||
printFile "/proc/sys/kernel/modprobe";
|
||||
printFile "/proc/sys/kernel/fbsplash";
|
||||
printFile "/proc/sys/kernel/poweroff_cmd";
|
||||
|
||||
@@ -87,7 +87,7 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
|
||||
$n += 2;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type" or $arg eq "--cores") {
|
||||
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type" or $arg eq "--cores" or $arg eq "--timeout") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
push @buildArgs, ($arg, $ARGV[$n]);
|
||||
|
||||
@@ -4,6 +4,7 @@ use Nix::SSH;
|
||||
use Nix::Config;
|
||||
use Nix::Store;
|
||||
use Nix::CopyClosure;
|
||||
use List::Util qw(sum);
|
||||
|
||||
|
||||
if (scalar @ARGV < 1) {
|
||||
@@ -77,6 +78,8 @@ while (@ARGV) {
|
||||
}
|
||||
}
|
||||
|
||||
die "$0: you did not specify a host name\n" unless defined $sshHost;
|
||||
|
||||
|
||||
openSSHConnection $sshHost or die "$0: unable to start SSH\n";
|
||||
|
||||
@@ -104,6 +107,11 @@ else { # Copy FROM the remote machine.
|
||||
|
||||
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
|
||||
|
||||
my $missingSize = 0;
|
||||
if ($progressViewer ne "") {
|
||||
$missingSize = sum (split ' ', `set -f; ssh @sshOpts $sshHost nix-store -q --size @missing`) or die;
|
||||
}
|
||||
|
||||
# Export the store paths on the remote machine and import them locally.
|
||||
if (scalar @missing > 0) {
|
||||
print STDERR "copying ", scalar @missing, " missing paths from ‘$sshHost’...\n";
|
||||
@@ -113,9 +121,9 @@ else { # Copy FROM the remote machine.
|
||||
}
|
||||
$compressor = "| $compressor" if $compressor ne "";
|
||||
$decompressor = "$decompressor |" if $decompressor ne "";
|
||||
$progressViewer = "$progressViewer |" if $progressViewer ne "";
|
||||
$progressViewer = "$progressViewer -s $missingSize |" if $progressViewer ne "";
|
||||
my $extraOpts = $sign ? "--sign" : "";
|
||||
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $progressViewer $decompressor $Nix::Config::binDir/nix-store --import > /dev/null") == 0
|
||||
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor $progressViewer $Nix::Config::binDir/nix-store --import > /dev/null") == 0
|
||||
or die "copying store paths from remote machine `$sshHost' failed: $?";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,16 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
|
||||
void EvalState::forceValue(Value & v)
|
||||
{
|
||||
if (v.type == tThunk) {
|
||||
ValueType saved = v.type;
|
||||
Env * env = v.thunk.env;
|
||||
Expr * expr = v.thunk.expr;
|
||||
try {
|
||||
v.type = tBlackhole;
|
||||
//checkInterrupt();
|
||||
v.thunk.expr->eval(*this, *v.thunk.env, v);
|
||||
expr->eval(*this, *env, v);
|
||||
} catch (Error & e) {
|
||||
v.type = saved;
|
||||
v.type = tThunk;
|
||||
v.thunk.env = env;
|
||||
v.thunk.expr = expr;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
%{
|
||||
#include "nixexpr.hh"
|
||||
#define BISON_HEADER_HACK
|
||||
#include "parser-tab.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
%error-verbose
|
||||
%defines
|
||||
/* %no-lines */
|
||||
%parse-param { yyscan_t scanner }
|
||||
%parse-param { ParseData * data }
|
||||
%lex-param { yyscan_t scanner }
|
||||
%lex-param { ParseData * data }
|
||||
%parse-param { void * scanner }
|
||||
%parse-param { nix::ParseData * data }
|
||||
%lex-param { void * scanner }
|
||||
%lex-param { nix::ParseData * data }
|
||||
%expect 1
|
||||
%expect-rr 1
|
||||
|
||||
@@ -52,7 +52,6 @@ namespace nix {
|
||||
|
||||
#include "parser-tab.hh"
|
||||
#include "lexer-tab.hh"
|
||||
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
+55
-66
@@ -172,7 +172,7 @@ public:
|
||||
/* Cancel the goal. It should wake up its waiters, get rid of any
|
||||
running child processes that are being monitored by the worker
|
||||
(important!), etc. */
|
||||
virtual void cancel() = 0;
|
||||
virtual void cancel(bool timeout) = 0;
|
||||
|
||||
protected:
|
||||
void amDone(ExitCode result);
|
||||
@@ -186,9 +186,10 @@ struct Child
|
||||
{
|
||||
WeakGoalPtr goal;
|
||||
set<int> fds;
|
||||
bool monitorForSilence;
|
||||
bool respectTimeouts;
|
||||
bool inBuildSlot;
|
||||
time_t lastOutput; /* time we last got output on stdout/stderr */
|
||||
time_t timeStarted;
|
||||
};
|
||||
|
||||
typedef map<pid_t, Child> Children;
|
||||
@@ -232,9 +233,6 @@ private:
|
||||
/* Last time the goals in `waitingForAWhile' where woken up. */
|
||||
time_t lastWokenUp;
|
||||
|
||||
/* Last time `waitForInput' was last called. */
|
||||
time_t lastWait;
|
||||
|
||||
public:
|
||||
|
||||
/* Set if at least one derivation had a BuildError (i.e. permanent
|
||||
@@ -266,7 +264,7 @@ public:
|
||||
/* Registers a running child process. `inBuildSlot' means that
|
||||
the process counts towards the jobs limit. */
|
||||
void childStarted(GoalPtr goal, pid_t pid,
|
||||
const set<int> & fds, bool inBuildSlot, bool monitorForSilence);
|
||||
const set<int> & fds, bool inBuildSlot, bool respectTimeouts);
|
||||
|
||||
/* Unregisters a running child process. `wakeSleepers' should be
|
||||
false if there is no sense in waking up goals that are sleeping
|
||||
@@ -697,9 +695,7 @@ HookInstance::HookInstance()
|
||||
throw SysError("dupping builder's stdout/stderr");
|
||||
|
||||
execl(buildHook.c_str(), buildHook.c_str(), settings.thisSystem.c_str(),
|
||||
(format("%1%") % settings.maxSilentTime).str().c_str(),
|
||||
(format("%1%") % settings.printBuildTrace).str().c_str(),
|
||||
(format("%1%") % settings.buildTimeout).str().c_str(),
|
||||
NULL);
|
||||
|
||||
throw SysError(format("executing `%1%'") % buildHook);
|
||||
@@ -851,7 +847,7 @@ public:
|
||||
DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, Worker & worker, bool repair = false);
|
||||
~DerivationGoal();
|
||||
|
||||
void cancel();
|
||||
void cancel(bool timeout);
|
||||
|
||||
void work();
|
||||
|
||||
@@ -977,8 +973,10 @@ void DerivationGoal::killChild()
|
||||
}
|
||||
|
||||
|
||||
void DerivationGoal::cancel()
|
||||
void DerivationGoal::cancel(bool timeout)
|
||||
{
|
||||
if (timeout)
|
||||
printMsg(lvlError, format("@ build-failed %1% - timeout") % drvPath);
|
||||
killChild();
|
||||
amDone(ecFailed);
|
||||
}
|
||||
@@ -1368,8 +1366,8 @@ void DerivationGoal::tryToBuild()
|
||||
outputLocks.unlock();
|
||||
buildUser.release();
|
||||
if (settings.printBuildTrace)
|
||||
printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%")
|
||||
% drvPath % drv.outputs["out"].path % 0 % e.msg());
|
||||
printMsg(lvlError, format("@ build-failed %1% - %2% %3%")
|
||||
% drvPath % 0 % e.msg());
|
||||
worker.permanentFailure = true;
|
||||
amDone(ecFailed);
|
||||
return;
|
||||
@@ -1541,11 +1539,11 @@ void DerivationGoal::buildDone()
|
||||
|
||||
if (settings.printBuildTrace) {
|
||||
if (hook && hookError)
|
||||
printMsg(lvlError, format("@ hook-failed %1% %2% %3% %4%")
|
||||
% drvPath % drv.outputs["out"].path % status % e.msg());
|
||||
printMsg(lvlError, format("@ hook-failed %1% - %2% %3%")
|
||||
% drvPath % status % e.msg());
|
||||
else
|
||||
printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%")
|
||||
% drvPath % drv.outputs["out"].path % 1 % e.msg());
|
||||
printMsg(lvlError, format("@ build-failed %1% - %2% %3%")
|
||||
% drvPath % 1 % e.msg());
|
||||
}
|
||||
|
||||
/* Register the outputs of this build as "failed" so we won't
|
||||
@@ -1568,8 +1566,7 @@ void DerivationGoal::buildDone()
|
||||
buildUser.release();
|
||||
|
||||
if (settings.printBuildTrace) {
|
||||
printMsg(lvlError, format("@ build-succeeded %1% %2%")
|
||||
% drvPath % drv.outputs["out"].path);
|
||||
printMsg(lvlError, format("@ build-succeeded %1% -") % drvPath);
|
||||
}
|
||||
|
||||
amDone(ecSuccess);
|
||||
@@ -1648,11 +1645,11 @@ HookReply DerivationGoal::tryBuildHook()
|
||||
set<int> fds;
|
||||
fds.insert(hook->fromHook.readSide);
|
||||
fds.insert(hook->builderOut.readSide);
|
||||
worker.childStarted(shared_from_this(), hook->pid, fds, false, false);
|
||||
worker.childStarted(shared_from_this(), hook->pid, fds, false, true);
|
||||
|
||||
if (settings.printBuildTrace)
|
||||
printMsg(lvlError, format("@ build-started %1% %2% %3% %4%")
|
||||
% drvPath % drv.outputs["out"].path % drv.platform % logFile);
|
||||
printMsg(lvlError, format("@ build-started %1% - %2% %3%")
|
||||
% drvPath % drv.platform % logFile);
|
||||
|
||||
return rpAccept;
|
||||
}
|
||||
@@ -1697,7 +1694,8 @@ void DerivationGoal::startBuilder()
|
||||
if HOME is not set, but they will just assume that the settings file
|
||||
they are looking for does not exist if HOME is set but points to some
|
||||
non-existing path. */
|
||||
env["HOME"] = "/homeless-shelter";
|
||||
Path homeDir = "/homeless-shelter";
|
||||
env["HOME"] = homeDir;
|
||||
|
||||
/* Tell the builder where the Nix store is. Usually they
|
||||
shouldn't care, but this is useful for purity checking (e.g.,
|
||||
@@ -1946,6 +1944,9 @@ void DerivationGoal::startBuilder()
|
||||
|
||||
else {
|
||||
|
||||
if (pathExists(homeDir))
|
||||
throw Error(format("directory `%1%' exists; please remove it") % homeDir);
|
||||
|
||||
/* We're not doing a chroot build, but we have some valid
|
||||
output paths. Since we can't just overwrite or delete
|
||||
them, we have to do hash rewriting: i.e. in the
|
||||
@@ -2029,8 +2030,8 @@ void DerivationGoal::startBuilder()
|
||||
singleton<set<int> >(builderOut.readSide), true, true);
|
||||
|
||||
if (settings.printBuildTrace) {
|
||||
printMsg(lvlError, format("@ build-started %1% %2% %3% %4%")
|
||||
% drvPath % drv.outputs["out"].path % drv.platform % logFile);
|
||||
printMsg(lvlError, format("@ build-started %1% - %2% %3%")
|
||||
% drvPath % drv.platform % logFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2466,7 +2467,7 @@ bool DerivationGoal::pathFailed(const Path & path)
|
||||
printMsg(lvlError, format("builder for `%1%' failed previously (cached)") % path);
|
||||
|
||||
if (settings.printBuildTrace)
|
||||
printMsg(lvlError, format("@ build-failed %1% %2% cached") % drvPath % path);
|
||||
printMsg(lvlError, format("@ build-failed %1% - cached") % drvPath);
|
||||
|
||||
worker.permanentFailure = true;
|
||||
amDone(ecFailed);
|
||||
@@ -2537,7 +2538,7 @@ public:
|
||||
SubstitutionGoal(const Path & storePath, Worker & worker, bool repair = false);
|
||||
~SubstitutionGoal();
|
||||
|
||||
void cancel();
|
||||
void cancel(bool timeout);
|
||||
|
||||
void work();
|
||||
|
||||
@@ -2578,8 +2579,10 @@ SubstitutionGoal::~SubstitutionGoal()
|
||||
}
|
||||
|
||||
|
||||
void SubstitutionGoal::cancel()
|
||||
void SubstitutionGoal::cancel(bool timeout)
|
||||
{
|
||||
if (timeout)
|
||||
printMsg(lvlError, format("@ substituter-failed %1% timeout") % storePath);
|
||||
if (pid != -1) {
|
||||
pid_t savedPid = pid;
|
||||
pid.kill();
|
||||
@@ -2770,10 +2773,8 @@ void SubstitutionGoal::tryToRun()
|
||||
|
||||
state = &SubstitutionGoal::finished;
|
||||
|
||||
if (settings.printBuildTrace) {
|
||||
printMsg(lvlError, format("@ substituter-started %1% %2%")
|
||||
% storePath % sub);
|
||||
}
|
||||
if (settings.printBuildTrace)
|
||||
printMsg(lvlError, format("@ substituter-started %1% %2%") % storePath % sub);
|
||||
}
|
||||
|
||||
|
||||
@@ -2860,9 +2861,8 @@ void SubstitutionGoal::finished()
|
||||
printMsg(lvlChatty,
|
||||
format("substitution of path `%1%' succeeded") % storePath);
|
||||
|
||||
if (settings.printBuildTrace) {
|
||||
if (settings.printBuildTrace)
|
||||
printMsg(lvlError, format("@ substituter-succeeded %1%") % storePath);
|
||||
}
|
||||
|
||||
amDone(ecSuccess);
|
||||
}
|
||||
@@ -2990,14 +2990,14 @@ unsigned Worker::getNrLocalBuilds()
|
||||
|
||||
void Worker::childStarted(GoalPtr goal,
|
||||
pid_t pid, const set<int> & fds, bool inBuildSlot,
|
||||
bool monitorForSilence)
|
||||
bool respectTimeouts)
|
||||
{
|
||||
Child child;
|
||||
child.goal = goal;
|
||||
child.fds = fds;
|
||||
child.lastOutput = time(0);
|
||||
child.timeStarted = child.lastOutput = time(0);
|
||||
child.inBuildSlot = inBuildSlot;
|
||||
child.monitorForSilence = monitorForSilence;
|
||||
child.respectTimeouts = respectTimeouts;
|
||||
children[pid] = child;
|
||||
if (inBuildSlot) nrLocalBuilds++;
|
||||
}
|
||||
@@ -3113,32 +3113,23 @@ void Worker::waitForInput()
|
||||
timeout.tv_usec = 0;
|
||||
time_t before = time(0);
|
||||
|
||||
/* If a global timeout has been set, sleep until it's done. */
|
||||
if (settings.buildTimeout != 0) {
|
||||
useTimeout = true;
|
||||
if (lastWait == 0 || lastWait > before) lastWait = before;
|
||||
timeout.tv_sec = std::max((time_t) 0, lastWait + settings.buildTimeout - before);
|
||||
}
|
||||
|
||||
/* If we're monitoring for silence on stdout/stderr, sleep until
|
||||
the first deadline for any child. */
|
||||
if (settings.maxSilentTime != 0) {
|
||||
time_t oldest = 0;
|
||||
/* If we're monitoring for silence on stdout/stderr, or if there
|
||||
is a build timeout, then wait for input until the first
|
||||
deadline for any child. */
|
||||
assert(sizeof(time_t) >= sizeof(long));
|
||||
time_t nearest = LONG_MAX; // nearest deadline
|
||||
foreach (Children::iterator, i, children) {
|
||||
if (i->second.monitorForSilence) {
|
||||
oldest = oldest == 0 || i->second.lastOutput < oldest
|
||||
? i->second.lastOutput : oldest;
|
||||
if (!i->second.respectTimeouts) continue;
|
||||
if (settings.maxSilentTime != 0)
|
||||
nearest = std::min(nearest, i->second.lastOutput + settings.maxSilentTime);
|
||||
if (settings.buildTimeout != 0)
|
||||
nearest = std::min(nearest, i->second.timeStarted + settings.buildTimeout);
|
||||
}
|
||||
}
|
||||
if (oldest) {
|
||||
time_t silenceTimeout = std::max((time_t) 0, oldest + settings.maxSilentTime - before);
|
||||
timeout.tv_sec = useTimeout
|
||||
? std::min(silenceTimeout, timeout.tv_sec)
|
||||
: silenceTimeout;
|
||||
if (nearest != LONG_MAX) {
|
||||
timeout.tv_sec = std::max((time_t) 1, nearest - before);
|
||||
useTimeout = true;
|
||||
printMsg(lvlVomit, format("sleeping %1% seconds") % timeout.tv_sec);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are polling goals that are waiting for a lock, then wake
|
||||
up after a few seconds at most. */
|
||||
@@ -3147,7 +3138,7 @@ void Worker::waitForInput()
|
||||
if (lastWokenUp == 0)
|
||||
printMsg(lvlError, "waiting for locks or build slots...");
|
||||
if (lastWokenUp == 0 || lastWokenUp > before) lastWokenUp = before;
|
||||
timeout.tv_sec = std::max((time_t) 0, (time_t) (lastWokenUp + settings.pollInterval - before));
|
||||
timeout.tv_sec = std::max((time_t) 1, (time_t) (lastWokenUp + settings.pollInterval - before));
|
||||
} else lastWokenUp = 0;
|
||||
|
||||
using namespace std;
|
||||
@@ -3171,9 +3162,6 @@ void Worker::waitForInput()
|
||||
|
||||
time_t after = time(0);
|
||||
|
||||
/* Keep track of when we were last called. */
|
||||
lastWait = after;
|
||||
|
||||
/* Process all available file descriptors. */
|
||||
|
||||
/* Since goals may be canceled from inside the loop below (causing
|
||||
@@ -3214,22 +3202,23 @@ void Worker::waitForInput()
|
||||
}
|
||||
|
||||
if (settings.maxSilentTime != 0 &&
|
||||
j->second.monitorForSilence &&
|
||||
j->second.respectTimeouts &&
|
||||
after - j->second.lastOutput >= (time_t) settings.maxSilentTime)
|
||||
{
|
||||
printMsg(lvlError,
|
||||
format("%1% timed out after %2% seconds of silence")
|
||||
% goal->getName() % settings.maxSilentTime);
|
||||
goal->cancel();
|
||||
goal->cancel(true);
|
||||
}
|
||||
|
||||
if (settings.buildTimeout != 0 &&
|
||||
after - before >= (time_t) settings.buildTimeout)
|
||||
j->second.respectTimeouts &&
|
||||
after - j->second.timeStarted >= (time_t) settings.buildTimeout)
|
||||
{
|
||||
printMsg(lvlError,
|
||||
format("%1% timed out after %2% seconds of activity")
|
||||
format("%1% timed out after %2% seconds")
|
||||
% goal->getName() % settings.buildTimeout);
|
||||
goal->cancel();
|
||||
goal->cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -372,9 +372,9 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots)
|
||||
|
||||
string result = runProgram(rootFinder);
|
||||
|
||||
Strings paths = tokenizeString<Strings>(result, "\n");
|
||||
StringSet paths = tokenizeString<StringSet>(result, "\n");
|
||||
|
||||
foreach (Strings::iterator, i, paths) {
|
||||
foreach (StringSet::iterator, i, paths) {
|
||||
if (isInStore(*i)) {
|
||||
Path path = toStorePath(*i);
|
||||
if (roots.find(path) == roots.end() && store.isValidPath(path)) {
|
||||
|
||||
+83
-53
@@ -19,8 +19,9 @@
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#if HAVE_UNSHARE
|
||||
#if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H
|
||||
#include <sched.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
@@ -434,30 +435,20 @@ void LocalStore::openDB(bool create)
|
||||
bind mount. So make the Nix store writable for this process. */
|
||||
void LocalStore::makeStoreWritable()
|
||||
{
|
||||
#if HAVE_UNSHARE
|
||||
#if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_REMOUNT)
|
||||
if (getuid() != 0) return;
|
||||
/* Check if /nix/store is on a read-only mount. */
|
||||
struct statvfs stat;
|
||||
if (statvfs(settings.nixStore.c_str(), &stat) !=0)
|
||||
throw SysError("Getting info of nix store mountpoint");
|
||||
|
||||
if (!pathExists("/proc/self/mountinfo")) return;
|
||||
|
||||
/* Check if /nix/store is a read-only bind mount. */
|
||||
bool found = false;
|
||||
Strings mounts = tokenizeString<Strings>(readFile("/proc/self/mountinfo", true), "\n");
|
||||
foreach (Strings::iterator, i, mounts) {
|
||||
vector<string> fields = tokenizeString<vector<string> >(*i, " ");
|
||||
if (fields.at(3) == "/" || fields.at(4) != settings.nixStore) continue;
|
||||
Strings options = tokenizeString<Strings>(fields.at(5), ",");
|
||||
if (std::find(options.begin(), options.end(), "ro") == options.end()) continue;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) return;
|
||||
|
||||
if (stat.f_flag & ST_RDONLY) {
|
||||
if (unshare(CLONE_NEWNS) == -1)
|
||||
throw SysError("setting up a private mount namespace");
|
||||
|
||||
if (mount(0, settings.nixStore.c_str(), 0, MS_REMOUNT | MS_BIND, 0) == -1)
|
||||
throw SysError(format("remounting %1% writable") % settings.nixStore);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -465,39 +456,8 @@ void LocalStore::makeStoreWritable()
|
||||
const time_t mtimeStore = 1; /* 1 second into the epoch */
|
||||
|
||||
|
||||
void canonicalisePathMetaData(const Path & path, bool recurse, uid_t fromUid)
|
||||
static void canonicaliseTimestampAndPermissions(const Path & path, const struct stat & st)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting attributes of path `%1%'") % path);
|
||||
|
||||
/* Really make sure that the path is of a supported type. This
|
||||
has already been checked in dumpPath(). */
|
||||
assert(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode));
|
||||
|
||||
if (fromUid != (uid_t) -1 && st.st_uid != fromUid)
|
||||
throw BuildError(format("invalid ownership on file `%1%'") % path);
|
||||
|
||||
/* Change ownership to the current uid. If it's a symlink, use
|
||||
lchown if available, otherwise don't bother. Wrong ownership
|
||||
of a symlink doesn't matter, since the owning user can't change
|
||||
the symlink and can't delete it because the directory is not
|
||||
writable. The only exception is top-level paths in the Nix
|
||||
store (since that directory is group-writable for the Nix build
|
||||
users group); we check for this case below. */
|
||||
if (st.st_uid != geteuid()) {
|
||||
#if HAVE_LCHOWN
|
||||
if (lchown(path.c_str(), geteuid(), (gid_t) -1) == -1)
|
||||
#else
|
||||
if (!S_ISLNK(st.st_mode) &&
|
||||
chown(path.c_str(), geteuid(), (gid_t) -1) == -1)
|
||||
#endif
|
||||
throw SysError(format("changing owner of `%1%' to %2%")
|
||||
% path % geteuid());
|
||||
}
|
||||
|
||||
if (!S_ISLNK(st.st_mode)) {
|
||||
|
||||
/* Mask out all type related bits. */
|
||||
@@ -528,18 +488,84 @@ void canonicalisePathMetaData(const Path & path, bool recurse, uid_t fromUid)
|
||||
#endif
|
||||
throw SysError(format("changing modification time of `%1%'") % path);
|
||||
}
|
||||
}
|
||||
|
||||
if (recurse && S_ISDIR(st.st_mode)) {
|
||||
|
||||
void canonicaliseTimestampAndPermissions(const Path & path)
|
||||
{
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting attributes of path `%1%'") % path);
|
||||
canonicaliseTimestampAndPermissions(path, st);
|
||||
}
|
||||
|
||||
|
||||
typedef std::pair<dev_t, ino_t> Inode;
|
||||
typedef set<Inode> InodesSeen;
|
||||
|
||||
|
||||
static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSeen & inodesSeen)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting attributes of path `%1%'") % path);
|
||||
|
||||
/* Really make sure that the path is of a supported type. This
|
||||
has already been checked in dumpPath(). */
|
||||
assert(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode));
|
||||
|
||||
/* Fail if the file is not owned by the build user. This prevents
|
||||
us from messing up the ownership/permissions of files
|
||||
hard-linked into the output (e.g. "ln /etc/shadow $out/foo").
|
||||
However, ignore files that we chown'ed ourselves previously to
|
||||
ensure that we don't fail on hard links within the same build
|
||||
(i.e. "touch $out/foo; ln $out/foo $out/bar"). */
|
||||
if (fromUid != (uid_t) -1 && st.st_uid != fromUid) {
|
||||
assert(!S_ISDIR(st.st_mode));
|
||||
if (inodesSeen.find(Inode(st.st_dev, st.st_ino)) == inodesSeen.end())
|
||||
throw BuildError(format("invalid ownership on file `%1%'") % path);
|
||||
mode_t mode = st.st_mode & ~S_IFMT;
|
||||
assert(S_ISLNK(st.st_mode) || (st.st_uid == geteuid() && (mode == 0444 || mode == 0555) && st.st_mtime == mtimeStore));
|
||||
return;
|
||||
}
|
||||
|
||||
inodesSeen.insert(Inode(st.st_dev, st.st_ino));
|
||||
|
||||
canonicaliseTimestampAndPermissions(path, st);
|
||||
|
||||
/* Change ownership to the current uid. If it's a symlink, use
|
||||
lchown if available, otherwise don't bother. Wrong ownership
|
||||
of a symlink doesn't matter, since the owning user can't change
|
||||
the symlink and can't delete it because the directory is not
|
||||
writable. The only exception is top-level paths in the Nix
|
||||
store (since that directory is group-writable for the Nix build
|
||||
users group); we check for this case below. */
|
||||
if (st.st_uid != geteuid()) {
|
||||
#if HAVE_LCHOWN
|
||||
if (lchown(path.c_str(), geteuid(), (gid_t) -1) == -1)
|
||||
#else
|
||||
if (!S_ISLNK(st.st_mode) &&
|
||||
chown(path.c_str(), geteuid(), (gid_t) -1) == -1)
|
||||
#endif
|
||||
throw SysError(format("changing owner of `%1%' to %2%")
|
||||
% path % geteuid());
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
Strings names = readDirectory(path);
|
||||
foreach (Strings::iterator, i, names)
|
||||
canonicalisePathMetaData(path + "/" + *i, true, fromUid);
|
||||
canonicalisePathMetaData_(path + "/" + *i, fromUid, inodesSeen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void canonicalisePathMetaData(const Path & path, uid_t fromUid)
|
||||
{
|
||||
canonicalisePathMetaData(path, true, fromUid);
|
||||
InodesSeen inodesSeen;
|
||||
|
||||
canonicalisePathMetaData_(path, fromUid, inodesSeen);
|
||||
|
||||
/* On platforms that don't have lchown(), the top-level path can't
|
||||
be a symlink, since we can't change its ownership. */
|
||||
@@ -981,6 +1007,10 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
|
||||
fromPipe.create();
|
||||
errorPipe.create();
|
||||
|
||||
/* Hack: prevent substituters that write too much to stderr from
|
||||
deadlocking our read() from stdout. */
|
||||
fcntl(errorPipe.writeSide, F_SETFL, O_NONBLOCK);
|
||||
|
||||
setSubstituterEnv();
|
||||
|
||||
run.pid = maybeVfork();
|
||||
|
||||
@@ -309,7 +309,7 @@ private:
|
||||
in a setuid Nix installation. */
|
||||
void canonicalisePathMetaData(const Path & path, uid_t fromUid);
|
||||
|
||||
void canonicalisePathMetaData(const Path & path, bool recurse, uid_t fromUid);
|
||||
void canonicaliseTimestampAndPermissions(const Path & path);
|
||||
|
||||
MakeError(PathInUse, Error);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ struct MakeReadOnly
|
||||
{
|
||||
try {
|
||||
/* This will make the path read-only. */
|
||||
if (path != "") canonicalisePathMetaData(path, false, -1);
|
||||
if (path != "") canonicaliseTimestampAndPermissions(path);
|
||||
} catch (...) {
|
||||
ignoreException();
|
||||
}
|
||||
|
||||
@@ -551,6 +551,9 @@ static void performOp(unsigned int clientVersion,
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
string name = readString(from);
|
||||
string value = readString(from);
|
||||
if (name == "build-timeout")
|
||||
string2Int(value, settings.buildTimeout);
|
||||
else
|
||||
settings.set("untrusted-" + name, value);
|
||||
}
|
||||
}
|
||||
@@ -895,8 +898,6 @@ static void daemonLoop()
|
||||
|
||||
void run(Strings args)
|
||||
{
|
||||
bool daemon = false;
|
||||
|
||||
for (Strings::iterator i = args.begin(); i != args.end(); ) {
|
||||
string arg = *i++;
|
||||
if (arg == "--daemon") /* ignored for backwards compatibility */;
|
||||
|
||||
@@ -37,3 +37,6 @@
|
||||
-e "s^@testPath\@^$(coreutils):$$(dirname $$(type -p expr))^g" \
|
||||
< $< > $@ || rm $@
|
||||
if test -x $<; then chmod +x $@; fi
|
||||
|
||||
$(CONFIG_HEADER):
|
||||
true
|
||||
|
||||
+17
-1
@@ -5,7 +5,7 @@ clearManifests
|
||||
|
||||
# Create the binary cache.
|
||||
cacheDir=$TEST_ROOT/binary-cache
|
||||
rm -rf $cacheDir
|
||||
rm -rf "$cacheDir"
|
||||
|
||||
outPath=$(nix-build dependencies.nix --no-out-link)
|
||||
|
||||
@@ -17,6 +17,8 @@ nix-push --dest $cacheDir $outPath
|
||||
clearStore
|
||||
rm -f $NIX_STATE_DIR/binary-cache*
|
||||
|
||||
export _NIX_CACHE_FILE_URLS=1
|
||||
|
||||
nix-env --option binary-caches "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "---"
|
||||
|
||||
nix-store --option binary-caches "file://$cacheDir" -r $outPath
|
||||
@@ -38,6 +40,20 @@ nix-store --check-validity $outPath
|
||||
nix-store -qR $outPath | grep input-2
|
||||
|
||||
|
||||
# Test whether fallback works if we have cached info but the
|
||||
# corresponding NAR has disappeared.
|
||||
clearStore
|
||||
|
||||
nix-build --option binary-caches "file://$cacheDir" dependencies.nix --dry-run # get info
|
||||
|
||||
mkdir $cacheDir/tmp
|
||||
mv $cacheDir/*.nar.xz $cacheDir/tmp/
|
||||
|
||||
NIX_DEBUG_SUBST=1 nix-build --option binary-caches "file://$cacheDir" dependencies.nix -o $TEST_ROOT/result --fallback
|
||||
|
||||
mv $cacheDir/tmp/* $cacheDir/
|
||||
|
||||
|
||||
# Test whether building works if the binary cache contains an
|
||||
# incomplete closure.
|
||||
clearStore
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
echo "\`timeout' builder entering an infinite loop"
|
||||
while true ; do : ; done
|
||||
while true ; do echo foo; sleep 1; done
|
||||
|
||||
@@ -3,6 +3,4 @@ with import ./config.nix;
|
||||
mkDerivation {
|
||||
name = "timeout";
|
||||
builder = ./timeout.builder.sh;
|
||||
PATH = "";
|
||||
goodPath = path;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user