about summary refs log tree commit diff
path: root/src/nix-populate
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2003-03-25T16·36+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2003-03-25T16·36+0000
commit0f40a560cab23f70881e5af405ea112a869dc39a (patch)
tree2bb622fd0230a5f53c330b946cbbe90714139ad5 /src/nix-populate
parent3f1a1457e9ad91f93151200fe43c7c33ea95417b (diff)
* Added a script nix-activate which builds a list of "activated"
  packages (i.e., the packages that should appear in the user's $PATH,
  and so on).  Based on this list, the script nix-populate creates a
  hierarchy of symlinks to the relevant files in those packages (e.g.,
  for pkg/bin and pkg/lib).  

  A nice property of nix-populate is that on each run it creates a
  *new* tree, rather than updating the old one.  It then atomically
  switches over to the new tree.  This allows atomic upgrades or
  rollbacks on the set of activated packages.

Diffstat (limited to 'src/nix-populate')
-rwxr-xr-xsrc/nix-populate86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/nix-populate b/src/nix-populate
new file mode 100755
index 000000000000..294ded893ce0
--- /dev/null
+++ b/src/nix-populate
@@ -0,0 +1,86 @@
+#! /usr/bin/perl -w
+
+use strict;
+
+my $pkglist = $ENV{"NIX_ACTIVATIONS"};
+$pkglist or die "NIX_ACTIVATIONS not set";
+my $linkdir = $ENV{"NIX_LINKS"};
+$linkdir or die "NIX_LINKS not set";
+my @dirs = ("bin", "sbin", "lib");
+
+# Figure out a generation number.
+my $nr = 1;
+while (-e "$linkdir/$nr") { $nr++; }
+my $gendir = "$linkdir/$nr";
+print "populating $gendir\n";
+
+# Create the subdirectories.
+mkdir $gendir;
+foreach my $dir (@dirs) {
+    mkdir "$gendir/$dir";
+}
+
+# For each activated package, create symlinks.
+
+sub createLinks {
+    my $srcdir = shift;
+    my $dstdir = shift;
+
+    my @srcfiles = glob("$srcdir/*");
+
+    foreach my $srcfile (@srcfiles) {
+	my $basename = $srcfile;
+	$basename =~ s/^.*\///g; # strip directory
+	my $dstfile = "$dstdir/$basename";
+	if (-d $srcfile) {
+	    # !!! hack for resolving name clashes
+	    if (!-e $dstfile) {
+		mkdir($dstfile) or 
+		    die "error creating directory $dstfile";
+	    }
+	    -d $dstfile or die "$dstfile is not a directory";
+	    createLinks($srcfile, $dstfile);
+	} else {
+	    print "linking $dstfile to $srcfile\n";
+	    symlink($srcfile, $dstfile) or
+		die "error creating link $dstfile";
+	}
+    }
+}
+
+
+open PKGS, "< $pkglist";
+
+while (<PKGS>) {
+    chomp;
+    my $hash = $_;
+    
+    my $pkgdir = `nix getpkg $hash`;
+    if ($?) { die "`nix getpkg' failed"; }
+    chomp $pkgdir;
+
+    print "merging $pkgdir\n";
+
+    foreach my $dir (@dirs) {
+	createLinks("$pkgdir/$dir", "$gendir/$dir");
+    }
+}
+
+close PKGS;
+
+# Make $gendir the current generation by pointing $linkdir/current to
+# it.  The rename() system call is supposed to be essentially atomic
+# on Unix.  That is, if we have links `current -> X' and `new_current
+# -> Y', and we rename new_current to current, a process accessing
+# current will see X or Y, but never a file-not-found or other error
+# condition.  This is sufficient to atomically switch the current link
+# tree.
+
+my $current = "$linkdir/current";
+
+print "switching $current to $gendir\n"; 
+
+my $tmplink = "$linkdir/new_current";
+symlink($gendir, $tmplink) or die "cannot create $tmplink";
+rename($tmplink, $current) or die "cannot rename $tmplink";
+