From 21655a70f5a6e80b477d8bf758aa24eb0fcbdbfe Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 21 Apr 2004 14:54:05 +0000 Subject: [PATCH] * Channels. These allow you to stay current with an evolving set of Nix expressions. To subscribe to a channel (needs to be done only once): nix-channel --add \ http://catamaran.labs.cs.uu.nl/dist/nix/channels/nixpkgs-unstable This just adds the given URL to ~/.nix-channels (which can also be edited manually). To update from all channels: nix-channel --update This fetches the latest expressions and pulls cache manifests. The default Nix expression (~/.nix-defexpr) is made to point to the conjunction of the expressions downloaded from all channels. So to update all installed derivations in the current user environment: nix-channel --update nix-env --upgrade '*' If you are really courageous, you can put this in a cronjob or something. You can subscribe to multiple channels. It is not entirely clear what happens when there are name clashes between derivations from different channels. From nix-env/main.cc it appears that the one with the lowest (highest?) hash will be used, which is pretty meaningless. --- configure.ac | 1 + corepkgs/Makefile.am | 2 +- corepkgs/channels/Makefile.am | 11 ++++ corepkgs/channels/unpack.nix | 7 ++ corepkgs/channels/unpack.sh.in | 24 +++++++ corepkgs/fetchurl/default.nix | 8 +-- scripts/Makefile.am | 3 +- scripts/nix-channel.in | 115 +++++++++++++++++++++++++++++++++ scripts/nix-prefetch-url.in | 71 ++++++++------------ scripts/nix-push.in | 4 +- 10 files changed, 194 insertions(+), 52 deletions(-) create mode 100644 corepkgs/channels/Makefile.am create mode 100644 corepkgs/channels/unpack.nix create mode 100644 corepkgs/channels/unpack.sh.in create mode 100755 scripts/nix-channel.in diff --git a/configure.ac b/configure.ac index df9e8249a..60f9e1ff3 100644 --- a/configure.ac +++ b/configure.ac @@ -140,6 +140,7 @@ AC_CONFIG_FILES([Makefile corepkgs/fetchurl/Makefile corepkgs/nar/Makefile corepkgs/buildenv/Makefile + corepkgs/channels/Makefile doc/Makefile doc/manual/Makefile ]) diff --git a/corepkgs/Makefile.am b/corepkgs/Makefile.am index 2fb23f1c0..c9ea11cef 100644 --- a/corepkgs/Makefile.am +++ b/corepkgs/Makefile.am @@ -1 +1 @@ -SUBDIRS = fetchurl nar buildenv +SUBDIRS = fetchurl nar buildenv channels diff --git a/corepkgs/channels/Makefile.am b/corepkgs/channels/Makefile.am new file mode 100644 index 000000000..1bf73f7f4 --- /dev/null +++ b/corepkgs/channels/Makefile.am @@ -0,0 +1,11 @@ +all-local: unpack.sh + +install-exec-local: + $(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs + $(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs/channels + $(INSTALL_DATA) unpack.nix $(DESTDIR)$(datadir)/nix/corepkgs/channels + $(INSTALL_PROGRAM) unpack.sh $(DESTDIR)$(datadir)/nix/corepkgs/channels + +include ../../substitute.mk + +EXTRA_DIST = default.nix unpack.sh.in diff --git a/corepkgs/channels/unpack.nix b/corepkgs/channels/unpack.nix new file mode 100644 index 000000000..80ca4a371 --- /dev/null +++ b/corepkgs/channels/unpack.nix @@ -0,0 +1,7 @@ +{system, inputs}: + +derivation { + name = "channels"; + builder = ./unpack.sh; + inherit system inputs; +} \ No newline at end of file diff --git a/corepkgs/channels/unpack.sh.in b/corepkgs/channels/unpack.sh.in new file mode 100644 index 000000000..f349f3da3 --- /dev/null +++ b/corepkgs/channels/unpack.sh.in @@ -0,0 +1,24 @@ +#! @shell@ -e + +export PATH=/bin:/usr/bin # !!! impure + +mkdir $out +mkdir $out/tmp +cd $out/tmp + +expr=$out/default.nix +echo '[' > $expr + +nr=0 +for i in $inputs; do + echo "unpacking $i" + @bunzip2@ < $i | tar xvf - + mv * ../$nr # !!! hacky + echo "(import ./$nr)" >> $expr + nr=$(($nr + 1)) +done + +echo ']' >> $expr + +cd .. +rmdir tmp \ No newline at end of file diff --git a/corepkgs/fetchurl/default.nix b/corepkgs/fetchurl/default.nix index 663bba4a3..8957662ec 100644 --- a/corepkgs/fetchurl/default.nix +++ b/corepkgs/fetchurl/default.nix @@ -1,8 +1,8 @@ -{system, url, md5}: derivation { +{system, url, md5}: + +derivation { name = baseNameOf (toString url); - system = system; builder = ./builder.sh; - url = url; - md5 = md5; id = md5; + inherit system url md5; } diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 13071b9f9..7e429aabe 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -1,6 +1,6 @@ bin_SCRIPTS = nix-collect-garbage \ nix-pull nix-push nix-prefetch-url \ - nix-install-package + nix-install-package nix-channel noinst_SCRIPTS = nix-profile.sh @@ -20,4 +20,5 @@ include ../substitute.mk EXTRA_DIST = nix-collect-garbage.in \ nix-pull.in nix-push.in nix-profile.sh.in \ nix-prefetch-url.in nix-install-package.in \ + nix-channel.in \ prebuilts.conf readmanifest.pm.in diff --git a/scripts/nix-channel.in b/scripts/nix-channel.in new file mode 100755 index 000000000..f554380e2 --- /dev/null +++ b/scripts/nix-channel.in @@ -0,0 +1,115 @@ +#! @perl@ -w + +use strict; + + +# 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 () { + 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; +} + + +# Fetch Nix expressions and pull cache manifests from the subscribed +# channels. +sub update { + readChannels; + + # Pull cache manifests. + foreach my $url (@channels) { + print "pulling cache manifest from `$url'\n"; + system "@bindir@/nix-pull '$url'/MANIFEST"; + die "cannot pull cache manifest from `$url'" if ($? != 0); + } + + # Create a Nix expression that fetches and unpacks the channel Nix + # expressions. + + my $nixExpr = "["; + + foreach my $url (@channels) { + my $fullURL = "$url/nixexprs.tar.bz2"; + my $hash = `@bindir@/nix-prefetch-url '$fullURL' 2> /dev/null` + or die "cannot fetch `$fullURL'"; + chomp $hash; + # !!! escaping + $nixExpr .= "((import @datadir@/nix/corepkgs/fetchurl) " . + "{url = $fullURL; md5 = \"$hash\"; system = \"@system@\";}) " + } + + $nixExpr .= "]"; + + $nixExpr = + "(import @datadir@/nix/corepkgs/channels/unpack.nix) " . + "{inputs = $nixExpr; system = \"@system@\";}"; + + # Instantiate and realise it. + my $storeExpr = `echo '$nixExpr' | @bindir@/nix-instantiate -` + or die "cannot instantiate Nix expression"; + chomp $storeExpr; + + my $outPath = `nix-store -qnfB '$storeExpr'` + or die "cannot realise store expression"; + chomp $outPath; + + # Make it the default Nix expression for `nix-env'. + system "@bindir@/nix-env --import '$outPath'"; + die "cannot pull set default Nix expression to `$outPath'" if ($? != 0); +} + + +while (scalar @ARGV) { + my $arg = shift @ARGV; + + if ($arg eq "--add") { + die "syntax: nix-channel --add URL" if (scalar @ARGV != 1); + addChannel (shift @ARGV); + last; + } + + elsif ($arg eq "--update") { + die "syntax: nix-channel --update" if (scalar @ARGV != 0); + update; + last; + } + + else { + die "unknown argument `$arg'"; + } +} diff --git a/scripts/nix-prefetch-url.in b/scripts/nix-prefetch-url.in index df6a1c86a..6a90e787c 100644 --- a/scripts/nix-prefetch-url.in +++ b/scripts/nix-prefetch-url.in @@ -1,56 +1,37 @@ -#! @perl@ -w +#! @shell@ -e -use strict; -use IPC::Open2; +url=$1 -my $url = shift @ARGV; -defined $url or die; +if test -z "$url"; then + echo "syntax: nix-prefetch-url URL" >&2 + exit 1 +fi -print "fetching $url...\n"; +# !!! race? should be relatively safe, `svn export' barfs if $tmpPath exists. +tmpPath1=@storedir@/nix-prefetch-url-$$ -my $out = "@storedir@/nix-prefetch-url-$$"; +# Perform the checkout. +@curl@ --fail --location --max-redirs 20 "$url" > $tmpPath1 -system "@curl@ --fail --location --max-redirs 20 \"$url\" > \"$out\""; -$? == 0 or die "unable to fetch $url"; +# Compute the hash. +hash=$(@bindir@/nix-hash --flat $tmpPath1) +echo "hash is $hash" >&2 -my $hash=`@bindir@/nix-hash --flat $out`; -$? == 0 or die "unable to hash $out"; -chomp $hash; +# Rename it so that the fetchsvn builder can find it. +tmpPath2=@storedir@/nix-prefetch-url-$hash +test -e $tmpPath2 || mv $tmpPath1 $tmpPath2 # !!! race -print "file has hash $hash\n"; +# Create a Nix expression that does a fetchsvn. +storeExpr=$( \ + echo "(import @datadir@/nix/corepkgs/fetchurl) \ + {url = $url; md5 = \"$hash\"; system = \"@system@\";}" \ + | nix-instantiate -) -my $out2 = "@storedir@/nix-prefetch-url-$hash"; -rename $out, $out2; +# Realise it. +finalPath=$(nix-store -qnB --force-realise $storeExpr) -# Create a Nix expression. -my $nixexpr = - "(import @datadir@/nix/corepkgs/fetchurl) " . - "{url = $url; md5 = \"$hash\"; system = \"@system@\";}"; +echo "path is $finalPath" >&2 -#print STDERR "expr: $nixexpr\n"; +rm -rf $tmpPath2 || true -# Instantiate a Nix expression. -#print STDERR "instantiating Nix expression...\n"; -my $pid = open2(\*READ, \*WRITE, "@bindir@/nix-instantiate -") - or die "cannot run nix-instantiate"; - -print WRITE $nixexpr; -close WRITE; - -my $drvpath = ; -chomp $drvpath; - -waitpid $pid, 0; -$? == 0 or die "nix-instantiate failed"; - -# Run Nix. -#print STDERR "realising store expression $drvpath...\n"; -system "@bindir@/nix-store --realise $drvpath > /dev/null"; -$? == 0 or die "realisation failed"; - -my $path = `@bindir@/nix-store -qn $drvpath`; -$? == 0 or die "query failed"; - -print "path is $path"; - -unlink $out2; +echo $hash diff --git a/scripts/nix-push.in b/scripts/nix-push.in index 02f40f04a..84330016f 100644 --- a/scripts/nix-push.in +++ b/scripts/nix-push.in @@ -12,7 +12,9 @@ my $manifest = "$tmpdir/MANIFEST"; END { unlink $manifest; unlink $nixfile; rmdir $tmpdir; } -my $curl = "@curl@ --fail --silent ${ENV{'CURL_FLAGS'}}"; +my $curl = "@curl@ --fail --silent"; +my $extraCurlFlags = ${ENV{'CURL_FLAGS'}}; +$curl = "$curl $extraCurlFlags" if defined $extraCurlFlags; # Parse the command line.