#! /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 () { 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 = \"@system@\"}"; my $nixexpr = "((import @datadir@/nix/corepkgs/nar/unnar.nix) " . "{narFile = ($fetch); outPath = \"$storepath\"; system = \"@system@\"}) "; $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 () { 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 () { 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"; }