about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-01-12T15·17+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-01-12T15·17+0000
commite4d4969ae929682aea936e035cc24d56949a82ba (patch)
tree1fcddffde869e004096673698a5e18ca87049c2a
parent5b527901ae625675f525dd65b82f90bcb2001afd (diff)
* New tools nix-pack-closure and nix-unpack-closure. These provide a
  useful way to transfer the closure of a store path to another
  machine.

  These commands provide functionality previously possible through
  `nix-push --copy'.  However, they are much more convenient in many
  situations (though possibly less efficient).
  
  Example:
  $ nix-pack-closure /nix/store/hj232g1r...-subversion-1.3.0 > svn.closure
  (on another machine:)
  $ nix-unpack-closure < svn.closure

  Note that Subversion is added to the store, but not installed into a
  user environment.  One should do `nix-env -i
  /nix/store/hj232g1r...-subversion-1.3.0' for that.

  Another example: copy the application Azureus to the machine
  `scratchy' through ssh:
  
  $ nix-pack-closure $(which azureus) | ssh scratchy nix-unpack-closure


-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 740110d4c1af..428d3fa6985a 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 000000000000..8523c61dc404
--- /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 000000000000..98c7d84db451
--- /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";