line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyrights 1998,2005-2017 by [Mark Overmeer]. |
2
|
|
|
|
|
|
|
# For other contributors see ChangeLog. |
3
|
|
|
|
|
|
|
# See the manual pages for details on the licensing terms. |
4
|
|
|
|
|
|
|
# Pod stripped from pm file by OODoc 2.02. |
5
|
1
|
|
|
1
|
|
424
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
24
|
|
6
|
1
|
|
|
1
|
|
3
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
21
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package CPAN::Site::Index; |
9
|
1
|
|
|
1
|
|
7
|
use vars '$VERSION'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
62
|
|
10
|
|
|
|
|
|
|
$VERSION = '1.14'; |
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
3
|
use base 'Exporter'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
79
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our @EXPORT_OK = qw/cpan_index cpan_mirror/; |
15
|
|
|
|
|
|
|
our $VERSION; # required in test-env |
16
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
435
|
use Log::Report 'cpan-site', syntax => 'SHORT'; |
|
1
|
|
|
|
|
63722
|
|
|
1
|
|
|
|
|
6
|
|
18
|
|
|
|
|
|
|
|
19
|
1
|
|
|
1
|
|
566
|
use version; |
|
1
|
|
|
|
|
1215
|
|
|
1
|
|
|
|
|
4
|
|
20
|
1
|
|
|
1
|
|
50
|
use File::Find qw/find/; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
45
|
|
21
|
1
|
|
|
1
|
|
398
|
use File::Copy qw/copy/; |
|
1
|
|
|
|
|
1561
|
|
|
1
|
|
|
|
|
47
|
|
22
|
1
|
|
|
1
|
|
4
|
use File::Basename qw/basename dirname/; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
43
|
|
23
|
1
|
|
|
1
|
|
441
|
use HTTP::Date qw/time2str/; |
|
1
|
|
|
|
|
2525
|
|
|
1
|
|
|
|
|
52
|
|
24
|
1
|
|
|
1
|
|
389
|
use File::Spec::Functions qw/catfile catdir splitdir/; |
|
1
|
|
|
|
|
497
|
|
|
1
|
|
|
|
|
53
|
|
25
|
1
|
|
|
1
|
|
552
|
use LWP::UserAgent (); |
|
1
|
|
|
|
|
24992
|
|
|
1
|
|
|
|
|
18
|
|
26
|
1
|
|
|
1
|
|
596
|
use Archive::Tar (); |
|
1
|
|
|
|
|
57169
|
|
|
1
|
|
|
|
|
25
|
|
27
|
1
|
|
|
1
|
|
567
|
use Archive::Zip qw(:ERROR_CODES :CONSTANTS); |
|
1
|
|
|
|
|
36096
|
|
|
1
|
|
|
|
|
154
|
|
28
|
1
|
|
|
1
|
|
406
|
use CPAN::Checksums (); |
|
1
|
|
|
|
|
20241
|
|
|
1
|
|
|
|
|
27
|
|
29
|
1
|
|
|
1
|
|
9
|
use IO::Zlib (); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2587
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $tar_gz = qr/ \.tar\.gz$ | \.tar\.Z$ | \.tgz$/xi; |
32
|
|
|
|
|
|
|
my $zip = qr/ \.zip$ /xi; |
33
|
|
|
|
|
|
|
my $cpan_update = 0.04; # days between reload of full CPAN index |
34
|
|
|
|
|
|
|
my $ua; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub safe_copy($$); |
37
|
|
|
|
|
|
|
sub cpan_index($@); |
38
|
|
|
|
|
|
|
sub register($$$); |
39
|
|
|
|
|
|
|
sub package_inventory($$;$); |
40
|
|
|
|
|
|
|
sub package_on_usual_location($); |
41
|
|
|
|
|
|
|
sub inspect_archive; |
42
|
|
|
|
|
|
|
sub inspect_tar_archive($$); |
43
|
|
|
|
|
|
|
sub inspect_zip_archive($$); |
44
|
|
|
|
|
|
|
sub collect_package_details($$$); |
45
|
|
|
|
|
|
|
sub update_global_cpan($$); |
46
|
|
|
|
|
|
|
sub load_file($$); |
47
|
|
|
|
|
|
|
sub merge_global_cpan($$$); |
48
|
|
|
|
|
|
|
sub create_details($$$$$); |
49
|
|
|
|
|
|
|
sub calculate_checksums($); |
50
|
|
|
|
|
|
|
sub read_details($); |
51
|
|
|
|
|
|
|
sub remove_expired_details($$$); |
52
|
|
|
|
|
|
|
sub mkdirhier(@); |
53
|
|
|
|
|
|
|
sub cpan_mirror($$$@); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub safe_copy($$) |
56
|
0
|
|
|
0
|
0
|
0
|
{ my ($from, $to) = @_; |
57
|
0
|
|
|
|
|
0
|
trace "copy $from to $to"; |
58
|
0
|
0
|
|
|
|
0
|
copy $from, $to |
59
|
|
|
|
|
|
|
or fault __x"cannot copy {from} to {to}", from => $from, to => $to; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub cpan_index($@) |
63
|
0
|
|
|
0
|
0
|
0
|
{ my ($mycpan, $globalcpan, %opts) = @_; |
64
|
0
|
|
|
|
|
0
|
my $lazy = $opts{lazy}; |
65
|
0
|
|
|
|
|
0
|
my $fallback = $opts{fallback}; |
66
|
0
|
0
|
|
|
|
0
|
my $undefs = exists $opts{undefs} ? $opts{undefs} : 1; |
67
|
|
|
|
|
|
|
|
68
|
0
|
0
|
|
|
|
0
|
unless($ua) |
69
|
0
|
|
|
|
|
0
|
{ $ua = LWP::UserAgent->new; |
70
|
0
|
0
|
|
|
|
0
|
$ua->env_proxy if $opts{env_proxy}; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
0
|
0
|
|
|
|
0
|
-d $mycpan |
74
|
|
|
|
|
|
|
or error __x"archive top '{dir}' is not a directory" |
75
|
|
|
|
|
|
|
, dir => $mycpan; |
76
|
|
|
|
|
|
|
|
77
|
0
|
|
|
|
|
0
|
my $program = basename $0; |
78
|
0
|
|
0
|
|
|
0
|
$VERSION ||= 'undef'; # test env at home |
79
|
0
|
|
|
|
|
0
|
trace "$program version $VERSION"; |
80
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
0
|
my $global = catdir $mycpan, 'global'; |
82
|
0
|
|
|
|
|
0
|
my $mods = catdir $mycpan, 'modules'; |
83
|
0
|
|
|
|
|
0
|
my $authors = catdir $mycpan, 'authors'; |
84
|
0
|
|
|
|
|
0
|
mkdirhier $global, $mods, $authors; |
85
|
|
|
|
|
|
|
|
86
|
0
|
|
|
|
|
0
|
my $globdetails = update_global_cpan $mycpan, $globalcpan; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Create mailrc and modlist |
89
|
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
0
|
safe_copy catfile($global, '01mailrc.txt.gz') |
91
|
|
|
|
|
|
|
, catfile($authors, '01mailrc.txt.gz'); |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
0
|
safe_copy catfile($global, '03modlist.data.gz') |
94
|
|
|
|
|
|
|
, catfile($mods, '03modlist.data.gz'); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# Create packages details |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
0
|
my $details = catfile $mods, '02packages.details.txt.gz'; |
99
|
0
|
|
|
|
|
0
|
my $newlist = catfile $mods, '02packages.details.tmp.gz'; |
100
|
0
|
|
|
|
|
0
|
my $newer; |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
0
|
my $reuse_dists = {}; |
103
|
0
|
0
|
0
|
|
|
0
|
if($lazy && -f $details) |
104
|
0
|
|
|
|
|
0
|
{ $reuse_dists = read_details $details; |
105
|
0
|
|
|
|
|
0
|
$newer = -M $details; |
106
|
0
|
|
|
|
|
0
|
remove_expired_details $mycpan, $reuse_dists, $newer; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
0
|
my ($mypkgs, $distdirs) |
110
|
|
|
|
|
|
|
= package_inventory $mycpan, $reuse_dists, $newer; |
111
|
|
|
|
|
|
|
|
112
|
0
|
0
|
|
|
|
0
|
merge_global_cpan $mycpan, $mypkgs, $globdetails |
113
|
|
|
|
|
|
|
if $fallback; |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
0
|
create_details $details, $newlist, $mypkgs, $lazy, $undefs; |
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
0
|
if(-f $details) |
118
|
0
|
|
|
|
|
0
|
{ trace "backup old details file to $details.bak"; |
119
|
0
|
|
|
|
|
0
|
safe_copy $details, "$details.bak"; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
0
|
0
|
|
|
|
0
|
if(-f $newlist) |
123
|
0
|
|
|
|
|
0
|
{ trace "promoting $newlist to current"; |
124
|
0
|
0
|
|
|
|
0
|
rename $newlist, $details |
125
|
|
|
|
|
|
|
or error __x"cannot rename '{from}' in '{to}'" |
126
|
|
|
|
|
|
|
, from => $newlist, to => $details; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
0
|
calculate_checksums $distdirs; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# |
133
|
|
|
|
|
|
|
# Package Inventory |
134
|
|
|
|
|
|
|
# |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# global variables for testing purposes (sorry) |
137
|
|
|
|
|
|
|
our ($topdir, $findpkgs, %finddirs, $olddists, $index_age); |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub register($$$) |
140
|
28
|
|
|
28
|
0
|
33
|
{ my ($package, $this_version, $dist) = @_; |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# warn "register $package, " . (defined $this_version ? $this_version : 'undef'); |
143
|
|
|
|
|
|
|
|
144
|
28
|
50
|
|
|
|
37
|
if(ref $this_version) |
145
|
0
|
|
|
|
|
0
|
{ eval { $this_version = version->parse($this_version) }; |
|
0
|
|
|
|
|
0
|
|
146
|
0
|
0
|
|
|
|
0
|
if($@) |
147
|
0
|
|
|
|
|
0
|
{ alert __x"error when creating version object for {pkg}: {err}" |
148
|
|
|
|
|
|
|
, pkg => $package, err => $@; |
149
|
0
|
|
|
|
|
0
|
return; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
28
|
50
|
|
|
|
50
|
my $registered_version = exists $findpkgs->{$package} ? $findpkgs->{$package}[0] : undef; |
154
|
28
|
100
|
|
|
|
35
|
$this_version =~ s/^v// if $this_version; |
155
|
|
|
|
|
|
|
|
156
|
28
|
50
|
33
|
|
|
44
|
return if defined $registered_version |
157
|
|
|
|
|
|
|
&& $registered_version > $this_version; |
158
|
|
|
|
|
|
|
|
159
|
28
|
|
|
|
|
85
|
$findpkgs->{$package} = [ $this_version, $dist ]; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub package_inventory($$;$) |
163
|
0
|
|
|
0
|
0
|
0
|
{ (my $mycpan, $olddists, $index_age) = @_; #!!! see "my" |
164
|
0
|
|
|
|
|
0
|
$topdir = catdir $mycpan, 'authors', 'id'; |
165
|
0
|
|
|
|
|
0
|
mkdirhier $topdir; |
166
|
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
0
|
$findpkgs = {}; |
168
|
0
|
|
|
|
|
0
|
trace "creating inventory from $topdir"; |
169
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
0
|
find {wanted => \&inspect_archive, no_chdir => 1}, $topdir; |
171
|
0
|
|
|
|
|
0
|
($findpkgs, \%finddirs); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub package_on_usual_location($) |
175
|
22
|
|
|
22
|
0
|
244
|
{ my $file = shift; |
176
|
22
|
|
|
|
|
42
|
my ($top, $subdir, @rest) = splitdir $file; |
177
|
22
|
50
|
|
|
|
119
|
defined $subdir or return 0; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
!@rest # path is at top-level of distro |
180
|
22
|
100
|
|
|
|
105
|
|| $subdir eq 'lib'; # inside lib |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub inspect_archive |
184
|
3
|
|
|
3
|
0
|
9509
|
{ my $fn = $File::Find::name; |
185
|
3
|
50
|
33
|
|
|
125
|
return unless -f $fn |
|
|
|
33
|
|
|
|
|
186
|
|
|
|
|
|
|
&& ($fn =~ $tar_gz || $fn =~ $zip); |
187
|
|
|
|
|
|
|
|
188
|
3
|
|
|
|
|
27
|
(my $dist = $fn) =~ s!^\Q$topdir\E[\\/]!!; |
189
|
|
|
|
|
|
|
|
190
|
3
|
50
|
33
|
|
|
9
|
if(defined $index_age && -M $fn > $index_age) |
191
|
|
|
|
|
|
|
{ |
192
|
0
|
0
|
|
|
|
0
|
unless(exists $olddists->{$dist}) |
193
|
0
|
|
|
|
|
0
|
{ trace "not the latest: $dist"; |
194
|
0
|
|
|
|
|
0
|
return; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
0
|
trace "latest older than index: $dist"; |
198
|
0
|
|
|
|
|
0
|
foreach (@{$olddists->{$dist}}) |
|
0
|
|
|
|
|
0
|
|
199
|
0
|
|
|
|
|
0
|
{ my ($pkg, $version) = @$_; |
200
|
0
|
|
|
|
|
0
|
register $pkg, $version, $dist; |
201
|
|
|
|
|
|
|
} |
202
|
0
|
|
|
|
|
0
|
return; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
3
|
|
|
|
|
14
|
trace "inspecting archive $fn"; |
206
|
3
|
|
|
|
|
65
|
$finddirs{$File::Find::dir}++; |
207
|
|
|
|
|
|
|
|
208
|
3
|
50
|
|
|
|
26
|
return inspect_tar_archive $dist, $fn |
209
|
|
|
|
|
|
|
if $fn =~ $tar_gz; |
210
|
|
|
|
|
|
|
|
211
|
0
|
0
|
|
|
|
0
|
return inspect_zip_archive $dist, $fn |
212
|
|
|
|
|
|
|
if $fn =~ $zip; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub inspect_tar_archive($$) |
216
|
3
|
|
|
3
|
0
|
5
|
{ my ($dist, $fn) = @_; |
217
|
|
|
|
|
|
|
|
218
|
3
|
|
|
|
|
17
|
my $arch = Archive::Tar->new; |
219
|
3
|
50
|
|
|
|
30
|
$arch->read($fn, 1) |
220
|
|
|
|
|
|
|
or error __x"no files in tar archive '{fn}': {err}" |
221
|
|
|
|
|
|
|
, fn => $fn, err => $arch->error; |
222
|
|
|
|
|
|
|
|
223
|
3
|
|
|
|
|
32460
|
foreach my $file ($arch->get_files) |
224
|
60
|
|
|
|
|
386
|
{ my $fn = $file->full_path; |
225
|
60
|
100
|
100
|
|
|
763
|
$file->is_file && $fn =~ m/\.pm$/i && package_on_usual_location $fn |
|
|
|
100
|
|
|
|
|
226
|
|
|
|
|
|
|
or next; |
227
|
20
|
|
|
|
|
42
|
collect_package_details $fn, $dist, $file->get_content_by_ref; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub inspect_zip_archive($$) |
232
|
0
|
|
|
0
|
0
|
0
|
{ my ($dist, $fn) = @_; |
233
|
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
0
|
my $arch = Archive::Zip->new; |
235
|
0
|
0
|
|
|
|
0
|
$arch->read($fn)==AZ_OK |
236
|
|
|
|
|
|
|
or error __x"no files in zip archive '{fn}': {err}" |
237
|
|
|
|
|
|
|
, fn => $fn, err => $arch->error; |
238
|
|
|
|
|
|
|
|
239
|
0
|
|
|
|
|
0
|
foreach my $member ($arch->membersMatching( qr/\.pm$/i )) |
240
|
0
|
|
|
|
|
0
|
{ my $fn = $member->fileName; |
241
|
0
|
0
|
0
|
|
|
0
|
$member->isTextFile && package_on_usual_location $fn |
242
|
|
|
|
|
|
|
or next; |
243
|
0
|
|
|
|
|
0
|
my ($contents, $status) = $member->contents; |
244
|
0
|
0
|
|
|
|
0
|
$status==AZ_OK |
245
|
|
|
|
|
|
|
or error "error in zip file {fn}: {err}" |
246
|
|
|
|
|
|
|
, fn => $fn, err => $status; |
247
|
0
|
|
|
|
|
0
|
collect_package_details $fn, $dist, \$contents; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub collect_package_details($$$) |
252
|
20
|
|
|
20
|
0
|
59
|
{ my ($fn, $dist) = (shift, shift); |
253
|
20
|
|
|
|
|
14
|
my @lines = split /\r?\n/, ${shift()}; |
|
20
|
|
|
|
|
2090
|
|
254
|
20
|
|
|
|
|
22
|
my $in_pod = 0; |
255
|
20
|
|
|
|
|
16
|
my $package; |
256
|
20
|
|
|
|
|
17
|
local $VERSION = undef; # may get destroyed by eval |
257
|
|
|
|
|
|
|
|
258
|
20
|
|
|
|
|
33
|
while(@lines) |
259
|
4623
|
|
|
|
|
3461
|
{ local $_ = shift @lines; |
260
|
4623
|
50
|
|
|
|
5227
|
last if m/^__(?:END|DATA)__$/; |
261
|
|
|
|
|
|
|
|
262
|
4623
|
100
|
|
|
|
5187
|
$in_pod = ($1 ne 'cut') if m/^=(\w+)/; |
263
|
4623
|
100
|
100
|
|
|
10337
|
next if $in_pod || m/^\s*#/; |
264
|
|
|
|
|
|
|
|
265
|
3388
|
|
100
|
|
|
10180
|
$_ .= shift @lines |
|
|
|
100
|
|
|
|
|
266
|
|
|
|
|
|
|
while @lines && m/package|use|VERSION/ && !m/[;{]/; |
267
|
|
|
|
|
|
|
|
268
|
3388
|
100
|
|
|
|
4345
|
if( m/^\s* package \s* ((?:\w+\:\:)*\w+) (?:\s+ (\S*))? \s* [;{]/x ) |
269
|
28
|
|
|
|
|
52
|
{ my ($thispkg, $v) = ($1, $2); |
270
|
28
|
|
|
|
|
19
|
my $thisversion; |
271
|
28
|
50
|
|
|
|
35
|
if($v) |
272
|
0
|
|
|
|
|
0
|
{ $thisversion = eval {qv($v)}; |
|
0
|
|
|
|
|
0
|
|
273
|
0
|
0
|
|
|
|
0
|
alert __x"illegal version for {pkg}, found '{version}': {err}" |
274
|
|
|
|
|
|
|
, pkg => $thispkg, version => $v, err => $@ if $@; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# second package in file? |
278
|
28
|
100
|
|
|
|
40
|
register $package, $VERSION, $dist |
279
|
|
|
|
|
|
|
if defined $package; |
280
|
|
|
|
|
|
|
|
281
|
28
|
|
|
|
|
41
|
($package, $VERSION) = ($thispkg, $thisversion); |
282
|
28
|
|
|
|
|
81
|
trace "pkg $package from $fn"; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
3388
|
50
|
|
|
|
7047
|
if( m/^\s* \$ ${package}::VERSION \s* = \s* ["']?(\w+?)["']? \s* ;/x ) |
286
|
0
|
|
|
|
|
0
|
{ $VERSION = $1; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
3388
|
100
|
100
|
|
|
9211
|
if( !$VERSION && m/^ (?:use\s+version\s*;\s*)? |
290
|
|
|
|
|
|
|
(?:our)? \s* \$ ((?: \w+\:\:)*) VERSION \s* \= (.*)/x ) |
291
|
7
|
50
|
|
|
|
15
|
{ defined $2 or next; |
292
|
7
|
|
|
|
|
11
|
my ($ns, $vers) = ($1, $2); |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# some versions of CPAN.pm do contain lines like "$VERSION =~ ..." |
295
|
|
|
|
|
|
|
# which also need to be processed. |
296
|
7
|
|
|
|
|
360
|
eval "\$VERSION =$vers"; |
297
|
7
|
50
|
|
|
|
17
|
if(defined $VERSION) |
298
|
7
|
100
|
|
|
|
21
|
{ ($package = $ns) =~ s/\:\:$// |
299
|
|
|
|
|
|
|
if length $ns; |
300
|
7
|
|
|
|
|
19
|
trace "pkg $package version $VERSION"; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
20
|
50
|
|
|
|
29
|
$VERSION = $VERSION->numify if ref $VERSION; |
306
|
20
|
50
|
|
|
|
45
|
register $package, $VERSION, $dist |
307
|
|
|
|
|
|
|
if defined $package; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
sub update_global_cpan($$) |
311
|
0
|
|
|
0
|
0
|
|
{ my ($mycpan, $globalcpan) = @_; |
312
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
|
my $global = catdir $mycpan, 'global'; |
314
|
|
|
|
|
|
|
my ($mailrc, $globdetails, $modlist) = |
315
|
0
|
|
|
|
|
|
map { catfile $global, $_ } |
|
0
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
qw/01mailrc.txt.gz 02packages.details.txt.gz 03modlist.data.gz/; |
317
|
|
|
|
|
|
|
|
318
|
0
|
0
|
0
|
|
|
|
return $globdetails |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
319
|
|
|
|
|
|
|
if -f $globdetails && -f $globdetails && -f $modlist |
320
|
|
|
|
|
|
|
&& -M $globdetails < $cpan_update; |
321
|
|
|
|
|
|
|
|
322
|
0
|
|
|
|
|
|
info "(re)loading global CPAN files"; |
323
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
mkdirhier $global; |
325
|
0
|
|
|
|
|
|
load_file "$globalcpan/authors/01mailrc.txt.gz", $mailrc; |
326
|
0
|
|
|
|
|
|
load_file "$globalcpan/modules/02packages.details.txt.gz", $globdetails; |
327
|
0
|
|
|
|
|
|
load_file "$globalcpan/modules/03modlist.data.gz", $modlist; |
328
|
0
|
|
|
|
|
|
$globdetails; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
sub load_file($$) |
332
|
0
|
|
|
0
|
0
|
|
{ my ($from, $to) = @_; |
333
|
0
|
|
|
|
|
|
my $response = $ua->get($from, ':content_file' => $to); |
334
|
0
|
0
|
|
|
|
|
return if $response->is_success; |
335
|
|
|
|
|
|
|
|
336
|
0
|
|
|
|
|
|
unlink $to; |
337
|
0
|
|
|
|
|
|
error __x"failed to get {uri} for {to}: {err}" |
338
|
|
|
|
|
|
|
, uri => $from, to => $to, err => $response->status_line; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub merge_global_cpan($$$) |
342
|
0
|
|
|
0
|
0
|
|
{ my ($mycpan, $pkgs, $globdetails) = @_; |
343
|
|
|
|
|
|
|
|
344
|
0
|
|
|
|
|
|
trace "merge packages with CPAN core list in $globdetails"; |
345
|
0
|
|
|
|
|
|
my $cpan_pkgs = read_details $globdetails; |
346
|
|
|
|
|
|
|
|
347
|
0
|
|
|
|
|
|
while(my ($cpandist, $cpanpkgs) = each %$cpan_pkgs) |
348
|
0
|
|
|
|
|
|
{ foreach (@$cpanpkgs) |
349
|
0
|
|
|
|
|
|
{ my ($pkg, $version) = @$_; |
350
|
0
|
0
|
|
|
|
|
next if exists $pkgs->{$pkg}; |
351
|
0
|
|
|
|
|
|
$pkgs->{$pkg} = [$version, $cpandist]; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub create_details($$$$$) |
357
|
0
|
|
|
0
|
0
|
|
{ my ($details, $filename, $pkgs, $lazy, $undefs) = @_; |
358
|
|
|
|
|
|
|
|
359
|
0
|
|
|
|
|
|
trace "creating package details in $filename"; |
360
|
0
|
0
|
|
|
|
|
my $fh = IO::Zlib->new($filename, 'wb') |
361
|
|
|
|
|
|
|
or fault __x"generating gzipped {fn}", fn => $filename; |
362
|
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
|
my $lines = keys %$pkgs; |
364
|
0
|
|
|
|
|
|
my $date = time2str time; |
365
|
0
|
0
|
|
|
|
|
my $how = $lazy ? "lazy" : "full"; |
366
|
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
|
info "produced list of $lines packages $how"; |
368
|
|
|
|
|
|
|
|
369
|
0
|
|
|
|
|
|
my $program = basename $0; |
370
|
0
|
|
|
|
|
|
my $module = __PACKAGE__; |
371
|
0
|
|
|
|
|
|
$fh->print (<<__HEADER); |
372
|
|
|
|
|
|
|
File: 02packages.details.txt |
373
|
|
|
|
|
|
|
URL: file://$details |
374
|
|
|
|
|
|
|
Description: Packages listed in CPAN and local repository |
375
|
|
|
|
|
|
|
Columns: package name, version, path |
376
|
|
|
|
|
|
|
Intended-For: private CPAN |
377
|
|
|
|
|
|
|
Line-Count: $lines |
378
|
|
|
|
|
|
|
Written-By: $program with $module $CPAN::Site::Index::VERSION ($how) |
379
|
|
|
|
|
|
|
Last-Updated: $date |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
__HEADER |
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
|
foreach my $pkg (sort keys %$pkgs) |
384
|
0
|
|
|
|
|
|
{ my ($version, $path) = @{$pkgs->{$pkg}}; |
|
0
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
|
386
|
0
|
0
|
0
|
|
|
|
$version = 'undef' |
387
|
|
|
|
|
|
|
if !defined $version || $version eq ''; |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
next |
390
|
0
|
0
|
0
|
|
|
|
if $version eq 'undef' && !$undefs; |
391
|
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
|
$path =~ s,\\,/,g; |
393
|
0
|
|
|
|
|
|
$fh->printf("%-30s\t%s\t%s\n", $pkg, $version, $path); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub calculate_checksums($) |
398
|
0
|
|
|
0
|
0
|
|
{ my $dirs = shift; |
399
|
0
|
|
|
|
|
|
trace "updating checksums"; |
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
|
foreach my $dir (keys %$dirs) |
402
|
0
|
|
|
|
|
|
{ trace "summing $dir"; |
403
|
0
|
0
|
|
|
|
|
CPAN::Checksums::updatedir($dir) |
404
|
|
|
|
|
|
|
or warning 'failed calculating checksums in {dir}', dir => $dir; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub read_details($) |
409
|
0
|
|
|
0
|
0
|
|
{ my $fn = shift; |
410
|
0
|
0
|
|
|
|
|
-f $fn or return {}; |
411
|
0
|
|
|
|
|
|
trace "collecting all details from $fn"; |
412
|
|
|
|
|
|
|
|
413
|
0
|
0
|
|
|
|
|
my $fh = IO::Zlib->new($fn, 'rb') |
414
|
|
|
|
|
|
|
or fault __x"cannot read from {fn}", fn => $fn; |
415
|
|
|
|
|
|
|
|
416
|
0
|
|
|
|
|
|
my $line; # skip header, search first blank |
417
|
0
|
|
|
|
|
|
do { $line = $fh->getline } until $line =~ m/^\s*$/; |
|
0
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
|
419
|
0
|
|
|
|
|
|
my $time_last_update = (stat $fn)[9]; |
420
|
0
|
|
|
|
|
|
my %dists; |
421
|
|
|
|
|
|
|
|
422
|
0
|
|
|
|
|
|
while(my $line = $fh->getline) |
423
|
0
|
|
|
|
|
|
{ chomp $line; |
424
|
0
|
|
|
|
|
|
my ($pkg, $version, $dist) = split ' ', $line, 3; |
425
|
|
|
|
|
|
|
|
426
|
0
|
0
|
|
|
|
|
unless($dist) |
427
|
0
|
|
|
|
|
|
{ warning "$fn error line=\n $line"; |
428
|
0
|
|
|
|
|
|
next; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
0
|
|
|
|
|
|
push @{$dists{$dist}}, [$pkg, $version]; |
|
0
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
\%dists; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub remove_expired_details($$$) |
438
|
0
|
|
|
0
|
0
|
|
{ my ($mycpan, $dists, $newer) = @_; |
439
|
0
|
|
|
|
|
|
trace "extracting only existing local distributions"; |
440
|
|
|
|
|
|
|
|
441
|
0
|
|
|
|
|
|
my $authors = catdir $mycpan, 'authors', 'id'; |
442
|
0
|
|
|
|
|
|
foreach my $dist (keys %$dists) |
443
|
0
|
|
|
|
|
|
{ my $fn = catfile $authors, $dist; |
444
|
0
|
0
|
|
|
|
|
if(! -f $fn) |
|
|
0
|
|
|
|
|
|
445
|
|
|
|
|
|
|
{ # removed local or a global dist |
446
|
0
|
|
|
|
|
|
delete $dists->{$dist}; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
elsif(-M $fn < $newer) |
449
|
0
|
|
|
|
|
|
{ trace "dist $dist file updated, reindexing"; |
450
|
0
|
|
|
|
|
|
delete $dists->{$dist}; |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
sub mkdirhier(@) |
456
|
0
|
|
|
0
|
0
|
|
{ foreach my $dir (@_) |
457
|
0
|
0
|
|
|
|
|
{ next if -d $dir; |
458
|
0
|
|
|
|
|
|
mkdirhier dirname $dir; |
459
|
|
|
|
|
|
|
|
460
|
0
|
0
|
|
|
|
|
mkdir $dir, 0755 |
461
|
|
|
|
|
|
|
or fault __x"cannot create directory {dir}", dir => $dir; |
462
|
|
|
|
|
|
|
|
463
|
0
|
|
|
|
|
|
trace "created $dir"; |
464
|
|
|
|
|
|
|
} |
465
|
0
|
|
|
|
|
|
1; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub cpan_mirror($$$@) |
469
|
0
|
|
|
0
|
0
|
|
{ my ($mycpan, $globalcpan, $mods, %opts) = @_; |
470
|
0
|
0
|
|
|
|
|
@$mods or return; |
471
|
0
|
|
|
|
|
|
my %need = map { ($_ => 1) } @$mods; |
|
0
|
|
|
|
|
|
|
472
|
0
|
|
|
|
|
|
my $auth = catdir $mycpan, 'authors', 'id'; |
473
|
|
|
|
|
|
|
|
474
|
0
|
0
|
|
|
|
|
unless($ua) |
475
|
0
|
|
|
|
|
|
{ $ua = LWP::UserAgent->new; |
476
|
0
|
0
|
|
|
|
|
$ua->env_proxy if $opts{env_proxy}; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
0
|
|
|
|
|
|
my $globdetails |
480
|
|
|
|
|
|
|
= update_global_cpan $mycpan, $globalcpan; |
481
|
|
|
|
|
|
|
|
482
|
0
|
0
|
|
|
|
|
my $fh = IO::Zlib->new($globdetails, 'rb') |
483
|
|
|
|
|
|
|
or fault __x"cannot read from {fn}", fn => $globdetails; |
484
|
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
|
while(my $line = $fh->getline) # skip header, search first blank |
486
|
0
|
0
|
|
|
|
|
{ last if $line =~ m/^\s*$/; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
0
|
|
0
|
|
|
|
$ua ||= LWP::UserAgent->new; |
490
|
0
|
|
|
|
|
|
while(my $line = $fh->getline) |
491
|
0
|
|
|
|
|
|
{ my ($pkg, $version, $dist) = split ' ', $line; |
492
|
0
|
0
|
|
|
|
|
delete $need{$pkg} or next; |
493
|
|
|
|
|
|
|
|
494
|
0
|
|
|
|
|
|
my $to = catfile $auth, split m#/#, $dist; |
495
|
0
|
0
|
|
|
|
|
if(-f $to) |
496
|
0
|
|
|
|
|
|
{ trace __x"package {pkg} present in distribution {dist}" |
497
|
|
|
|
|
|
|
, pkg => $pkg, dist => $dist; |
498
|
0
|
|
|
|
|
|
next; |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
|
501
|
0
|
|
|
|
|
|
my $source = "$globalcpan/authors/id/$dist"; |
502
|
0
|
|
|
|
|
|
mkdirhier dirname $to; |
503
|
0
|
|
|
|
|
|
my $response = $ua->get($source, ':content_file' => $to); |
504
|
0
|
0
|
|
|
|
|
unless($response->is_success) |
505
|
0
|
|
|
|
|
|
{ unlink $to; |
506
|
0
|
|
|
|
|
|
error __x"failed to get {uri} for {to}: {err}" |
507
|
|
|
|
|
|
|
, uri => $source, to => $to, err => $response->status_line; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
0
|
|
|
|
|
|
info __x"got {pkg} in {dist}", pkg => $pkg, dist => $dist; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
warning __x"package {pkg} does not exist", pkg => $_ |
514
|
0
|
|
|
|
|
|
for sort keys %need; |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
1; |