use strict; use readmanifest; use File::Basename; use File::stat; use File::Temp qw/tempfile/; use Fcntl ':flock'; if (scalar @ARGV != 3 && scalar @ARGV != 4) { print STDERR "Syntax: perl mirror-channel.pl []\n"; exit 1; } my $curl = "curl --location --silent --show-error --fail"; my $srcChannelURL = $ARGV[0]; my $dstChannelURL = $ARGV[1]; my $dstChannelPath = $ARGV[2]; my $nixexprsURL = $ARGV[3] || "$srcChannelURL/nixexprs.tar.bz2"; die "$dstChannelPath doesn't exist\n" unless -d $dstChannelPath; open LOCK, ">$dstChannelPath/.lock" or die; flock LOCK, LOCK_EX; my ($fh, $tmpManifest) = tempfile(UNLINK => 1); 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"; # Protect against Hydra problems that leave the channel empty. die "cowardly refusing to mirror an empty channel" if $size == 0; # 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 $narHash = $file->{narHash}; my $srcURL = $file->{url}; my $dstName = $narHash; $dstName =~ s/:/_/; # `:' in filenames might cause problems 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 = ; 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); # Mirror nixexprs.tar.bz2. my $tmpFile = "$dstChannelPath/.tmp.$$.nixexprs.tar.bz2"; system("$curl '$nixexprsURL' > $tmpFile") == 0 or die; rename($tmpFile, "$dstChannelPath/nixexprs.tar.bz2") or die "cannot rename $tmpFile";