#! /usr/bin/perl -w use strict; my $keep = 0; my $sourceroot = 0; my $name = "current"; my $srcid; my $argnr = 0; while ($argnr < scalar @ARGV) { my $arg = $ARGV[$argnr++]; if ($arg eq "--keep") { $keep = 1; } elsif ($arg eq "--source-root") { $sourceroot = 1; } elsif ($arg eq "--name") { $name = $ARGV[$argnr++]; } elsif ($arg =~ /^([0-9a-z]{32})$/) { $srcid = $arg; } else { die "unknown argument `$arg'" }; } my $linkdir = "@localstatedir@/nix/links"; # Build the specified package, and all its dependencies. my $nfid = `nix --install $srcid`; if ($?) { die "`nix --install' failed"; } chomp $nfid; die unless $nfid =~ /^([0-9a-z]{32})$/; my $pkgdir = `nix --query --list $nfid`; if ($?) { die "`nix --query --list' failed"; } chomp $pkgdir; # Figure out a generation number. opendir(DIR, $linkdir); my $nr = 0; foreach my $n (sort(readdir(DIR))) { next if (!($n =~ /^\d+$/)); $nr = $n + 1 if ($n >= $nr); } closedir(DIR); my $link = "$linkdir/$nr"; # Create a symlink from $link to $pkgdir. symlink($pkgdir, $link) or die "cannot create $link: $!"; # Store the id of the normal form. This is useful for garbage # collection and the like. my $idfile = "$linkdir/$nr.id"; open ID, "> $idfile" or die "cannot create $idfile"; print ID "$nfid\n"; close ID; # Optionally store the source id. if ($sourceroot) { $idfile = "$linkdir/$nr-src.id"; open ID, "> $idfile" or die "cannot create $idfile"; print ID "$srcid\n"; close ID; } my $current = "$linkdir/$name"; # Read the current generation so that we can delete it (if --keep # wasn't specified). my $oldlink = readlink($current); # Make $link 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. print "switching $current to $link\n"; my $tmplink = "$linkdir/.new_$name"; symlink($link, $tmplink) or die "cannot create $tmplink"; rename($tmplink, $current) or die "cannot rename $tmplink"; if (!$keep && defined $oldlink) { print "deleting old $oldlink\n"; unlink($oldlink) == 1 or print "cannot delete $oldlink\n"; unlink("$oldlink.id") == 1 or print "cannot delete $oldlink.id\n"; unlink("$oldlink-src.id"); }