I.e. do what git does. I'm too lazy to keep the builtin help text up to date :-) Also add ‘--help’ to various commands that lacked it (e.g. nix-collect-garbage).
		
			
				
	
	
		
			207 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Text
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Text
		
	
	
		
			Executable file
		
	
	
	
	
#! @perl@ -w @perlFlags@
 | 
						|
 | 
						|
use strict;
 | 
						|
use File::Basename;
 | 
						|
use File::Path qw(mkpath);
 | 
						|
use Nix::Config;
 | 
						|
use Nix::Manifest;
 | 
						|
 | 
						|
Nix::Config::readConfig;
 | 
						|
 | 
						|
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"} or die '$HOME not set\n';
 | 
						|
my $channelsList = "$home/.nix-channels";
 | 
						|
my $nixDefExpr = "$home/.nix-defexpr";
 | 
						|
 | 
						|
# 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";
 | 
						|
mkpath(dirname $profile, 0, 0755);
 | 
						|
 | 
						|
my %channels;
 | 
						|
 | 
						|
 | 
						|
# 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*\#/;
 | 
						|
        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.
 | 
						|
sub writeChannels {
 | 
						|
    open CHANNELS, ">$channelsList" or die "cannot open `$channelsList': $!";
 | 
						|
    foreach my $name (keys %channels) {
 | 
						|
        print CHANNELS "$channels{$name} $name\n";
 | 
						|
    }
 | 
						|
    close CHANNELS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
# Adds a channel.
 | 
						|
sub addChannel {
 | 
						|
    my ($url, $name) = @_;
 | 
						|
    readChannels;
 | 
						|
    $channels{$name} = $url;
 | 
						|
    writeChannels;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
# Remove a channel.
 | 
						|
sub removeChannel {
 | 
						|
    my ($name) = @_;
 | 
						|
    readChannels;
 | 
						|
    my $url = $channels{$name};
 | 
						|
    deleteOldManifests($url . "/MANIFEST", undef) if defined $url;
 | 
						|
    delete $channels{$name};
 | 
						|
    writeChannels;
 | 
						|
 | 
						|
    system("$Nix::Config::binDir/nix-env --profile '$profile' -e '$name'") == 0
 | 
						|
        or die "cannot remove channel `$name'\n";
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
# Fetch Nix expressions and pull manifests from the subscribed
 | 
						|
# channels.
 | 
						|
sub update {
 | 
						|
    my @channelNames = @_;
 | 
						|
 | 
						|
    readChannels;
 | 
						|
 | 
						|
    # Download each channel.
 | 
						|
    my $exprs = "";
 | 
						|
    foreach my $name (keys %channels) {
 | 
						|
        next if scalar @channelNames > 0 && ! grep { $_ eq $name } @{channelNames};
 | 
						|
 | 
						|
        my $url = $channels{$name};
 | 
						|
        my $origUrl = "$url/MANIFEST";
 | 
						|
 | 
						|
        # Check if $url is a redirect.  If so, follow it now to ensure
 | 
						|
        # consistency if the redirection is changed between
 | 
						|
        # downloading the manifest and the tarball.
 | 
						|
        my $headers = `$Nix::Config::curl --silent --head '$url'`;
 | 
						|
        die "$0: unable to check `$url'\n" if $? != 0;
 | 
						|
        $headers =~ s/\r//g;
 | 
						|
        $url = $1 if $headers =~ /^Location:\s*(.*)\s*$/m;
 | 
						|
 | 
						|
        # Check if the channel advertises a binary cache.
 | 
						|
        my $binaryCacheURL = `$Nix::Config::curl --silent '$url'/binary-cache-url`;
 | 
						|
        my $extraAttrs = "";
 | 
						|
        my $getManifest = ($Nix::Config::config{"force-manifest"} // "false") eq "true";
 | 
						|
        if ($? == 0 && $binaryCacheURL ne "") {
 | 
						|
            $extraAttrs .= "binaryCacheURL = \"$binaryCacheURL\"; ";
 | 
						|
            deleteOldManifests($origUrl, undef);
 | 
						|
        } else {
 | 
						|
            $getManifest = 1;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($getManifest) {
 | 
						|
            # No binary cache, so pull the channel manifest.
 | 
						|
            mkdir $manifestDir, 0755 unless -e $manifestDir;
 | 
						|
            die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir;
 | 
						|
            $ENV{'NIX_ORIG_URL'} = $origUrl;
 | 
						|
            system("$Nix::Config::binDir/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
 | 
						|
                or die "cannot pull manifest from `$url'\n";
 | 
						|
        }
 | 
						|
 | 
						|
        # Download the channel tarball.
 | 
						|
        my $fullURL = "$url/nixexprs.tar.bz2";
 | 
						|
        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'\n" if $? != 0;
 | 
						|
        chomp $path;
 | 
						|
 | 
						|
        # If the URL contains a version number, append it to the name
 | 
						|
        # attribute (so that "nix-env -q" on the channels profile
 | 
						|
        # shows something useful).
 | 
						|
        my $cname = $name;
 | 
						|
        $cname .= $1 if basename($url) =~ /(-\d.*)$/;
 | 
						|
 | 
						|
        $exprs .= "'f: f { name = \"$cname\"; channelName = \"$name\"; src = builtins.storePath \"$path\"; $extraAttrs }' ";
 | 
						|
    }
 | 
						|
 | 
						|
    # 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($profile, $channelLink) or die "cannot symlink `$channelLink' to `$profile'";
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
die "$0: argument expected\n" if scalar @ARGV == 0;
 | 
						|
 | 
						|
 | 
						|
while (scalar @ARGV) {
 | 
						|
    my $arg = shift @ARGV;
 | 
						|
 | 
						|
    if ($arg eq "--add") {
 | 
						|
        die "$0: `--add' requires one or two arguments\n" 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") {
 | 
						|
        die "$0: `--remove' requires one argument\n" if scalar @ARGV != 1;
 | 
						|
        removeChannel(shift @ARGV);
 | 
						|
        last;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($arg eq "--list") {
 | 
						|
        die "$0: `--list' requires one argument\n" if scalar @ARGV != 0;
 | 
						|
        readChannels;
 | 
						|
        foreach my $name (keys %channels) {
 | 
						|
            print "$name $channels{$name}\n";
 | 
						|
        }
 | 
						|
        last;
 | 
						|
    }
 | 
						|
 | 
						|
    elsif ($arg eq "--update") {
 | 
						|
        update(@ARGV);
 | 
						|
        last;
 | 
						|
    }
 | 
						|
 | 
						|
    elsif ($arg eq "--help") {
 | 
						|
        exec "man nix-channel" or die;
 | 
						|
    }
 | 
						|
 | 
						|
    elsif ($arg eq "--version") {
 | 
						|
        print "nix-channel (Nix) $Nix::Config::version\n";
 | 
						|
        exit 0;
 | 
						|
    }
 | 
						|
 | 
						|
    else {
 | 
						|
        die "unknown argument `$arg'; try `--help'\n";
 | 
						|
    }
 | 
						|
}
 |