aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-01-08 14:32:45 +0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-01-08 14:32:45 +0100
commita957893b261a4438101c205e38fe8ce62b83a121 (patch)
treede3e3fd274ca4fa201f4fdf746929d55bfdc79f2 /scripts
parent7ba0e9cb481f00baca02f31393ad49681fc48a5d (diff)
Allow nix-shell to be used as a #! interpreter
This allows scripts to fetch their own dependencies via nix-shell. For instance, here is a Haskell script that, when executed, pulls in GHC and the HTTP package: #! /usr/bin/env nix-shell #! nix-shell -i runghc -p haskellPackages.ghc haskellPackages.HTTP import Network.HTTP main = do resp <- Network.HTTP.simpleHTTP (getRequest "http://nixos.org/") body <- getResponseBody resp print (take 100 body) Or a Perl script that pulls in Perl and some CPAN packages: #! /usr/bin/env nix-shell #! nix-shell -i perl -p perl perlPackages.HTMLTokeParserSimple perlPackages.LWP use HTML::TokeParser::Simple; my $p = HTML::TokeParser::Simple->new(url => 'http://nixos.org/'); while (my $token = $p->get_tag("a")) { my $href = $token->get_attr("href"); print "$href\n" if $href; } Note that the options to nix-shell must be given on a separate line that starts with the magic string ‘#! nix-shell’. This is because ‘env’ does not allow passing arguments to an interpreter directly.
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/nix-build.in37
1 files changed, 37 insertions, 0 deletions
diff --git a/scripts/nix-build.in b/scripts/nix-build.in
index 3ac02ad35..b7c923f88 100755
--- a/scripts/nix-build.in
+++ b/scripts/nix-build.in
@@ -25,6 +25,8 @@ my @envExclude = ();
my $myName = $runEnv ? "nix-shell" : "nix-build";
+my $inShebang = 0;
+my $script;
my $tmpDir = mkTempDir($myName);
@@ -35,6 +37,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];
@@ -155,6 +180,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;
}