diff options
Diffstat (limited to 'scripts/nix-build.in')
-rwxr-xr-x | scripts/nix-build.in | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/scripts/nix-build.in b/scripts/nix-build.in index f8cf318ff07a..ca43041b77b0 100755 --- a/scripts/nix-build.in +++ b/scripts/nix-build.in @@ -5,6 +5,8 @@ use strict; use Nix::Config; use Nix::Store; use Nix::Utils; +use File::Basename; +use Cwd; binmode STDERR, ":encoding(utf8)"; @@ -14,6 +16,7 @@ my $runEnv = $0 =~ /nix-shell$/; my $pure = 0; my $fromArgs = 0; my $packages = 0; +my $interactive = 1; my @instArgs = (); my @buildArgs = (); @@ -25,6 +28,8 @@ my @envExclude = (); my $myName = $runEnv ? "nix-shell" : "nix-build"; +my $inShebang = 0; +my $script; my $tmpDir = mkTempDir($myName); @@ -35,6 +40,29 @@ my $drvLink = "$tmpDir/derivation"; $SIG{'INT'} = sub { exit 1 }; +# Heuristic to see if we're invoked as a shebang script, namely, if we +# have a single argument, it's the name of an executable file, and it +# starts with "#!". +if ($runEnv && scalar @ARGV == 1) { + $script = $ARGV[0]; + if (-f $script && -x $script) { + open SCRIPT, "<$script" or die "$0: cannot open ‘$script’: $!\n"; + my $first = <SCRIPT>; + if ($first =~ /^\#\!/) { + $inShebang = 1; + @ARGV = (); + while (<SCRIPT>) { + chomp; + if (/^\#\!\s*nix-shell (.*)$/) { + @ARGV = split / /, $1; + } + } + } + close SCRIPT; + } +} + + for (my $n = 0; $n < scalar @ARGV; $n++) { my $arg = $ARGV[$n]; @@ -131,10 +159,11 @@ for (my $n = 0; $n < scalar @ARGV; $n++) { $runEnv = 1; } - elsif ($arg eq "--command") { + elsif ($arg eq "--command" || $arg eq "--run") { $n++; die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV; - $envCommand = "$ARGV[$n]\nexit $!"; + $envCommand = "$ARGV[$n]\nexit"; + $interactive = 0 if $arg eq "--run"; } elsif ($arg eq "--exclude") { @@ -155,6 +184,18 @@ for (my $n = 0; $n < scalar @ARGV; $n++) { $packages = 1; } + elsif ($inShebang && $arg eq "-i") { + $n++; + die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV; + my $interpreter = $ARGV[$n]; + # Überhack to support Perl. Perl examines the shebang and + # executes it unless it contains the string "perl" or "indir", + # or (undocumented) argv[0] does not contain "perl". Exploit + # the latter by doing "exec -a". + my $execArgs = $interpreter =~ /perl/ ? "-a PERL" : ""; + $envCommand = "exec $execArgs $interpreter $script"; + } + elsif (substr($arg, 0, 1) eq "-") { push @buildArgs, $arg; } @@ -182,6 +223,11 @@ foreach my $expr (@exprs) { # Instantiate. my @drvPaths; if ($expr !~ /^\/.*\.drv$/) { + # If we're in a #! script, interpret filenames relative to the + # script. + $expr = dirname(Cwd::abs_path($script)) . "/" . $expr + if $inShebang && $expr !~ /^\//; + # !!! 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, $_;} @@ -232,17 +278,20 @@ foreach my $expr (@exprs) { ($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\] "; ' . + 'if [ "$(type -t runHook)" = function ]; then runHook shellHook; fi; ' . '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); + my @args = ($ENV{NIX_BUILD_SHELL} // "bash"); + push @args, "--rcfile" if $interactive; + push @args, $rcfile; + exec @args; die; } @@ -276,7 +325,7 @@ foreach my $expr (@exprs) { while (<OUTPATHS>) {chomp; push @outPaths, $_;} if (!close OUTPATHS) { die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127); - exit $? >> 8 || 1; + exit ($? >> 8 || 1); } next if $dryRun; |