#! @perl@ -w use strict; use Nix::Config; my $manifestDir = $Nix::Config::manifestDir; # Turn on caching in nix-prefetch-url. my $channelCache = "$Nix::Config::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 () { 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; # Create the manifests directory if it doesn't exist. mkdir $manifestDir, 0755 unless -e $manifestDir; # 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 $manifestDir) { # Pull cache manifests. foreach my $url (@channels) { #print "pulling cache manifest from `$url'\n"; system("$Nix::Config::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) = `$Nix::Config::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 = "$Nix::Config::stateDir/gcroots/per-user/$userName/channels"; # Build the Nix expression. print "unpacking channel Nix expressions...\n"; my $outPath = `\\ $Nix::Config::binDir/nix-build --out-link '$rootFile' --drv-link '$rootFile'.tmp \\ '' \\ --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 <