summaryrefslogtreecommitdiff
path: root/Master/tlpkg/dev/download-package-repository
blob: 2e10603e51fd1dda9df47892775aba37669210f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/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);
}

&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");
  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";
  }
  
  $::archivedir = "__ARCHIVE__";
  if (-d "$::localrepo/$Archive") {
    rename("$::localrepo/$Archive", "$::archivedir") ||
      die "unable to rename $::localrepo/$Archive: $!";
  }
  if (!-d "$::localrepo/$::archivedir") {
    mkdir("$::localrepo/$::archivedir") ||
      die "$0: could not create directory $::localrepo/$::archivedir: $!";
  }
  my $pkg_count = 0;
  for my $pkgname ($tlpdb->list_packages) {
    next if $pkgname =~ /^00texlive/;
    my $tlp = $tlpdb->get_package($pkgname);
    $pkg_count += get_container("$pkgname", $tlp->containermd5() );
    get_container("$pkgname.doc", $tlp->doccontainermd5() ) 
      if ($tlp->docfiles());
    get_container("$pkgname.source", $tlp->srccontainermd5() ) 
      if ($tlp->srcfiles());
    # last if ($pkg_count > 2); # stop for testing
  }
  rename("$::localrepo/$::archivedir", "$Archive") ||
    die "unable to rename $::localrepo/$::archivedir: $!";

  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");
      die "md5 sum mismatch for package $pkgname:
        database:  $md5there
        dowloaded: $md5here\n" if ($md5here ne $md5there);
      return 1;
    }
    # info("package container up to date: $pkgcontainerfile\n");
    print("OK: $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<url|path>

Remote package repository to be used as a source for the creation of 
the local package repository.  This can be either a local directory via 
C</path/to/directory> or a C<file:/> url, or a network location via 
a C<http://> or C<ftp://> url. (No other protocols are supported.)

The default is to pick a mirror automatically, using
L<http://mirror.ctan.org/systems/texlive/tlnet>; the chosen mirror is
used for the entire download.  See L<http://ctan.org> for more about CTAN
and its mirrors.

If the repository is on the network, trailing C</> characters and/or
trailing C</tlpkg> and C</archive> components are ignored.  For example,
you could choose a particular CTAN mirror with something like this:

  -repository http://ctan.example.org/its/ctan/dir/systems/texlive/tlnet

Of course a real hostname and its particular top-level CTAN path
have to be specified.  The list of CTAN mirrors is available at
L<http://ctan.org/mirrors>. For more information see install-tl -help.

=item B<-persistent-downloads>

=item B<-no-persistent-downloads>

Activating this option attempts to set up a persistent connection
using the Net::LWP Perl module.  This opens only one connection between 
your computer and the server per session and reuses it, instead of 
initiating a new download for each package.  

This option is turned on by default, and this program will fall 
back to using wget if this is not possible. If you want to disable 
usage of LWP and persistent connections, please use
B<-no-persistent-downloads>.

The standard options B<-help> and B<-q>, B<-v>, and
B<-logfile>=I<file> are accepted too; see the C<process_logging_options>
function in L<TeXLive::TLUtils> for details.

=head1 DESCRIPTION

Creates or updates a local package repository within the installer 
directory structure. Useful particularily on unstable internet 
connentions to predownload all packages before the installation.
The local repository will be picked up automatically by the installer 
as a default one. The repository is not enabled untill all pacakges 
has been downloaded and md5 sum checked. If downloading has been 
interrupted for any reason, just rerun this script again to complete it.

=head1 AUTHORS AND COPYRIGHT

This script and its documentation were written for the TeX Live
distribution (L<http://tug.org/texlive>) and both are licensed under the
GNU General Public License Version 2 or later.

=cut