lix/scripts/nix-channel.in
2009-02-27 11:01:03 +00:00

200 lines
5 KiB
Text

#! @perl@ -w
use strict;
my $rootsDir = "@localstatedir@/nix/gcroots";
my $stateDir = $ENV{"NIX_STATE_DIR"};
$stateDir = "@localstatedir@/nix" unless defined $stateDir;
# Turn on caching in nix-prefetch-url.
my $channelCache = "$stateDir/channel-cache";
mkdir $channelCache, 0755 unless -e $channelCache;
$ENV{'NIX_DOWNLOAD_CACHE'} = $channelCache if -W $channelCache;
# Figure out the name of the `.nix-channels' file to use.
my $home = $ENV{"HOME"};
die '$HOME not set' unless defined $home;
my $channelsList = "$home/.nix-channels";
my $nixDefExpr = "$home/.nix-defexpr";
my @channels;
# Reads the list of channels from the file $channelsList;
sub readChannels {
return if (!-f $channelsList);
open CHANNELS, "<$channelsList" or die "cannot open `$channelsList': $!";
while (<CHANNELS>) {
chomp;
next if /^\s*\#/;
push @channels, $_;
}
close CHANNELS;
}
# Writes the list of channels to the file $channelsList;
sub writeChannels {
open CHANNELS, ">$channelsList" or die "cannot open `$channelsList': $!";
foreach my $url (@channels) {
print CHANNELS "$url\n";
}
close CHANNELS;
}
# Adds a channel to the file $channelsList;
sub addChannel {
my $url = shift;
readChannels;
foreach my $url2 (@channels) {
return if $url eq $url2;
}
push @channels, $url;
writeChannels;
}
# Remove a channel from the file $channelsList;
sub removeChannel {
my $url = shift;
my @left = ();
readChannels;
foreach my $url2 (@channels) {
push @left, $url2 if $url ne $url2;
}
@channels = @left;
writeChannels;
}
# Fetch Nix expressions and pull cache manifests from the subscribed
# channels.
sub update {
readChannels;
# Do we have write permission to the manifests directory? If not,
# then just skip pulling the manifest and just download the Nix
# expressions. If the user is a non-privileged user in a
# multi-user Nix installation, he at least gets installation from
# source.
if (-W "$stateDir/manifests") {
# Remove all the old manifests.
for my $manifest (glob "$stateDir/manifests/*.nixmanifest") {
unlink $manifest or die "cannot remove `$manifest': $!";
}
# Pull cache manifests.
foreach my $url (@channels) {
#print "pulling cache manifest from `$url'\n";
system("@bindir@/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
or die "cannot pull cache manifest from `$url'";
}
}
# Create a Nix expression that fetches and unpacks the channel Nix
# expressions.
my $inputs = "[";
foreach my $url (@channels) {
$url =~ /\/([^\/]+)\/?$/;
my $channelName = $1;
$channelName = "unnamed" unless defined $channelName;
my $fullURL = "$url/nixexprs.tar.bz2";
print "downloading Nix expressions from `$fullURL'...\n";
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL'`;
die "cannot fetch `$fullURL'" if $? != 0;
chomp $path;
$inputs .= '"' . $channelName . '"' . " " . $path . " ";
}
$inputs .= "]";
# Figure out a name for the GC root.
my $userName = getpwuid($<);
die "who ARE you? go away" unless defined $userName;
my $rootFile = "$rootsDir/per-user/$userName/channels";
# Build the Nix expression.
print "unpacking channel Nix expressions...\n";
my $outPath = `\\
@bindir@/nix-build --out-link '$rootFile' --drv-link '$rootFile'.tmp \\
@datadir@/nix/corepkgs/channels/unpack.nix \\
--argstr system @system@ --arg inputs '$inputs'`
or die "cannot unpack the channels";
chomp $outPath;
unlink "$rootFile.tmp";
# Make the channels appear in nix-env.
unlink $nixDefExpr if -l $nixDefExpr; # old-skool ~/.nix-defexpr
mkdir $nixDefExpr or die "cannot create directory `$nixDefExpr'" if !-e $nixDefExpr;
my $channelLink = "$nixDefExpr/channels";
unlink $channelLink; # !!! not atomic
symlink($outPath, $channelLink) or die "cannot symlink `$channelLink' to `$outPath'";
}
sub usageError {
print STDERR <<EOF;
Usage:
nix-channel --add URL
nix-channel --remove URL
nix-channel --list
nix-channel --update
EOF
exit 1;
}
usageError if scalar @ARGV == 0;
while (scalar @ARGV) {
my $arg = shift @ARGV;
if ($arg eq "--add") {
usageError if scalar @ARGV != 1;
addChannel (shift @ARGV);
last;
}
if ($arg eq "--remove") {
usageError if scalar @ARGV != 1;
removeChannel (shift @ARGV);
last;
}
if ($arg eq "--list") {
usageError if scalar @ARGV != 0;
readChannels;
foreach my $url (@channels) {
print "$url\n";
}
last;
}
elsif ($arg eq "--update") {
usageError if scalar @ARGV != 0;
update;
last;
}
elsif ($arg eq "--help") {
usageError;
}
else {
die "unknown argument `$arg'; try `--help'";
}
}