#!/usr/bin/env perl # # Originally written by T.M.Trzeciak in 2010 # # Purpose: create/update a local package repository # How to use: place it tlpkg/installer and run # our $Master; our $location; BEGIN { $^W = 1; $Master = __FILE__; $Master =~ s;\\;/;g if ($^O =~ /^MSWin/i); $Master =~ s;[^/]*$;../..; unless ($Master =~ s;(/[^/]*){3,3}$;;); unshift (@INC, "$Master/tlpkg"); $::installerdir = $Master; $::localrepo = $Master; # $::localrepo = '.'; # $Master = $ENV{"TLINSTALLERDIR"}; # print "$Master\n"; } use TeXLive::TLPDB; use TeXLive::TLPOBJ; use TeXLive::TLConfig; use TeXLive::TLUtils; use TeXLive::TLDownload; use Getopt::Long; use Pod::Usage; use File::Path; use Cwd; TeXLive::TLUtils::process_logging_options(); my $opt_location; my $opt_destination; my $opt_persistent_downloads = 1; my $opt_help = 0; GetOptions( "location|url|repository|repo=s" => \$opt_location, # "destination=s" => \$opt_destination, "persistent-downloads!" => \$opt_persistent_downloads, "h|help|?" => \$opt_help) or pod2usage(1); if ($opt_help) { my @noperldoc = ("-noperldoc", "1") if ($^O =~ /^MSWin/i); pod2usage(-exitstatus => 0, -verbose => 2, @noperldoc); } exit(&main()); sub main { if ( !setup_programs( "$::installerdir/$InfraLocation/installer", TeXLive::TLUtils::platform() ) ) { die "$0: failed to set up necessary programs.\n"; } if ($opt_persistent_downloads) { TeXLive::TLUtils::setup_persistent_downloads() ; } $location = defined($opt_location) ? $opt_location : TeXLive::TLUtils::give_ctan_mirror(); if (!defined($location)) { die("$0: failed to obtain repository location.\n"); } $::localrepo = $opt_destination if defined($opt_destination); if ( $location eq $::localrepo ) { die "destination and remote repository cannot be the same: $location"; } info("Cloning package repository from $location\n"); $::archivedir = "__ARCHIVE__"; if (-d "$::localrepo/$::archivedir") { rename("$::localrepo/$::archivedir", "$::localrepo/$Archive") || die "unable to rename $::localrepo/$::archivedir to $Archive: $!"; } if (!-d "$::localrepo/$Archive") { mkdir("$::localrepo/$Archive") || die "$0: could not create directory $::localrepo/$Archive: $!"; } if (!-d "$::localrepo/$InfraLocation" ) { mkdir("$::localrepo/$InfraLocation") || die "$0: cannot create directory $::localrepo/$InfraLocation: $!"; } my $tlpdbfile = "$InfraLocation/$DatabaseName"; my $tlpdbpacked = "$tlpdbfile.$DefaultContainerFormat"; my $md5there; download_file("$location/$tlpdbfile.md5", "$::localrepo/$tlpdbfile.md5"); open MD5FILE, "$::localrepo/$tlpdbfile.md5" or die "cannot open $::localrepo/$tlpdbfile.md5: $!"; if (read (MD5FILE, $md5there, 32) != 32) { die "cannot download remote TeX Live database from $location.\n"; } close MD5FILE; my $md5here = (!-r "$::localrepo/$tlpdbfile") ? "" : TeXLive::TLUtils::tlmd5("$::localrepo/$tlpdbfile"); # debug("md5 hash mismatch\n") if ($md5there ne $md5here); if ($md5there ne $md5here) { download_file("$location/$tlpdbpacked", "$::localrepo/$tlpdbpacked"); if ( system("$::progs{'xzdec'} <\"$::localrepo/$tlpdbpacked\" >\"$::localrepo/$tlpdbfile\"") ) { die "cannot decompress $::localrepo/$tlpdbpacked\n"; } } my $tlpdb = TeXLive::TLPDB->new ("root" => $::localrepo); if ( !defined($tlpdb) ) { die "unusable repository database at $location\n"; } if (-d "$::localrepo/$Archive") { rename("$::localrepo/$Archive", "$::localrepo/$::archivedir") || die "unable to rename $::localrepo/$Archive to $::archivedir: $!"; } my $error_count = 0; for my $pkgname ($tlpdb->list_packages) { next if $pkgname =~ /^00texlive/; my $tlp = $tlpdb->get_package($pkgname); $error_count += get_container("$pkgname", $tlp->containermd5() ); $error_count += get_container("$pkgname.doc", $tlp->doccontainermd5() ) if ($tlp->docfiles()); $error_count += get_container("$pkgname.source", $tlp->srccontainermd5() ) if ($tlp->srcfiles()); } if ($error_count == 0) { rename("$::localrepo/$::archivedir", "$::localrepo/$Archive") || die "unable to rename $::localrepo/$::archivedir to $Archive: $!"; print("Pacakge repository cloning finished successfully.\n"); return 0; } else { print("Pacakge repository cloning finished with errors.\n"); print("Rerunning again might fix the problems.\n"); return 1; } sub get_container { my ($pkgname, $md5there) = @_; my $pkgcontainerfile = "$pkgname.$DefaultContainerExtension"; my $localfile = "$::localrepo/$::archivedir/$pkgcontainerfile"; my $remotefile = "$location/$Archive/$pkgcontainerfile"; if (!-r "$localfile" || TeXLive::TLUtils::tlmd5("$localfile") ne $md5there ) { print("downloading $pkgname\n"); download_file("$remotefile", "$localfile"); # check downloaded file my $md5here = TeXLive::TLUtils::tlmd5("$localfile"); if ($md5here ne $md5there) { warn("md5 sum mismatch for package $pkgname: database: $md5there dowloaded: $md5here\n"); return 1; } return 0; } # info("package container up to date: $pkgcontainerfile\n"); print("skipping $pkgname\n"); return 0; } } __END__ =head1 NAME download-package-repository - creates a local package repository =head1 SYNOPSIS download-package-repository [OPTION]... =head1 OPTIONS =item B<-repository> I =item B<-persistent-downloads> =item B<-no-persistent-downloads> See the tlmgr documentation (L) for information. The standard options B<-help> and B<-q>, B<-v>, and B<-logfile>=I are accepted too; see the C function in L for details. =head1 DESCRIPTION This script is useful particularly on unstable Internet connections to pre-download all packages before doing an installation. In general,it creates or updates a local package repository (within the TL installer directories). The resulting local repository will be picked up automatically by the installer as a default one. The new repository is not enabled untill all packages have been downloaded and verified. If the download is interrupted for any reason, just rerun this script again to complete it. It will pick upwhere it left off. =head1 AUTHORS AND COPYRIGHT This script and its documentation were written for the TeX Live distribution (L) and both are licensed under the GNU General Public License Version 2 or later. =cut