Nix expressions in that directory are combined into an attribute set
  {file1 = import file1; file2 = import file2; ...}, i.e. each Nix
  expression is an attribute with the file name as the attribute
  name.  Also recurses into directories.
* nix-env: removed the "--import" (-I) option which set the
  ~/.nix-defexpr symlink.
* nix-channel: don't use "nix-env --import", instead symlink
  ~/.nix-defexpr/channels.  So finally nix-channel --update doesn't
  override any default Nix expressions but combines with them.
  This means that you can have (say) a local Nixpkgs SVN tree and use
  it as a default for nix-env:
  $ ln -s .../path-to-nixpkgs-tree ~/.nix-defexpr/nixpkgs_svn
  and be subscribed to channels (including Nixpkgs) at the same time.
  (If there is any ambiguity, the -A flag can be used to
  disambiguate, e.g. "nix-env -i -A nixpkgs_svn.pan".)
		
	
			
		
			
				
	
	
		
			202 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
	
		
			5.2 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";
 | |
|     
 | |
|     # Instantiate the Nix expression.
 | |
|     print "unpacking channel Nix expressions...\n";
 | |
|     my $storeExpr = `@bindir@/nix-instantiate --add-root '$rootFile'.tmp @datadir@/nix/corepkgs/channels/unpack.nix --argstr system @system@ --arg inputs '$inputs'`
 | |
|         or die "cannot instantiate Nix expression";
 | |
|     chomp $storeExpr;
 | |
| 
 | |
|     # Build the resulting derivation.
 | |
|     my $outPath = `@bindir@/nix-store --add-root '$rootFile' -r '$storeExpr'`
 | |
|         or die "cannot realise store expression";
 | |
|     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'";
 | |
|     }
 | |
| }
 |