forked from lix-project/lix
![Eelco Dolstra](/assets/img/avatar_default.png)
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".)
203 lines
5.2 KiB
Plaintext
203 lines
5.2 KiB
Plaintext
#! @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'";
|
|
}
|
|
}
|