* Quick script to mirror Nix channels. Ideally it should be possible

to do this with a `wget -r' but the manifest contains absolute
  rather than relative URLs, so those have to be rewritten.  And since
  they have to be rewritten anyway, we can add size and hash fields to
  make the manifest compatible with older version of Nix (and make the
  download size estimate work).


git-svn-id: https://nixos.org/repos/nix/release/trunk/channels@15076 70bd8c7a-acb8-0310-9f0d-9cc1c95dcdbb
This commit is contained in:
Eelco Dolstra 2009-04-16 09:25:42 +00:00
commit a5c419b725

74
mirror-channel.pl Normal file
View file

@ -0,0 +1,74 @@
use strict;
use readmanifest;
use File::Basename;
use File::stat;
use File::Temp qw/tempfile/;
if (scalar @ARGV != 3) {
print STDERR "Syntax: perl mirror-channel.pl <src-channel-url> <dst-channel-url> <dst-channel-dir>\n";
exit 1;
}
my $srcChannelURL = $ARGV[0];
my $dstChannelURL = $ARGV[1];
my $dstChannelPath = $ARGV[2];
die "$dstChannelPath doesn't exist\n" unless -d $dstChannelPath;
my ($fh, $tmpManifest) = tempfile(UNLINK => 1);
print "$tmpManifest\n";
system("curl '$srcChannelURL/MANIFEST' > $tmpManifest") == 0 or die;
# Read the manifest.
my %narFiles;
my %localPaths;
my %patches;
my $version = readManifest($tmpManifest, \%narFiles, \%localPaths, \%patches);
%localPaths = ();
%patches = (); # not supported yet
my $size = scalar (keys %narFiles);
print "$size store paths in manifest\n";
# Download every file that we don't already have, and update every URL
# to point to the mirror. Also fill in the size and hash fields in
# the manifest in order to be compatible with Nix < 0.13.
while (my ($storePath, $files) = each %narFiles) {
foreach my $file (@{$files}) {
my $srcURL = $file->{url};
my $dstName = basename $srcURL;
my $dstFile = "$dstChannelPath/$dstName";
my $dstURL = "$dstChannelURL/$dstName";
$file->{url} = $dstURL;
if (! -e $dstFile) {
print "downloading $srcURL\n";
my $dstFileTmp = "$dstChannelPath/.tmp.$$.nar.$dstName";
system("curl '$srcURL' > $dstFileTmp") == 0 or die;
rename($dstFileTmp, $dstFile) or die "cannot rename $dstFileTmp";
}
$file->{size} = stat($dstFile)->size or die;
my $hashFile = "$dstChannelPath/.hash.$dstName";
my $hash;
if (-e $hashFile) {
open HASH, "<$hashFile" or die;
$hash = <HASH>;
close HASH;
} else {
$hash = `nix-hash --flat --type sha256 --base32 '$dstFile'` or die;
chomp $hash;
open HASH, ">$hashFile" or die;
print HASH $hash;
close HASH;
}
$file->{hash} = "sha256:$hash";
}
}
# Write the new manifest.
writeManifest("$dstChannelPath/MANIFEST", \%narFiles, \%patches);