#! @perl@ -w use strict; my $rootsDir = "@localstatedir@/nix/gcroots/channels"; my $stateDir = $ENV{"NIX_STATE_DIR"}; $stateDir = "@localstatedir@/nix" unless defined $stateDir; # 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 @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; 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; # Get rid of all the old substitutes. system("@bindir@/nix-store", "--clear-substitutes") == 0 or die "cannot clear substitutes"; # 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", "$url/MANIFEST") == 0 or die "cannot pull cache manifest from `$url'"; } # Create a Nix expression that fetches and unpacks the channel Nix # expressions. my $nixExpr = "["; foreach my $url (@channels) { my $fullURL = "$url/nixexprs.tar.bz2"; $ENV{"PRINT_PATH"} = 1; my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL' 2> /dev/null`; die "cannot fetch `$fullURL'" if $? != 0; chomp $path; $nixExpr .= $path . " "; } $nixExpr .= "]"; $nixExpr = "(import @datadir@/nix/corepkgs/channels/unpack.nix) " . "{inputs = $nixExpr; system = \"@system@\";}"; # Figure out a name for the GC root. my $userName = getpwuid($<); die "who ARE you? go away" unless defined $userName; my $rootFile = "$rootsDir/$userName"; # Instantiate the Nix expression. my $storeExpr = `echo '$nixExpr' | @bindir@/nix-instantiate --add-root '$rootFile'.tmp -` 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 it the default Nix expression for `nix-env'. system("@bindir@/nix-env", "--import", "$outPath") == 0 or die "cannot pull set default Nix expression 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'"; } }