diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2012-04-14 18:38:52 +0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2012-04-14 18:38:52 +0200 |
commit | e855c7e2c9a9a5cbe4406c1f9351181a9ebe6283 (patch) | |
tree | 1de5115d72e5ec55080a831297058dd0eb49b3be | |
parent | 969a14599d2f7bfd02971475b5b2be49fb965117 (diff) | |
download | guix-e855c7e2c9a9a5cbe4406c1f9351181a9ebe6283.tar.gz |
nix-channel improvements
"nix-channel --add" now accepts a second argument: the channel name. This allows channels to have a nicer name than (say) nixpkgs_unstable. If no name is given, it defaults to the last component of the URL (with "-unstable" or "-stable" removed). Also, channels are now stored in a profile (/nix/var/nix/profiles/per-user/$USER/channels). One advantage of this is that it allows rollbacks (e.g. if "nix-channel --update" gives an undesirable update).
-rw-r--r-- | corepkgs/unpack-channel.nix | 6 | ||||
-rw-r--r-- | corepkgs/unpack-channel.sh | 32 | ||||
-rw-r--r-- | doc/manual/nix-channel.xml | 48 | ||||
-rw-r--r-- | doc/manual/nix-store.xml | 5 | ||||
-rwxr-xr-x | scripts/nix-channel.in | 129 | ||||
-rw-r--r-- | tests/nix-channel.sh | 4 |
6 files changed, 104 insertions, 120 deletions
diff --git a/corepkgs/unpack-channel.nix b/corepkgs/unpack-channel.nix index 5e6ccf23fd..eba957dff4 100644 --- a/corepkgs/unpack-channel.nix +++ b/corepkgs/unpack-channel.nix @@ -1,11 +1,11 @@ with import <nix/config.nix>; -{ system, inputs }: +{ name, src }: derivation { - name = "channels"; + system = builtins.currentSystem; builder = shell; args = [ "-e" ./unpack-channel.sh ]; - inherit system inputs bzip2 tar tr; + inherit name src bzip2 tar tr; PATH = "${nixBinDir}:${coreutils}"; } diff --git a/corepkgs/unpack-channel.sh b/corepkgs/unpack-channel.sh index 7c244a6a85..0b7d89bc46 100644 --- a/corepkgs/unpack-channel.sh +++ b/corepkgs/unpack-channel.sh @@ -1,30 +1,4 @@ mkdir $out -mkdir $out/tmp -cd $out/tmp - -inputs=($inputs) -for ((n = 0; n < ${#inputs[*]}; n += 2)); do - channelName=${inputs[n]} - channelTarball=${inputs[n+1]} - - echo "unpacking channel $channelName" - - $bzip2 -d < $channelTarball | $tar xf - - - if test -e */channel-name; then - channelName="$(cat */channel-name)" - fi - - nr=1 - attrName=$(echo $channelName | $tr -- '- ' '__') - dirName=$attrName - while test -e ../$dirName; do - nr=$((nr+1)) - dirName=$attrName-$nr - done - - mv * ../$dirName # !!! hacky -done - -cd .. -rmdir tmp +cd $out +$bzip2 -d < $src | $tar xf - +mv * $out/$name diff --git a/doc/manual/nix-channel.xml b/doc/manual/nix-channel.xml index 024add8601..22d8900d8f 100644 --- a/doc/manual/nix-channel.xml +++ b/doc/manual/nix-channel.xml @@ -19,7 +19,7 @@ <cmdsynopsis> <command>nix-channel</command> <group choice='req'> - <arg choice='plain'><option>--add</option> <replaceable>url</replaceable></arg> + <arg choice='plain'><option>--add</option> <replaceable>url</replaceable> <arg choice='opt'><replaceable>name</replaceable></arg></arg> <arg choice='plain'><option>--remove</option> <replaceable>url</replaceable></arg> <arg choice='plain'><option>--list</option></arg> <arg choice='plain'><option>--update</option></arg> @@ -31,32 +31,39 @@ <para>A Nix channel is mechanism that allows you to automatically stay up-to-date with a set of pre-built Nix expressions. A Nix channel is -just a URL that points to a place that contains a set of Nix -expressions, as well as a <command>nix-push</command> manifest. See -also <xref linkend="sec-channels" />.</para> +just a URL that points to a place containing a set of Nix expressions +and a <command>nix-push</command> manifest. <phrase +condition="manual">See also <xref linkend="sec-channels" +/>.</phrase></para> <para>This command has the following operations: <variablelist> - <varlistentry><term><option>--add</option> <replaceable>url</replaceable></term> + <varlistentry><term><option>--add</option> <replaceable>url</replaceable> [<replaceable>name</replaceable>]</term> - <listitem><para>Adds <replaceable>url</replaceable> to the list of - subscribed channels.</para></listitem> + <listitem><para>Adds a channel named + <replaceable>name</replaceable> with URL + <replaceable>url</replaceable> to the list of subscribed channels. + If <replaceable>name</replaceable> is omitted, it defaults to the + last component of <replaceable>url</replaceable>, with the + suffixes <literal>-stable</literal> or + <literal>-unstable</literal> removed.</para></listitem> </varlistentry> - <varlistentry><term><option>--remove</option> <replaceable>url</replaceable></term> + <varlistentry><term><option>--remove</option> <replaceable>name</replaceable></term> - <listitem><para>Removes <replaceable>url</replaceable> from the - list of subscribed channels.</para></listitem> + <listitem><para>Removes the channel named + <replaceable>name</replaceable> from the list of subscribed + channels.</para></listitem> </varlistentry> <varlistentry><term><option>--list</option></term> - <listitem><para>Prints the URLs of all subscribed channels on - standard output.</para></listitem> + <listitem><para>Prints the names and URLs of all subscribed + channels on standard output.</para></listitem> </varlistentry> @@ -64,7 +71,7 @@ also <xref linkend="sec-channels" />.</para> <listitem><para>Downloads the Nix expressions of all subscribed channels, makes them the default for <command>nix-env</command> - operations (by symlinking them in the directory + operations (by symlinking them from the directory <filename>~/.nix-defexpr</filename>), and performs a <command>nix-pull</command> on the manifests of all channels to make pre-built binaries available.</para></listitem> @@ -75,8 +82,8 @@ also <xref linkend="sec-channels" />.</para> </para> -<para>Note that <option>--add</option> and <option>--remove</option> -do not automatically perform an update.</para> +<para>Note that <option>--add</option> does not automatically perform +an update.</para> <para>The list of subscribed channels is stored in <filename>~/.nix-channels</filename>.</para> @@ -90,4 +97,15 @@ respectively.</para> </refsection> +<refsection><title>Examples</title> + +<para>To subscribe to the Nixpkgs channel and install the GNU Hello package:</para> + +<screen> +$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable +$ nix-channel --update +$ nix-env -iA nixpkgs.hello</screen> + +</refsection> + </refentry> diff --git a/doc/manual/nix-store.xml b/doc/manual/nix-store.xml index 6a4ca3f717..6cc765bf27 100644 --- a/doc/manual/nix-store.xml +++ b/doc/manual/nix-store.xml @@ -58,8 +58,9 @@ options.</phrase></para> <listitem><para>Causes the result of a realisation (<option>--realise</option> and <option>--force-realise</option>) - to be registered as a root of the garbage collector (see <xref - linkend="ssec-gc-roots" />). The root is stored in + to be registered as a root of the garbage collector<phrase + condition="manual"> (see <xref linkend="ssec-gc-roots" + />)</phrase>. The root is stored in <replaceable>path</replaceable>, which must be inside a directory that is scanned for roots by the garbage collector (i.e., typically in a subdirectory of diff --git a/scripts/nix-channel.in b/scripts/nix-channel.in index ebfc246cfa..283071a9c8 100755 --- a/scripts/nix-channel.in +++ b/scripts/nix-channel.in @@ -1,6 +1,8 @@ #! @perl@ -w @perlFlags@ use strict; +use File::Basename; +use File::Path qw(make_path); use Nix::Config; my $manifestDir = $Nix::Config::manifestDir; @@ -11,67 +13,67 @@ 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"}; -die '$HOME not set' unless defined $home; +my $home = $ENV{"HOME"} or die '$HOME not set\n'; my $channelsList = "$home/.nix-channels"; - my $nixDefExpr = "$home/.nix-defexpr"; - -my @channels; +# 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"; +make_path(dirname $profile, mode => 0755); + +my %channels; -# Reads the list of channels from the file $channelsList; +# 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*\#/; - push @channels, $_; + 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 to the file $channelsList; +# Writes the list of channels. sub writeChannels { open CHANNELS, ">$channelsList" or die "cannot open `$channelsList': $!"; - foreach my $url (@channels) { - print CHANNELS "$url\n"; + foreach my $name (keys %channels) { + print CHANNELS "$channels{$name} $name\n"; } close CHANNELS; } -# Adds a channel to the file $channelsList; +# Adds a channel. sub addChannel { - my $url = shift; + my ($url, $name) = @_; readChannels; - foreach my $url2 (@channels) { - return if $url eq $url2; - } - push @channels, $url; + $channels{$name} = $url; writeChannels; } -# Remove a channel from the file $channelsList; +# Remove a channel. sub removeChannel { - my $url = shift; - my @left = (); + my ($name) = @_; readChannels; - foreach my $url2 (@channels) { - push @left, $url2 if $url ne $url2; - } - @channels = @left; + delete $channels{$name}; writeChannels; + + system("$Nix::Config::binDir/nix-env --profile '$profile' -e '$name'") == 0 + or die "cannot remove channel `$name'"; } -# Fetch Nix expressions and pull cache manifests from the subscribed +# Fetch Nix expressions and pull manifests from the subscribed # channels. sub update { readChannels; @@ -82,64 +84,46 @@ sub update { # Do we have write permission to the manifests directory? die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir; - # Pull cache manifests. - foreach my $url (@channels) { - #print "pulling cache manifest from `$url'\n"; + # Download each channel. + my $exprs = ""; + foreach my $name (keys %channels) { + my $url = $channels{$name}; + + # Pull the channel manifest. system("$Nix::Config::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; + or die "cannot pull manifest from `$url'\n"; + # Download the channel tarball. my $fullURL = "$url/nixexprs.tar.bz2"; - print "downloading Nix expressions from `$fullURL'...\n"; - $ENV{"PRINT_PATH"} = 1; - $ENV{"QUIET"} = 1; - my ($hash, $path) = `$Nix::Config::binDir/nix-prefetch-url '$fullURL'`; + 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'" 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 = "$Nix::Config::stateDir/gcroots/per-user/$userName/channels"; - - # Build the Nix expression. - print "unpacking channel Nix expressions...\n"; - my $outPath = `\\ - $Nix::Config::binDir/nix-build --out-link '$rootFile' --drv-link '$rootFile'.tmp \\ - '<nix/unpack-channel.nix>' \\ - --argstr system @system@ --arg inputs '$inputs'` - or die "cannot unpack the channels"; - chomp $outPath; + $exprs .= "'f: f { name = \"$name\"; src = builtins.storePath \"$path\"; }' "; + } - unlink "$rootFile.tmp"; + # 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($outPath, $channelLink) or die "cannot symlink `$channelLink' to `$outPath'"; + symlink($profile, $channelLink) or die "cannot symlink `$channelLink' to `$profile'"; } sub usageError { print STDERR <<EOF; Usage: - nix-channel --add URL - nix-channel --remove URL + nix-channel --add URL [CHANNEL-NAME] + nix-channel --remove CHANNEL-NAME nix-channel --list nix-channel --update EOF @@ -154,22 +138,29 @@ while (scalar @ARGV) { my $arg = shift @ARGV; if ($arg eq "--add") { - usageError if scalar @ARGV != 1; - addChannel (shift @ARGV); + usageError 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") { usageError if scalar @ARGV != 1; - removeChannel (shift @ARGV); + removeChannel(shift @ARGV); last; } if ($arg eq "--list") { usageError if scalar @ARGV != 0; readChannels; - foreach my $url (@channels) { - print "$url\n"; + foreach my $name (keys %channels) { + print "$name $channels{$name}\n"; } last; } diff --git a/tests/nix-channel.sh b/tests/nix-channel.sh index 4819b57c91..eb1d572953 100644 --- a/tests/nix-channel.sh +++ b/tests/nix-channel.sh @@ -9,9 +9,9 @@ rm -f $TEST_ROOT/.nix-channels export HOME=$TEST_ROOT # Test add/list/remove. -nix-channel --add http://foo/bar +nix-channel --add http://foo/bar xyzzy nix-channel --list | grep -q http://foo/bar -nix-channel --remove http://foo/bar +nix-channel --remove xyzzy [ -e $TEST_ROOT/.nix-channels ] [ "$(cat $TEST_ROOT/.nix-channels)" = '' ] |