forked from lix-project/lix
59c9019685
If derivation declares multiple outputs and first (default) output if not "out", then "nix-instantiate" calls return path with output names appended after "!". Than suffix must be stripped before ant path checks are done.
287 lines
8.7 KiB
Text
Executable file
287 lines
8.7 KiB
Text
Executable file
#! @perl@ -w @perlFlags@
|
|
|
|
use strict;
|
|
use Nix::Config;
|
|
use Nix::Store;
|
|
use Nix::Utils;
|
|
use File::Temp qw(tempdir);
|
|
|
|
|
|
my $dryRun = 0;
|
|
my $verbose = 0;
|
|
my $runEnv = $0 =~ /nix-shell$/;
|
|
my $pure = 0;
|
|
my $fromArgs = 0;
|
|
my $packages = 0;
|
|
|
|
my @instArgs = ();
|
|
my @buildArgs = ();
|
|
my @exprs = ();
|
|
|
|
my $shell = $ENV{SHELL} || "/bin/sh";
|
|
my $envCommand = ""; # interactive shell
|
|
my @envExclude = ();
|
|
|
|
my $myName = $runEnv ? "nix-shell" : "nix-build";
|
|
|
|
|
|
my $tmpDir = tempdir("$myName.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") {
|
|
exec "man $myName" or die;
|
|
}
|
|
|
|
elsif ($arg eq "--version") {
|
|
print "$myName (Nix) $Nix::Config::version\n";
|
|
exit 0;
|
|
}
|
|
|
|
elsif ($arg eq "--add-drv-link") {
|
|
$drvLink = "./derivation";
|
|
}
|
|
|
|
elsif ($arg eq "--no-out-link" || $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" || $arg eq "-o") {
|
|
$n++;
|
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
|
$outLink = $ARGV[$n];
|
|
}
|
|
|
|
elsif ($arg eq "--attr" || $arg eq "-A" || $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" || $arg eq "-j" || $arg eq "--max-silent-time" || $arg eq "--log-type" || $arg eq "--cores" || $arg eq "--timeout") {
|
|
$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 "-") {
|
|
@exprs = ("-");
|
|
}
|
|
|
|
elsif ($arg eq "--verbose" || substr($arg, 0, 2) eq "-v") {
|
|
push @buildArgs, $arg;
|
|
push @instArgs, $arg;
|
|
$verbose = 1;
|
|
}
|
|
|
|
elsif ($arg eq "--quiet" || $arg eq "--repair") {
|
|
push @buildArgs, $arg;
|
|
push @instArgs, $arg;
|
|
}
|
|
|
|
elsif ($arg eq "--check") {
|
|
push @buildArgs, $arg;
|
|
}
|
|
|
|
elsif ($arg eq "--run-env") { # obsolete
|
|
$runEnv = 1;
|
|
}
|
|
|
|
elsif ($arg eq "--command") {
|
|
$n++;
|
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
|
$envCommand = "$ARGV[$n]\nexit $!";
|
|
}
|
|
|
|
elsif ($arg eq "--exclude") {
|
|
$n++;
|
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
|
push @envExclude, $ARGV[$n];
|
|
}
|
|
|
|
elsif ($arg eq "--pure") { $pure = 1; }
|
|
elsif ($arg eq "--impure") { $pure = 0; }
|
|
|
|
elsif ($arg eq "--expr" || $arg eq "-E") {
|
|
$fromArgs = 1;
|
|
push @instArgs, "--expr";
|
|
}
|
|
|
|
elsif ($arg eq "--packages" || $arg eq "-p") {
|
|
$packages = 1;
|
|
}
|
|
|
|
elsif (substr($arg, 0, 1) eq "-") {
|
|
push @buildArgs, $arg;
|
|
}
|
|
|
|
else {
|
|
push @exprs, $arg;
|
|
}
|
|
}
|
|
|
|
if ($packages) {
|
|
push @instArgs, "--expr";
|
|
@exprs = (
|
|
'with import <nixpkgs> { }; runCommand "shell" { buildInputs = [ '
|
|
. (join " ", map { "($_)" } @exprs) . ']; } ""');
|
|
} elsif (!$fromArgs) {
|
|
@exprs = ("shell.nix") if scalar @exprs == 0 && $runEnv && -e "shell.nix";
|
|
@exprs = ("default.nix") if scalar @exprs == 0;
|
|
}
|
|
|
|
$ENV{'IN_NIX_SHELL'} = 1 if $runEnv;
|
|
|
|
|
|
foreach my $expr (@exprs) {
|
|
|
|
# Instantiate.
|
|
my @drvPaths;
|
|
if ($expr !~ /^\/.*\.drv$/) {
|
|
# !!! 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;
|
|
}
|
|
} else {
|
|
push @drvPaths, $expr;
|
|
}
|
|
|
|
if ($runEnv) {
|
|
die "$0: a single derivation is required\n" if scalar @drvPaths != 1;
|
|
my $drvPath = $drvPaths[0];
|
|
$drvPath = (split '!',$drvPath)[0];
|
|
$drvPath = readlink $drvPath or die "cannot read symlink `$drvPath'" if -l $drvPath;
|
|
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", "--no-output", "--no-gc-warning", @buildArgs, @inputDrvs, @{$drv->{inputSrcs}}) == 0
|
|
or die "$0: failed to build all dependencies\n";
|
|
|
|
# Set the environment.
|
|
if ($pure) {
|
|
foreach my $name (keys %ENV) {
|
|
next if grep { $_ eq $name } ("HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ");
|
|
delete $ENV{$name};
|
|
}
|
|
# NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
|
|
$ENV{'__ETC_PROFILE_SOURCED'} = 1;
|
|
}
|
|
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} = $ENV{'TEMPDIR'} = $ENV{'TMP'} = $ENV{'TEMP'} = $ENV{'TMPDIR'} // "/tmp";
|
|
$ENV{'NIX_STORE'} = $Nix::Config::storeDir;
|
|
$ENV{$_} = $drv->{env}->{$_} foreach keys %{$drv->{env}};
|
|
|
|
# Run a shell using the derivation's environment. For
|
|
# convenience, source $stdenv/setup to setup additional
|
|
# environment variables and shell functions. Also don't lose
|
|
# the current $PATH directories.
|
|
my $rcfile = "$tmpDir/rc";
|
|
writeFile(
|
|
$rcfile,
|
|
"rm -rf '$tmpDir'; " .
|
|
'unset BASH_ENV; ' .
|
|
'[ -n "$PS1" ] && [ -e ~/.bashrc ] && source ~/.bashrc; ' .
|
|
($pure ? '' : 'p=$PATH; ' ) .
|
|
'dontAddDisableDepTrack=1; ' .
|
|
'[ -e $stdenv/setup ] && source $stdenv/setup; ' .
|
|
'if [ "$(type -t runHook)" = function ]; then runHook shellHook; fi; ' .
|
|
($pure ? '' : 'PATH=$PATH:$p; unset p; ') .
|
|
'set +e; ' .
|
|
'[ -n "$PS1" ] && PS1="\n\[\033[1;32m\][nix-shell:\w]$\[\033[0m\] "; ' .
|
|
'unset NIX_ENFORCE_PURITY; ' .
|
|
'unset NIX_INDENT_MAKE; ' .
|
|
'shopt -u nullglob; ' .
|
|
'unset TZ; ' . (defined $ENV{'TZ'} ? "export TZ='${ENV{'TZ'}}'; " : '') .
|
|
$envCommand);
|
|
$ENV{BASH_ENV} = $rcfile;
|
|
exec($ENV{NIX_BUILD_SHELL} // "bash", "--rcfile", $rcfile);
|
|
die;
|
|
}
|
|
|
|
# Ugly hackery to make "nix-build -A foo.all" produce symlinks
|
|
# ./result, ./result-dev, and so on, rather than ./result,
|
|
# ./result-2-dev, and so on. This combines multiple derivation
|
|
# paths into one "/nix/store/drv-path!out1,out2,..." argument.
|
|
my $prevDrvPath = "";
|
|
my @drvPaths2;
|
|
foreach my $drvPath (@drvPaths) {
|
|
my $p = $drvPath; my $output = "out";
|
|
if ($drvPath =~ /(.*)!(.*)/) {
|
|
$p = $1; $output = $2;
|
|
} else {
|
|
$p = $drvPath;
|
|
}
|
|
my $target = readlink $p or die "cannot read symlink `$p'";
|
|
print STDERR "derivation is $target\n" if $verbose;
|
|
if ($target eq $prevDrvPath) {
|
|
push @drvPaths2, (pop @drvPaths2) . "," . $output;
|
|
} else {
|
|
push @drvPaths2, $target . "!" . $output;
|
|
$prevDrvPath = $target;
|
|
}
|
|
}
|
|
|
|
# Build.
|
|
my @outPaths;
|
|
my $pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
|
|
@buildArgs, @drvPaths2;
|
|
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";
|
|
}
|
|
}
|