about summary refs log tree commit diff
path: root/scripts/nix-channel.in
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2012-04-14T16·38+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2012-04-14T16·38+0200
commite855c7e2c9a9a5cbe4406c1f9351181a9ebe6283 (patch)
tree1de5115d72e5ec55080a831297058dd0eb49b3be /scripts/nix-channel.in
parent969a14599d2f7bfd02971475b5b2be49fb965117 (diff)
nix-channel improvements
"nix-channel --add" now accepts a second argument: the channel name.
This allows channels to have a nicer name than (say) nixpkgs_unstable.
If no name is given, it defaults to the last component of the URL
(with "-unstable" or "-stable" removed).

Also, channels are now stored in a profile
(/nix/var/nix/profiles/per-user/$USER/channels).  One advantage of
this is that it allows rollbacks (e.g. if "nix-channel --update" gives
an undesirable update).
Diffstat (limited to 'scripts/nix-channel.in')
-rwxr-xr-xscripts/nix-channel.in129
1 files changed, 60 insertions, 69 deletions
diff --git a/scripts/nix-channel.in b/scripts/nix-channel.in
index ebfc246cfa30..283071a9c8b1 100755
--- a/scripts/nix-channel.in
+++ b/scripts/nix-channel.in
@@ -1,6 +1,8 @@
 #! @perl@ -w @perlFlags@
 
 use strict;
+use File::Basename;
+use File::Path qw(make_path);
 use Nix::Config;
 
 my $manifestDir = $Nix::Config::manifestDir;
@@ -11,67 +13,67 @@ 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 $home = $ENV{"HOME"} or die '$HOME not set\n';
 my $channelsList = "$home/.nix-channels";
-
 my $nixDefExpr = "$home/.nix-defexpr";
-    
 
-my @channels;
+# Figure out the name of the channels profile.
+my $userName = getpwuid($<) or die "cannot figure out user name";
+my $profile = "$Nix::Config::stateDir/profiles/per-user/$userName/channels";
+make_path(dirname $profile, mode => 0755);
+    
+my %channels;
 
 
-# Reads the list of channels from the file $channelsList;
+# Reads the list of channels.
 sub readChannels {
     return if (!-f $channelsList);
     open CHANNELS, "<$channelsList" or die "cannot open `$channelsList': $!";
     while (<CHANNELS>) {
         chomp;
         next if /^\s*\#/;
-        push @channels, $_;
+        my ($url, $name) = split ' ', $_;
+        $url =~ s/\/*$//; # remove trailing slashes
+        $name = basename $url unless defined $name;
+        $channels{$name} = $url;
     }
     close CHANNELS;
 }
 
 
-# Writes the list of channels to the file $channelsList;
+# Writes the list of channels.
 sub writeChannels {
     open CHANNELS, ">$channelsList" or die "cannot open `$channelsList': $!";
-    foreach my $url (@channels) {
-        print CHANNELS "$url\n";
+    foreach my $name (keys %channels) {
+        print CHANNELS "$channels{$name} $name\n";
     }
     close CHANNELS;
 }
 
 
-# Adds a channel to the file $channelsList;
+# Adds a channel.
 sub addChannel {
-    my $url = shift;
+    my ($url, $name) = @_;
     readChannels;
-    foreach my $url2 (@channels) {
-        return if $url eq $url2;
-    }
-    push @channels, $url;
+    $channels{$name} = $url;
     writeChannels;
 }
 
 
-# Remove a channel from the file $channelsList;
+# Remove a channel.
 sub removeChannel {
-    my $url = shift;
-    my @left = ();
+    my ($name) = @_;
     readChannels;
-    foreach my $url2 (@channels) {
-        push @left, $url2 if $url ne $url2;
-    }
-    @channels = @left;
+    delete $channels{$name};
     writeChannels;
+
+    system("$Nix::Config::binDir/nix-env --profile '$profile' -e '$name'") == 0
+        or die "cannot remove channel `$name'";
 }
 
 
-# Fetch Nix expressions and pull cache manifests from the subscribed
+# Fetch Nix expressions and pull manifests from the subscribed
 # channels.
 sub update {
     readChannels;
@@ -82,64 +84,46 @@ sub update {
     # Do we have write permission to the manifests directory?
     die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir;
 
-    # Pull cache manifests.
-    foreach my $url (@channels) {
-        #print "pulling cache manifest from `$url'\n";
+    # Download each channel.
+    my $exprs = "";
+    foreach my $name (keys %channels) {
+        my $url = $channels{$name};
+        
+        # Pull the channel manifest.
         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;
+            or die "cannot pull manifest from `$url'\n";
 
+        # Download the channel tarball.
         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'`;
+        print STDERR "downloading Nix expressions from `$fullURL'...\n";
+        my ($hash, $path) = `PRINT_PATH=1 QUIET=1 $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 \\
-        '<nix/unpack-channel.nix>' \\
-        --argstr system @system@ --arg inputs '$inputs'`
-        or die "cannot unpack the channels";
-    chomp $outPath;
+        $exprs .= "'f: f { name = \"$name\"; src = builtins.storePath \"$path\"; }' ";
+    }
 
-    unlink "$rootFile.tmp";
+    # Unpack the channel tarballs into the Nix store and install them
+    # into the channels profile.
+    print STDERR "unpacking channels...\n";
+    system("$Nix::Config::binDir/nix-env --profile '$profile' " .
+           "-f '<nix/unpack-channel.nix>' -i -E $exprs --quiet") == 0
+           or die "cannot unpack the channels";
 
     # 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'";
+    symlink($profile, $channelLink) or die "cannot symlink `$channelLink' to `$profile'";
 }
 
 
 sub usageError {
     print STDERR <<EOF;
 Usage:
-  nix-channel --add URL
-  nix-channel --remove URL
+  nix-channel --add URL [CHANNEL-NAME]
+  nix-channel --remove CHANNEL-NAME
   nix-channel --list
   nix-channel --update
 EOF
@@ -154,22 +138,29 @@ while (scalar @ARGV) {
     my $arg = shift @ARGV;
 
     if ($arg eq "--add") {
-        usageError if scalar @ARGV != 1;
-        addChannel (shift @ARGV);
+        usageError if scalar @ARGV < 1 || scalar @ARGV > 2;
+        my $url = shift @ARGV;
+        my $name = shift @ARGV;
+        unless (defined $name) {
+            $name = basename $url;
+            $name =~ s/-unstable//;
+            $name =~ s/-stable//;
+        }
+        addChannel($url, $name);
         last;
     }
 
     if ($arg eq "--remove") {
         usageError if scalar @ARGV != 1;
-        removeChannel (shift @ARGV);
+        removeChannel(shift @ARGV);
         last;
     }
 
     if ($arg eq "--list") {
         usageError if scalar @ARGV != 0;
         readChannels;
-        foreach my $url (@channels) {
-            print "$url\n";
+        foreach my $name (keys %channels) {
+            print "$name $channels{$name}\n";
         }
         last;
     }