about summary refs log blame commit diff
path: root/scripts/nix-channel.in
blob: 3688063cba4e55a2dc6e9eefc6690b0335f46465 (plain) (tree)
1
2
3
4
5
6
7
8
9



            
                                             
 


                                                           
 

                                             
                                                  
                                                               

 



                                                         

                                      







                                                         
                                                                             

                        
                         







                                                        
                                                                             


















                                           












                                               




                                                                    


                                                                      






                                                                      





                                                                                   
 




                                                                      
                     
                                 


                                                             
 
                                              
                                                                 
                               

                                                                   

                                                 
                                                                
     
                   
 
                                        


                                                        
                                                           
    
                               
                                                   




                                                                               

                   

                           





                                                                                         
 
 









                          


 


                                



                          
                                        



                                 














                                        
                                
                                        


               



                              

          
                                                    

     
#! @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;

    # Create the manifests directory if it doesn't exist.
    mkdir "$stateDir/manifests", 0755 unless -e "$stateDir/manifests";

    # 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") {

        # 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'";
    }
}