Revision df716c98d203ab64cdf05f9c17fdae565b7daa1c authored by Eelco Dolstra on 23 June 2012, 04:28:35 UTC, committed by Eelco Dolstra on 23 June 2012, 04:28:35 UTC
On Linux it's possible to run a process in its own network namespace, meaning that it gets its own set of network interfaces, disjunct from the rest of the system. We use this to completely remove network access to chroot builds, except that they get a private loopback interface. This means that: - Builders cannot connect to the outside network or to other processes on the same machine, except processes within the same build. - Vice versa, other processes cannot connect to processes in a chroot build, and open ports/connections do not show up in "netstat". - If two concurrent builders try to listen on the same port (e.g. as part of a test), they no longer conflict with each other. This was inspired by the "PrivateNetwork" flag in systemd.
1 parent 2f3f413
nix-build.in
#! @perl@ -w @perlFlags@
use strict;
use Nix::Config;
use Nix::Store;
use File::Temp qw(tempdir);
my $dryRun = 0;
my $verbose = 0;
my $runEnv = 0;
my @instArgs = ();
my @buildArgs = ();
my @exprs = ();
my $shell = $ENV{SHELL} || "/bin/sh";
my $envCommand = "p=\$PATH; source \$stdenv/setup; PATH=\$PATH:\$p; exec $shell";
my @envExclude = ();
my $tmpDir = tempdir("nix-build.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
my $outLink = "./result";
my $drvLink = "$tmpDir/derivation";
# Ensure that the $tmpDir is deleted.
$SIG{'INT'} = sub { exit 1 };
for (my $n = 0; $n < scalar @ARGV; $n++) {
my $arg = $ARGV[$n];
if ($arg eq "--help") {
print STDERR <<EOF;
Usage: nix-build [OPTION]... [FILE]...
`nix-build' builds the given Nix expressions (which
default to ./default.nix if none are given). A symlink called
`result' is placed in the current directory.
Flags:
--add-drv-link: create a symlink `derivation' to the store derivation
--drv-link NAME: create symlink NAME instead of `derivation'
--no-out-link: do not create the `result' symlink
--out-link / -o NAME: create symlink NAME instead of `result'
--attr / -A ATTR: select a specific attribute from the Nix expression
--run-env: build dependencies of the specified derivation, then start a
shell with the environment of the derivation
--command: command to run with `--run-env'
--exclude: regexp specifying dependencies to be excluded by `--run-env'
Any additional flags are passed to `nix-store'.
EOF
exit 0;
# '` hack
}
elsif ($arg eq "--add-drv-link") {
$drvLink = "./derivation";
}
elsif ($arg eq "--no-out-link" or $arg eq "--no-link") {
$outLink = "$tmpDir/result";
}
elsif ($arg eq "--drv-link") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$drvLink = $ARGV[$n];
}
elsif ($arg eq "--out-link" or $arg eq "-o") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$outLink = $ARGV[$n];
}
elsif ($arg eq "--attr" or $arg eq "-A" or $arg eq "-I") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @instArgs, ($arg, $ARGV[$n]);
}
elsif ($arg eq "--arg" || $arg eq "--argstr") {
die "$0: `$arg' requires two arguments\n" unless $n + 2 < scalar @ARGV;
push @instArgs, ($arg, $ARGV[$n + 1], $ARGV[$n + 2]);
$n += 2;
}
elsif ($arg eq "--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" or $arg eq "--cores") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @buildArgs, ($arg, $ARGV[$n]);
}
elsif ($arg eq "--dry-run") {
push @buildArgs, "--dry-run";
$dryRun = 1;
}
elsif ($arg eq "--show-trace") {
push @instArgs, $arg;
}
elsif ($arg eq "--verbose" or substr($arg, 0, 2) eq "-v") {
push @buildArgs, $arg;
push @instArgs, $arg;
$verbose = 1;
}
elsif ($arg eq "--quiet") {
push @buildArgs, $arg;
push @instArgs, $arg;
}
elsif ($arg eq "--run-env") {
$runEnv = 1;
}
elsif ($arg eq "--command") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
$envCommand = $ARGV[$n];
}
elsif ($arg eq "--exclude") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @envExclude, $ARGV[$n];
}
elsif (substr($arg, 0, 1) eq "-") {
push @buildArgs, $arg;
}
else {
push @exprs, $arg;
}
}
@exprs = ("./default.nix") if scalar @exprs == 0;
foreach my $expr (@exprs) {
# Instantiate.
my @drvPaths;
# !!! would prefer the perl 5.8.0 pipe open feature here.
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
if (!close DRVPATHS) {
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
}
if ($runEnv) {
die "$0: ‘--run-env’ requires a single derivation\n" if scalar @drvPaths != 1;
my $drvPath = readlink $drvPaths[0] or die "cannot read symlink `$drvPaths[0]'";
my $drv = derivationFromPath($drvPath);
# Build or fetch all dependencies of the derivation.
my @inputDrvs = grep { my $x = $_; (grep { $x =~ $_ } @envExclude) == 0 } @{$drv->{inputDrvs}};
system("$Nix::Config::binDir/nix-store -r @buildArgs @inputDrvs @{$drv->{inputSrcs}} > /dev/null") == 0
or die "$0: failed to build all dependencies\n";
# Set the environment.
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} || "/tmp";
foreach (keys %{$drv->{env}}) {
$ENV{$_} = $drv->{env}->{$_};
}
# Run a shell using the derivation's environment. For
# convenience, source $stdenv/setup to setup additional
# environment variables. Also don't lose the current $PATH
# directories.
exec($ENV{SHELL}, "-c", $envCommand);
die;
}
foreach my $drvPath (@drvPaths) {
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
print STDERR "derivation is $target\n" if $verbose;
}
# Build.
my @outPaths;
$pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
@buildArgs, @drvPaths;
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
if (!close OUTPATHS) {
die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127);
exit 1;
}
next if $dryRun;
foreach my $outPath (@outPaths) {
my $target = readlink $outPath or die "cannot read symlink `$outPath'";
print "$target\n";
}
}

Computing file changes ...