* Base the Nixpkgs channel on

http://hydra.nixos.org/view/nixpkgs/unstable/.  So now the Nixpkgs
  channel corresponds to exactly one revision of Nixpkgs (i.e. no more
  binaries from previous revisions), there is some minimal assurance
  that the channel is okay (because the builds in the "unstable" view
  need to succeed), and older Nixpkgs pre-releases are available under
  http://nixos.org/releases/nixpkgs/.  This means we've come full
  circle, because this is how the Nixpkgs channel used to work before
  we had Hydra :-)

  The downside is that it can take longer for the channel to catch up
  with the Nixpkgs repository.  But that's only a problem for people
  who build from the Nixpkgs repository.


git-svn-id: https://nixos.org/repos/nix/release/trunk/channels@33565 70bd8c7a-acb8-0310-9f0d-9cc1c95dcdbb
This commit is contained in:
Eelco Dolstra 2012-04-04 14:45:24 +00:00
parent b847c5d809
commit 4d9d3a88a1
2 changed files with 72 additions and 128 deletions

View file

@ -1,81 +1,45 @@
# This script mirrors a remote Nix channel in the local filesystem.
# It downloads the remote manifest, then any NAR files that are not
# already available in the target directory. If $ENABLE_PATCHES is
# set, it also generates patches between the NAR files in the old
# version of the manifest and the new version. Because this script
# can take a long time to finish, it uses a lock to guard against
# concurrent updates, allowing it to be run periodically from a cron
# job.
# already available in the target directory.
use strict;
use Nix::Manifest;
use Nix::GeneratePatches;
use File::Basename;
use File::stat;
use File::Temp qw/tempfile tempdir/;
use Fcntl ':flock';
use POSIX qw(strftime);
if (scalar @ARGV != 6 && scalar @ARGV != 7) {
print STDERR "Syntax: perl mirror-channel.pl <src-channel-url> <dst-channel-dir> <nar-dir> <nar-url> <patches-dir> <patches-url> [<nix-exprs-url>]\n";
if (scalar @ARGV < 4 || scalar @ARGV > 6) {
print STDERR "Syntax: perl mirror-channel.pl <src-channel-url> <dst-channel-dir> <nar-dir> <nar-url> [<all-patches-manifest [<nix-exprs-url>]]\n";
exit 1;
}
my $curl = "curl --location --silent --show-error --fail";
my $curl = "curl --location --no-progress-bar --show-error --fail";
my $srcChannelURL = $ARGV[0];
my $dstChannelPath = $ARGV[1];
my $narPath = $ARGV[2];
my $narURL = $ARGV[3];
my $patchesPath = $ARGV[4];
my $patchesURL = $ARGV[5];
my $nixexprsURL = $ARGV[6] || "$srcChannelURL/nixexprs.tar.bz2";
my $enablePatches = defined $ENV{'ENABLE_PATCHES'} && -e "$dstChannelPath/MANIFEST";
my $allPatchesManifest = $ARGV[4] || "";
my $nixexprsURL = $ARGV[5] || "$srcChannelURL/nixexprs.tar.bz2";
die "$dstChannelPath doesn't exist\n" unless -d $dstChannelPath;
die "$narPath doesn't exist\n" unless -d $narPath;
die "$patchesPath doesn't exist\n" unless -d $patchesPath;
my $manifestPath = "$dstChannelPath/MANIFEST";
my $tmpDir = tempdir("nix-mirror-XXXXXXX", TMPDIR => 1, CLEANUP => 1);
# Fetch the manifest.
system("$curl '$srcChannelURL/MANIFEST' > $dstChannelPath/MANIFEST") == 0 or die;
open LOCK, ">$dstChannelPath/.lock" or die;
flock LOCK, LOCK_EX;
print STDERR "started mirroring at ", strftime("%a %b %e %H:%M:%S %Y", localtime), "\n";
# Backup the old manifest once per day.
my $backupPath = strftime("$dstChannelPath/MANIFEST.backup-%Y%m%d", gmtime);
if (-f $manifestPath && ! -f $backupPath) {
system "cp $manifestPath $backupPath";
}
# Read the old manifest, if available.
my %narFilesOld;
my %patchesOld;
readManifest($manifestPath, \%narFilesOld, \%patchesOld)
if -f $manifestPath;
my %knownURLs;
while (my ($storePath, $files) = each %narFilesOld) {
$knownURLs{$_->{url}} = $_ foreach @{$files};
}
# Fetch the new manifest.
my $srcManifest = "$tmpDir/MANIFEST.src";
system("$curl '$srcChannelURL/MANIFEST' > $srcManifest") == 0 or die;
# Mirror nixexprs.tar.bz2.
system("$curl '$nixexprsURL' > $dstChannelPath/nixexprs.tar.bz2") == 0 or die "cannot download `$nixexprsURL'";
# Read the manifest.
my (%narFiles, %patches);
readManifest($srcManifest, \%narFiles, \%patches);
readManifest("$dstChannelPath/MANIFEST", \%narFiles, \%patches);
%patches = (); # not supported yet
@ -108,20 +72,13 @@ while (my ($storePath, $files) = each %narFiles) {
# Verify whether the downloaded file is a bzipped NAR file
# that matches the NAR hash given in the manifest.
system("bunzip2 < $dstFileTmp > $tmpDir/out") == 0 or die "downloaded file is not a bzip2 file!";
my $hash = `nix-hash --type sha256 --flat $tmpDir/out`;
my $hash = `bunzip2 < $dstFileTmp | nix-hash --type sha256 --flat /dev/stdin` or die;
chomp $hash;
die "hash mismatch in downloaded file `$srcURL'" if "sha256:$hash" ne $file->{narHash};
rename($dstFileTmp, $dstFile) or die "cannot rename $dstFileTmp";
}
my $old = $knownURLs{$dstURL};
if (defined $old) {
$file->{size} = $old->{size};
$file->{hash} = $old->{hash};
} else {
$file->{size} = stat($dstFile)->size or die "cannot get size of $dstFile";
my $hashFile = "$narPath/.hash.$dstName";
@ -140,7 +97,6 @@ while (my ($storePath, $files) = each %narFiles) {
$file->{hash} = "sha256:$hash";
}
}
}
# Read all the old patches and propagate the useful ones. We use the
@ -148,62 +104,11 @@ while (my ($storePath, $files) = each %narFiles) {
# generated in the past, so that patches are not lost if (for
# instance) a package temporarily disappears from the source channel,
# or if multiple instances of this script are running concurrently.
my (%dummy1, %dummy2, %allPatches);
sub readAllPatches {
readManifest("$patchesPath/all-patches", \%dummy1, \%dummy2, \%allPatches)
if -f "$patchesPath/all-patches";
}
readAllPatches;
my (%dummy, %allPatches);
readManifest($allPatchesManifest, \%dummy, \%allPatches)
if $allPatchesManifest ne "" && -f $allPatchesManifest;
propagatePatches \%allPatches, \%narFiles, \%patches;
propagatePatches \%patchesOld, \%narFiles, \%patches; # not really needed
# Make the temporary manifest available.
writeManifest("$dstChannelPath/MANIFEST.tmp", \%narFiles, \%patches);
rename("$dstChannelPath/MANIFEST.tmp", "$manifestPath") or die;
rename("$dstChannelPath/MANIFEST.tmp.bz2", "$manifestPath.bz2") or die;
# Mirror nixexprs.tar.bz2. This should really be done atomically with updating the manifest.
my $tmpFile = "$dstChannelPath/.tmp.$$.nixexprs.tar.bz2";
system("$curl '$nixexprsURL' > $tmpFile") == 0 or die "cannot download `$nixexprsURL'";
rename($tmpFile, "$dstChannelPath/nixexprs.tar.bz2") or die "cannot rename $tmpFile";
# Release the lock on the manifest to allow the manifest to be updated
# by other runs of this script while we're generating patches.
flock LOCK, LOCK_UN;
if ($enablePatches) {
# Generate patches asynchronously. This can take a long time.
generatePatches(\%narFilesOld, \%narFiles, \%allPatches, \%patches,
$narPath, $patchesPath, $patchesURL, $tmpDir);
# Lock all-patches.
open PLOCK, ">$patchesPath/all-patches.lock" or die;
flock PLOCK, LOCK_EX;
# Update the list of all patches. We need to reread all-patches
# and merge in our new patches because the file may have changed
# in the meantime.
readAllPatches;
copyPatches \%patches, \%allPatches;
writeManifest("$patchesPath/all-patches", {}, \%allPatches, 0);
# Reacquire the manifest lock.
flock LOCK, LOCK_EX;
# Rewrite the manifest. We have to reread it and propagate all
# patches because it may have changed in the meantime.
readManifest($manifestPath, \%narFiles, \%patches);
propagatePatches \%allPatches, \%narFiles, \%patches;
writeManifest($manifestPath, \%narFiles, \%patches);
}
writeManifest("$dstChannelPath/MANIFEST", \%narFiles, \%patches);

39
mirror-nixpkgs.sh Executable file
View file

@ -0,0 +1,39 @@
#! /bin/sh -e
viewUrl=http://hydra.nixos.org/view/nixpkgs/unstable/latest-finished
releasesDir=/data/releases/nixpkgs
channelLink=/data/releases/nixpkgs/channels/nixpkgs-unstable
curl="curl --silent --show-error --fail"
url=$($curl --head $viewUrl | sed 's/Location: \(.*\)\r/\1/; t; d')
if [ -z "$url" ]; then exit 1; fi
echo "View page is $url"
release=$($curl $url | sed 's|<h1>View.*(<tt>\(.*\)</tt>.*|\1|; t; d')
if [ -z "$release" ]; then echo "Failed to get release"; exit 1; fi
echo "Release is $release"
releaseDir=$releasesDir/$release
echo $releaseDir
if [ -d $releaseDir ]; then
echo "Release already exists"
else
tmpDir=$releasesDir/.tmp-$release-$$
mkdir -p $tmpDir
echo $url > $tmpDir/src-url
perl -w ./mirror-channel.pl "$url/eval/channel" "$tmpDir" \
/data/releases/nars http://nixos.org/releases/nars \
/data/releases/patches/all-patches "$url/tarball/download/4"
mv $tmpDir $releaseDir
fi
htaccess=$(dirname $channelLink)/.htaccess
echo "Redirect /releases/nixpkgs/channels/nixpkgs-unstable http://nixos.org/releases/nixpkgs/$release" > $htaccess.tmp
ln -sfn $releaseDir $channelLink # dummy symlink
mv $htaccess.tmp $htaccess