![Eelco Dolstra](/assets/img/avatar_default.png)
The script nix-install-package takes a `Nix package file' (which contains one or more derivations, along with URLs of Nix caches), unpacks it, pulls the caches, and installs the derivations in the user's environment. For best results, associate the command `xterm -e /nix/bin/nix-install-package' with the MIME type `application/x-nix-package' and visit http://losser.st-lab.cs.uu.nl/~eelco/test/.
150 lines
3.6 KiB
Perl
150 lines
3.6 KiB
Perl
#! /usr/bin/perl -w
|
|
|
|
use strict;
|
|
use IPC::Open2;
|
|
use POSIX qw(tmpnam);
|
|
|
|
my $tmpdir;
|
|
do { $tmpdir = tmpnam(); }
|
|
until mkdir $tmpdir, 0777;
|
|
|
|
my $manifest = "$tmpdir/manifest";
|
|
my $conffile = "@sysconfdir@/nix/prebuilts.conf";
|
|
|
|
#END { unlink $manifest; rmdir $tmpdir; }
|
|
|
|
my @srcpaths;
|
|
my @subs;
|
|
my @sucs;
|
|
|
|
my $fullexpr = "[";
|
|
|
|
|
|
sub processURL {
|
|
my $url = shift;
|
|
$url =~ s/\/$//;
|
|
print "obtaining list of Nix archives at $url...\n";
|
|
|
|
system "wget --cache=off '$url'/MANIFEST -O '$manifest' 2> /dev/null"; # !!! escape
|
|
if ($?) { die "`wget' failed"; }
|
|
|
|
open MANIFEST, "<$manifest";
|
|
|
|
my $inside = 0;
|
|
|
|
my $storepath;
|
|
my $narname;
|
|
my $hash;
|
|
my @preds;
|
|
|
|
while (<MANIFEST>) {
|
|
chomp;
|
|
s/\#.*$//g;
|
|
next if (/^$/);
|
|
|
|
if (!$inside) {
|
|
if (/^\{$/) {
|
|
$inside = 1;
|
|
undef $storepath;
|
|
undef $narname;
|
|
undef $hash;
|
|
@preds = ();
|
|
}
|
|
else { die "bad line: $_"; }
|
|
} else {
|
|
if (/^\}$/) {
|
|
$inside = 0;
|
|
my $fullurl = "$url/$narname";
|
|
# print "$storepath\n";
|
|
|
|
# Construct a Nix expression that fetches and unpacks a
|
|
# Nix archive from the network.
|
|
my $fetch =
|
|
"(import @datadir@/nix/corepkgs/fetchurl) " .
|
|
"{url = $fullurl; md5 = \"$hash\"; system = \"@host@\"}";
|
|
my $nixexpr =
|
|
"((import @datadir@/nix/corepkgs/nar/unnar.nix) " .
|
|
"{narFile = ($fetch); outPath = \"$storepath\"; system = \"@host@\"}) ";
|
|
$fullexpr .= $nixexpr; # !!! O(n^2)?
|
|
|
|
push @srcpaths, $storepath;
|
|
|
|
foreach my $p (@preds) {
|
|
push @sucs, $p;
|
|
push @sucs, $storepath;
|
|
}
|
|
|
|
}
|
|
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) {
|
|
$storepath = $1;
|
|
}
|
|
elsif (/^\s*NarName:\s*(\S+)\s*$/) {
|
|
$narname = $1;
|
|
}
|
|
elsif (/^\s*MD5:\s*(\S+)\s*$/) {
|
|
$hash = $1;
|
|
}
|
|
elsif (/^\s*SuccOf:\s*(\/\S+)\s*$/) {
|
|
push @preds, $1;
|
|
}
|
|
else { die "bad line: $_"; }
|
|
}
|
|
}
|
|
|
|
close MANIFEST;
|
|
}
|
|
|
|
|
|
# Obtain URLs either from the command line or from a configuration file.
|
|
if (scalar @ARGV > 0) {
|
|
while (@ARGV) {
|
|
my $url = shift @ARGV;
|
|
processURL $url;
|
|
}
|
|
} else {
|
|
open CONFFILE, "<$conffile";
|
|
while (<CONFFILE>) {
|
|
chomp;
|
|
if (/^\s*(\S+)\s*(\#.*)?$/) {
|
|
my $url = $1;
|
|
processURL $url;
|
|
}
|
|
}
|
|
close CONFFILE;
|
|
}
|
|
|
|
$fullexpr .= "]";
|
|
|
|
|
|
# Instantiate store expressions from the Nix expressions we created above.
|
|
print STDERR "instantiating Nix expression...\n";
|
|
my $pid = open2(\*READ, \*WRITE, "nix-instantiate -") or die "cannot run nix-instantiate";
|
|
|
|
print WRITE $fullexpr;
|
|
close WRITE;
|
|
my $i = 0;
|
|
while (<READ>) {
|
|
chomp;
|
|
die unless /^\//;
|
|
my $subpath = $_;
|
|
die unless ($i < scalar @srcpaths);
|
|
my $srcpath = $srcpaths[$i++];
|
|
push @subs, $srcpath;
|
|
push @subs, $subpath;
|
|
}
|
|
|
|
waitpid $pid, 0;
|
|
$? == 0 or die "nix-instantiate failed";
|
|
|
|
|
|
# Register all substitutes.
|
|
print STDERR "registering substitutes...\n";
|
|
system "nix-store --substitute @subs";
|
|
if ($?) { die "`nix-store --substitute' failed"; }
|
|
|
|
|
|
# Register all successors.
|
|
print STDERR "registering successors...\n";
|
|
system "nix-store --successor @sucs";
|
|
if ($?) { die "`nix-store --successor' failed"; }
|