forked from lix-project/lix
* 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.
This commit is contained in:
parent
3f1a1457e9
commit
0f40a560ca
22
src/nix-activate
Executable file
22
src/nix-activate
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
#! /usr/bin/perl -w
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
my $pkglist = "/home/eelco/.nixactivations";
|
||||||
|
|
||||||
|
if (!-f $pkglist) {
|
||||||
|
system "touch $pkglist";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $hash;
|
||||||
|
foreach $hash (@ARGV) {
|
||||||
|
system "grep -q $hash $pkglist";
|
||||||
|
if ($?) {
|
||||||
|
print STDERR "activating $hash\n";
|
||||||
|
system "nix getpkg $hash > /dev/null";
|
||||||
|
if ($?) { die "`nix getpkg' failed"; }
|
||||||
|
system "echo $hash >> $pkglist";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system "nix-populate";
|
|
@ -1,18 +0,0 @@
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
ROOTLIST=~/.nixroots
|
|
||||||
|
|
||||||
if ! test -f $ROOTLIST; then
|
|
||||||
touch $ROOTLIST
|
|
||||||
fi
|
|
||||||
|
|
||||||
for i in $*; do
|
|
||||||
if nix ensure $i > /dev/null; then
|
|
||||||
if grep -q $i $ROOTLIST; then
|
|
||||||
echo $i already is a root
|
|
||||||
else
|
|
||||||
echo adding root $i
|
|
||||||
echo $i >> $ROOTLIST
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
86
src/nix-populate
Executable file
86
src/nix-populate
Executable file
|
@ -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";
|
||||||
|
|
Loading…
Reference in a new issue