aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/Makefile.am6
-rw-r--r--scripts/nix-pack-closure.in67
-rw-r--r--scripts/nix-unpack-closure.in81
3 files changed, 152 insertions, 2 deletions
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 740110d4c..428d3fa69 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -1,6 +1,7 @@
bin_SCRIPTS = nix-collect-garbage \
nix-pull nix-push nix-prefetch-url \
- nix-install-package nix-channel nix-build
+ nix-install-package nix-channel nix-build \
+ nix-pack-closure nix-unpack-closure
noinst_SCRIPTS = nix-profile.sh generate-patches.pl
@@ -23,4 +24,5 @@ EXTRA_DIST = nix-collect-garbage.in \
readmanifest.pm.in \
nix-build.in \
download-using-manifests.pl.in \
- generate-patches.pl.in
+ generate-patches.pl.in \
+ nix-pack-closure.in nix-unpack-closure.in
diff --git a/scripts/nix-pack-closure.in b/scripts/nix-pack-closure.in
new file mode 100644
index 000000000..8523c61dc
--- /dev/null
+++ b/scripts/nix-pack-closure.in
@@ -0,0 +1,67 @@
+#! @perl@ -w
+
+# This tool computes the closure of a path (using "nix-store --query
+# --requisites") and puts the contents of each path in the closure in
+# a big NAR archive that can be installed on another Nix installation
+# using "nix-unpack-closure".
+
+# TODO: make this program "streamy", i.e., don't use a temporary
+# directory.
+
+use strict;
+use POSIX qw(tmpnam);
+
+my $binDir = $ENV{"NIX_BIN_DIR"};
+$binDir = "@bindir@" unless defined $binDir;
+
+my $tmpDir;
+do { $tmpDir = tmpnam(); }
+until mkdir $tmpDir, 0777;
+END { system "rm -rf '$tmpDir'"; }
+mkdir "$tmpDir/contents", 0777 or die;
+mkdir "$tmpDir/references", 0777 or die;
+mkdir "$tmpDir/derivers", 0777 or die;
+
+
+
+my %storePaths;
+
+
+while (@ARGV) {
+ my $storePath = shift @ARGV;
+
+ # Get the closure of this path.
+ my $pid = open(READ,
+ "$binDir/nix-store --query --requisites " .
+ "--force-realise '$storePath'|") or die;
+
+ while (<READ>) {
+ chomp;
+ die "bad: $_" unless /^\//;
+ $storePaths{$_} = "";
+ }
+
+ close READ or die "nix-store failed: $?";
+}
+
+
+foreach my $storePath (sort(keys %storePaths)) {
+ print STDERR "packing `$storePath'...\n";
+
+ $storePath =~ /\/([^\/]+)$/;
+ my $name = $1;
+
+ system("$binDir/nix-store --dump '$storePath' > $tmpDir/contents/$name") == 0
+ or die "nix-store --dump failed on `$storePath': $?";
+
+ system("$binDir/nix-store --query --references '$storePath' > $tmpDir/references/$name") == 0
+ or die "nix-store --query --references failed on `$storePath': $?";
+
+ system("$binDir/nix-store --query --deriver '$storePath' > $tmpDir/derivers/$name") == 0
+ or die "nix-store --query --deriver failed on `$storePath': $?";
+}
+
+
+# Write a NAR archive of everything to standard output.
+system("nix-store --dump '$tmpDir'") == 0
+ or die "nix-store --dump failed";
diff --git a/scripts/nix-unpack-closure.in b/scripts/nix-unpack-closure.in
new file mode 100644
index 000000000..98c7d84db
--- /dev/null
+++ b/scripts/nix-unpack-closure.in
@@ -0,0 +1,81 @@
+#! @perl@ -w
+
+# This tool unpacks the closures created by "nix-pack-closure" and
+# adds them to the Nix store.
+
+# TODO: make this program "streamy", i.e., don't use a temporary
+# directory.
+
+use strict;
+use POSIX qw(tmpnam);
+
+my $binDir = $ENV{"NIX_BIN_DIR"};
+$binDir = "@bindir@" unless defined $binDir;
+
+my $tmpDir;
+do { $tmpDir = tmpnam(); }
+until mkdir $tmpDir, 0777;
+END { system "rm -rf '$tmpDir'"; }
+
+
+# Unpack the NAR archive on standard input.
+system("nix-store --restore '$tmpDir/unpacked'") == 0
+ or die "nix-store --restore failed";
+
+
+open VALID, ">$tmpDir/validity" or die;
+
+
+# For each path in the closure that is not yet valid, add it to the
+# store. TODO: use proper locking. Or even better, let nix-store do
+# this.
+opendir(DIR, "$tmpDir/unpacked/contents") or die "cannot open directory: $!";
+
+foreach my $name (sort(readdir DIR)) {
+ next if $name eq "." or $name eq "..";
+
+ my $storePath = "/nix/store/$name"; # !!!
+
+ # !!! this really isn't a good validity check!
+ system "/nix/bin/nix-store --check-validity '$storePath' 2> /dev/null";
+ if ($? != 0) {
+ print STDERR "unpacking `$storePath'...\n";
+
+ # !!! race
+ system("rm -rf '$storePath'") == 0
+ or die "cannot remove `$storePath': $?";
+
+ system("$binDir/nix-store --restore '$storePath' < '$tmpDir/unpacked/contents/$name'") == 0
+ or die "nix-store --dump failed on `$storePath': $?";
+
+ print VALID "$storePath\n";
+
+ open DRV, "<$tmpDir/unpacked/derivers/$name" or die;
+ my $deriver = <DRV>;
+ chomp $deriver;
+ $deriver = "" if $deriver eq "unknown-deriver";
+ close DRV;
+
+ my @refs;
+ open REFS, "<$tmpDir/unpacked/references/$name" or die;
+ while (<REFS>) {
+ chomp;
+ push @refs, $_;
+ }
+ close REFS;
+
+ print VALID "$deriver\n";
+
+ print VALID (scalar @refs), "\n";
+ foreach my $ref (@refs) {
+ print VALID "$ref\n";
+ }
+ }
+}
+
+closedir(DIR) or die;
+
+
+# Register the invalid paths as valid.
+system("nix-store --register-validity <'$tmpDir/validity'") == 0
+ or die "nix-store --register-validity failed";