| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package App::EPAN; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
72102
|
use 5.012; |
|
|
1
|
|
|
|
|
3
|
|
|
4
|
|
|
|
|
|
|
{ our $VERSION = '0.002' } |
|
5
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
33
|
|
|
6
|
1
|
|
|
1
|
|
714
|
use English qw( -no_match_vars ); |
|
|
1
|
|
|
|
|
3977
|
|
|
|
1
|
|
|
|
|
6
|
|
|
7
|
1
|
|
|
1
|
|
835
|
use version; |
|
|
1
|
|
|
|
|
2036
|
|
|
|
1
|
|
|
|
|
5
|
|
|
8
|
1
|
|
|
1
|
|
656
|
use autodie; |
|
|
1
|
|
|
|
|
16795
|
|
|
|
1
|
|
|
|
|
6
|
|
|
9
|
1
|
|
|
1
|
|
7911
|
use Getopt::Long qw< :config gnu_getopt >; |
|
|
1
|
|
|
|
|
13343
|
|
|
|
1
|
|
|
|
|
7
|
|
|
10
|
1
|
|
|
1
|
|
795
|
use Pod::Usage qw< pod2usage >; |
|
|
1
|
|
|
|
|
50774
|
|
|
|
1
|
|
|
|
|
108
|
|
|
11
|
1
|
|
|
1
|
|
701
|
use Dist::Metadata (); |
|
|
1
|
|
|
|
|
32415
|
|
|
|
1
|
|
|
|
|
33
|
|
|
12
|
1
|
|
|
1
|
|
541
|
use Path::Class qw< file dir >; |
|
|
1
|
|
|
|
|
36725
|
|
|
|
1
|
|
|
|
|
83
|
|
|
13
|
1
|
|
|
1
|
|
18
|
use Cwd qw< cwd >; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
40
|
|
|
14
|
1
|
|
|
1
|
|
574
|
use File::Find::Rule (); |
|
|
1
|
|
|
|
|
8616
|
|
|
|
1
|
|
|
|
|
24
|
|
|
15
|
1
|
|
|
1
|
|
658
|
use Compress::Zlib (); |
|
|
1
|
|
|
|
|
55457
|
|
|
|
1
|
|
|
|
|
36
|
|
|
16
|
1
|
|
|
1
|
|
585
|
use Log::Log4perl::Tiny qw< :easy :dead_if_first >; |
|
|
1
|
|
|
|
|
15083
|
|
|
|
1
|
|
|
|
|
4
|
|
|
17
|
1
|
|
|
1
|
|
933
|
use Moo; |
|
|
1
|
|
|
|
|
11814
|
|
|
|
1
|
|
|
|
|
5
|
|
|
18
|
1
|
|
|
1
|
|
2783
|
use IPC::Run (); |
|
|
1
|
|
|
|
|
25874
|
|
|
|
1
|
|
|
|
|
25
|
|
|
19
|
1
|
|
|
1
|
|
529
|
use File::Copy (); |
|
|
1
|
|
|
|
|
2416
|
|
|
|
1
|
|
|
|
|
30
|
|
|
20
|
1
|
|
|
1
|
|
486
|
use File::Which qw< which >; |
|
|
1
|
|
|
|
|
1020
|
|
|
|
1
|
|
|
|
|
749
|
|
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
has configuration => ( |
|
23
|
|
|
|
|
|
|
is => 'rw', |
|
24
|
|
|
|
|
|
|
lazy => 1, |
|
25
|
|
|
|
|
|
|
predicate => 'has_config', |
|
26
|
|
|
|
|
|
|
clearer => 'clear_config', |
|
27
|
|
|
|
|
|
|
default => sub { {} }, |
|
28
|
|
|
|
|
|
|
); |
|
29
|
|
|
|
|
|
|
has action => (is => 'rw',); |
|
30
|
|
|
|
|
|
|
has last_index => (is => 'rw',); |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub run { |
|
33
|
0
|
|
|
0
|
1
|
|
my $package = shift; |
|
34
|
0
|
|
|
|
|
|
my $self = $package->new(); |
|
35
|
0
|
|
|
|
|
|
$self->get_options(@_); |
|
36
|
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
my $action = $self->action(); |
|
38
|
0
|
0
|
|
|
|
|
pod2usage(-verbose => 99, -sections => 'USAGE') unless defined $action; |
|
39
|
0
|
0
|
|
|
|
|
if (my $method = $self->can("action_$action")) { |
|
40
|
0
|
|
|
|
|
|
$self->$method(); |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
else { |
|
43
|
0
|
|
|
|
|
|
FATAL "action '$action' is not supported\n"; |
|
44
|
0
|
|
|
|
|
|
$self->action_list_actions; |
|
45
|
0
|
|
|
|
|
|
exit 1; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
0
|
|
|
|
|
|
return; |
|
48
|
|
|
|
|
|
|
} ## end sub run |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub get_options { |
|
51
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
52
|
0
|
0
|
0
|
|
|
|
my $action = |
|
53
|
|
|
|
|
|
|
(scalar(@_) && length($_[0]) && (substr($_[0], 0, 1) ne '-')) |
|
54
|
|
|
|
|
|
|
? shift(@_) |
|
55
|
|
|
|
|
|
|
: 'list-actions'; |
|
56
|
0
|
|
|
|
|
|
$action =~ s{-}{_}gmxs; |
|
57
|
0
|
|
|
|
|
|
local @ARGV = @_; |
|
58
|
0
|
|
|
|
|
|
$self->action($action); |
|
59
|
0
|
|
|
|
|
|
my %config = (); |
|
60
|
0
|
0
|
|
|
|
|
GetOptions( |
|
61
|
|
|
|
|
|
|
\%config, |
|
62
|
|
|
|
|
|
|
qw( |
|
63
|
|
|
|
|
|
|
mailrc|m|1=s |
|
64
|
|
|
|
|
|
|
output|packages-details|o|2=s |
|
65
|
|
|
|
|
|
|
modlist|modlist-data|l|3=s |
|
66
|
|
|
|
|
|
|
target|t=s |
|
67
|
|
|
|
|
|
|
test|T! |
|
68
|
|
|
|
|
|
|
author|a=s |
|
69
|
|
|
|
|
|
|
usage! help! man! version! |
|
70
|
|
|
|
|
|
|
) |
|
71
|
|
|
|
|
|
|
) or pod2usage(-verbose => 99, -sections => 'USAGE'); |
|
72
|
0
|
|
0
|
|
|
|
our $VERSION ||= 'whateva'; |
|
73
|
|
|
|
|
|
|
pod2usage(message => "$0 $VERSION", -verbose => 99, -sections => ' ') |
|
74
|
0
|
0
|
|
|
|
|
if $config{version}; |
|
75
|
0
|
0
|
|
|
|
|
pod2usage(-verbose => 99, -sections => 'USAGE') if $config{usage}; |
|
76
|
|
|
|
|
|
|
pod2usage(-verbose => 99, -sections => 'USAGE|EXAMPLES|OPTIONS') |
|
77
|
0
|
0
|
|
|
|
|
if $config{help}; |
|
78
|
0
|
0
|
|
|
|
|
pod2usage(-verbose => 2) if $config{man}; |
|
79
|
0
|
|
|
|
|
|
$self->configuration( |
|
80
|
|
|
|
|
|
|
{ |
|
81
|
|
|
|
|
|
|
cmdline_config => \%config, |
|
82
|
|
|
|
|
|
|
config => \%config, |
|
83
|
|
|
|
|
|
|
args => [@ARGV], |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
); |
|
86
|
0
|
|
|
|
|
|
return; |
|
87
|
|
|
|
|
|
|
} ## end sub get_options |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub args { |
|
90
|
0
|
|
|
0
|
1
|
|
return @{$_[0]->configuration()->{args}}; |
|
|
0
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub config { |
|
94
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
95
|
0
|
0
|
|
|
|
|
return @{$self->configuration()->{config}}{@_} if wantarray(); |
|
|
0
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
|
return $self->configuration()->{config}{shift @_}; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub target_dir { |
|
100
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
101
|
0
|
|
0
|
|
|
|
return dir($self->config('target') // 'epan'); |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub execute_tests { |
|
105
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
106
|
0
|
|
|
|
|
|
return $self->config('test'); |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
0
|
|
|
0
|
1
|
|
sub action_index { return shift->_do_index } |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
{ |
|
112
|
1
|
|
|
1
|
|
17
|
no strict 'refs'; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2150
|
|
|
113
|
|
|
|
|
|
|
*{action_idx} = \&action_index; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub _save { |
|
117
|
0
|
|
|
0
|
|
|
my ($self, $name, $contents, $config_key, $output) = @_; |
|
118
|
|
|
|
|
|
|
|
|
119
|
0
|
0
|
|
|
|
|
if (defined(my $confout = $self->config($config_key))) { |
|
120
|
0
|
0
|
|
|
|
|
$output = |
|
|
|
0
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
!length($confout) ? undef |
|
122
|
|
|
|
|
|
|
: $confout eq '-' ? \*STDOUT |
|
123
|
|
|
|
|
|
|
: file($confout); |
|
124
|
|
|
|
|
|
|
} ## end if (defined(my $confout...)) |
|
125
|
0
|
0
|
|
|
|
|
if (defined $output) { |
|
126
|
0
|
|
|
|
|
|
INFO "saving output to $output"; |
|
127
|
0
|
0
|
|
|
|
|
$self->_save2($output, |
|
128
|
|
|
|
|
|
|
scalar(ref($contents) ? $contents->() : $contents)); |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
else { |
|
131
|
0
|
|
|
|
|
|
INFO "empty filename for $name file, skipping"; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
} ## end sub _save |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub _do_index { |
|
136
|
0
|
|
|
0
|
|
|
my ($self, $basedir) = @_; |
|
137
|
0
|
|
0
|
|
|
|
$basedir //= $self->target_dir; |
|
138
|
0
|
0
|
|
|
|
|
LOGDIE "path '$basedir' does not exist (wrong -t option?)" |
|
139
|
|
|
|
|
|
|
unless -d $basedir; |
|
140
|
|
|
|
|
|
|
|
|
141
|
0
|
|
|
|
|
|
$self->_save( |
|
142
|
|
|
|
|
|
|
'01mailrc', # name |
|
143
|
|
|
|
|
|
|
'', # contents |
|
144
|
|
|
|
|
|
|
'mailrc', # configuration key to look output file |
|
145
|
|
|
|
|
|
|
$basedir->file(qw< authors 01mailrc.txt.gz >) # default |
|
146
|
|
|
|
|
|
|
); |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
$self->_save( |
|
149
|
|
|
|
|
|
|
'02packages.details', # name |
|
150
|
|
|
|
|
|
|
sub { # where to get data from. Call is avoided if |
|
151
|
|
|
|
|
|
|
# no file on output |
|
152
|
0
|
|
|
0
|
|
|
INFO "getting contributions for regenerated index..."; |
|
153
|
0
|
|
|
|
|
|
$self->_index_for($basedir); |
|
154
|
|
|
|
|
|
|
}, |
|
155
|
0
|
|
|
|
|
|
'output', # configuration key to look output file |
|
156
|
|
|
|
|
|
|
$basedir->file(qw< modules 02packages.details.txt.gz >) # default |
|
157
|
|
|
|
|
|
|
); |
|
158
|
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
$self->_save( |
|
160
|
|
|
|
|
|
|
'03modlist.data', # name |
|
161
|
|
|
|
|
|
|
<<'END_OF_03_MODLIST_DATA', |
|
162
|
|
|
|
|
|
|
File: 03modlist.data |
|
163
|
|
|
|
|
|
|
Description: These are the data that are published in the module |
|
164
|
|
|
|
|
|
|
list, but they may be more recent than the latest posted |
|
165
|
|
|
|
|
|
|
modulelist. Over time we'll make sure that these data |
|
166
|
|
|
|
|
|
|
can be used to print the whole part two of the |
|
167
|
|
|
|
|
|
|
modulelist. Currently this is not the case. |
|
168
|
|
|
|
|
|
|
Modcount: 0 |
|
169
|
|
|
|
|
|
|
Written-By: PAUSE version 1.005 |
|
170
|
|
|
|
|
|
|
Date: Sun, 28 Jul 2013 07:41:15 GMT |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
package CPAN::Modulelist; |
|
173
|
|
|
|
|
|
|
# Usage: print Data::Dumper->new([CPAN::Modulelist->data])->Dump or similar |
|
174
|
|
|
|
|
|
|
# cannot 'use strict', because we normally run under Safe |
|
175
|
|
|
|
|
|
|
# use strict; |
|
176
|
|
|
|
|
|
|
sub data { |
|
177
|
|
|
|
|
|
|
my $result = {}; |
|
178
|
|
|
|
|
|
|
my $primary = "modid"; |
|
179
|
|
|
|
|
|
|
for (@$CPAN::Modulelist::data){ |
|
180
|
|
|
|
|
|
|
my %hash; |
|
181
|
|
|
|
|
|
|
@hash{@$CPAN::Modulelist::cols} = @$_; |
|
182
|
|
|
|
|
|
|
$result->{$hash{$primary}} = \%hash; |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
return $result; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
$CPAN::Modulelist::cols = [ ]; |
|
187
|
|
|
|
|
|
|
$CPAN::Modulelist::data = [ ]; |
|
188
|
|
|
|
|
|
|
END_OF_03_MODLIST_DATA |
|
189
|
|
|
|
|
|
|
'modlist', # configuration key to look output file |
|
190
|
|
|
|
|
|
|
$basedir->file(qw< modules 03modlist.data.gz >) # default |
|
191
|
|
|
|
|
|
|
); |
|
192
|
|
|
|
|
|
|
} ## end sub _do_index |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub _save2 { |
|
195
|
0
|
|
|
0
|
|
|
my ($self, $path, $contents) = @_; |
|
196
|
0
|
|
|
|
|
|
my ($fh, $is_gz); |
|
197
|
0
|
0
|
|
|
|
|
if (ref($path) eq 'GLOB') { |
|
198
|
0
|
|
|
|
|
|
$fh = $path; |
|
199
|
0
|
|
|
|
|
|
$is_gz = 0; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
else { |
|
202
|
0
|
0
|
|
|
|
|
$path->dir()->mkpath() unless -d $path->dir()->stringify(); |
|
203
|
0
|
|
|
|
|
|
$fh = $path->open('>'); |
|
204
|
0
|
|
|
|
|
|
$is_gz = $path->stringify() =~ m{\.gz$}mxs; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
0
|
0
|
|
|
|
|
if ($is_gz) { |
|
208
|
0
|
|
|
|
|
|
my $gz = Compress::Zlib::gzopen($fh, 'wb'); |
|
209
|
0
|
|
|
|
|
|
$gz->gzwrite($contents); |
|
210
|
0
|
|
|
|
|
|
$gz->gzclose(); |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
else { |
|
213
|
0
|
|
|
|
|
|
binmode $fh; |
|
214
|
0
|
|
|
|
|
|
print {$fh} $contents; |
|
|
0
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
} |
|
216
|
0
|
|
|
|
|
|
return; |
|
217
|
|
|
|
|
|
|
} ## end sub _save2 |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub _index_for { |
|
220
|
0
|
|
|
0
|
|
|
my ($self, $path) = @_; |
|
221
|
0
|
|
0
|
|
|
|
$path //= $self->target_dir; |
|
222
|
0
|
|
|
|
|
|
my @index = $self->_index_body_for($path); |
|
223
|
0
|
|
0
|
|
|
|
our $VERSION ||= 'whateva'; |
|
224
|
0
|
|
|
|
|
|
my $header = <<"END_OF_HEADER"; |
|
225
|
|
|
|
|
|
|
File: 02packages.details.txt |
|
226
|
|
|
|
|
|
|
URL: http://cpan.perl.org/modules/02packages.details.txt.gz |
|
227
|
|
|
|
|
|
|
Description: Package names found in directory \$CPAN/authors/id/ |
|
228
|
|
|
|
|
|
|
Columns: package name, version, path |
|
229
|
|
|
|
|
|
|
Intended-For: Automated fetch routines, namespace documentation. |
|
230
|
|
|
|
|
|
|
Written-By: epan $VERSION |
|
231
|
0
|
|
|
|
|
|
Line-Count: ${ \ scalar @index } |
|
232
|
0
|
|
|
|
|
|
Last-Updated: ${ \ scalar localtime() } |
|
233
|
|
|
|
|
|
|
END_OF_HEADER |
|
234
|
0
|
|
|
|
|
|
return join "\n", $header, @index, ''; |
|
235
|
|
|
|
|
|
|
} ## end sub _index_for |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
sub _collect_index_for { |
|
238
|
0
|
|
|
0
|
|
|
my ($self, $path) = @_; |
|
239
|
0
|
|
0
|
|
|
|
$path //= $self->target_dir; |
|
240
|
0
|
|
|
|
|
|
$path = dir($path); |
|
241
|
0
|
0
|
|
|
|
|
LOGDIE "path '$path' does not exist (wrong -t option?)" unless -d $path; |
|
242
|
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
my $idpath = $path->subdir(qw< authors id >); |
|
244
|
0
|
|
|
|
|
|
my %data_for; |
|
245
|
0
|
|
|
|
|
|
for my $file (File::Find::Rule->extras({follow => 1})->file() |
|
246
|
|
|
|
|
|
|
->in($idpath->stringify())) |
|
247
|
|
|
|
|
|
|
{ |
|
248
|
0
|
|
|
|
|
|
INFO "indexing $file"; |
|
249
|
0
|
|
|
|
|
|
my $index_path = |
|
250
|
|
|
|
|
|
|
file($file)->relative($idpath)->as_foreign('Unix')->stringify(); |
|
251
|
0
|
|
|
|
|
|
my $dm = Dist::Metadata->new(file => $file); |
|
252
|
0
|
|
|
|
|
|
my $version_for = $dm->package_versions(); |
|
253
|
|
|
|
|
|
|
|
|
254
|
0
|
|
|
|
|
|
$data_for{distro}{$index_path} = $version_for; |
|
255
|
0
|
|
|
|
|
|
(my $bare_index_path = $index_path) =~ |
|
256
|
|
|
|
|
|
|
s{^(.)/(\1.)/(\2.*?)/}{$3/}mxs; |
|
257
|
0
|
|
|
|
|
|
$data_for{bare_distro}{$bare_index_path} = $version_for; |
|
258
|
|
|
|
|
|
|
|
|
259
|
0
|
|
|
|
|
|
my %_localdata_for; |
|
260
|
0
|
|
|
|
|
|
my $score = 0; |
|
261
|
0
|
|
|
|
|
|
my $previous; |
|
262
|
0
|
|
|
|
|
|
while (my ($module, $version) = each %$version_for) { |
|
263
|
0
|
|
0
|
|
|
|
my $print_version = $version // 'undef'; |
|
264
|
0
|
|
|
|
|
|
DEBUG "data for $module: [$print_version] [$index_path]"; |
|
265
|
0
|
|
|
|
|
|
$_localdata_for{$module} = { |
|
266
|
|
|
|
|
|
|
version => $version, |
|
267
|
|
|
|
|
|
|
distro => $index_path, |
|
268
|
|
|
|
|
|
|
_file => $file, |
|
269
|
|
|
|
|
|
|
}; |
|
270
|
0
|
0
|
|
|
|
|
next if $score != 0; |
|
271
|
0
|
0
|
|
|
|
|
next unless exists($data_for{module}{$module}); |
|
272
|
0
|
|
|
|
|
|
$previous = $data_for{module}{$module}; |
|
273
|
0
|
|
|
|
|
|
DEBUG 'some previous version exists'; |
|
274
|
0
|
0
|
|
|
|
|
if (! defined $version) { |
|
|
|
0
|
|
|
|
|
|
|
275
|
0
|
0
|
|
|
|
|
$score = -1 if defined($previous->{version}); |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
elsif (defined $previous->{version}) { |
|
278
|
0
|
|
|
|
|
|
my $tv = version->parse($version); |
|
279
|
0
|
|
|
|
|
|
my $pv = version->parse($previous->{version}); |
|
280
|
0
|
|
|
|
|
|
$score = $tv <=> $pv; |
|
281
|
|
|
|
|
|
|
} |
|
282
|
0
|
|
|
|
|
|
DEBUG "score: $score"; |
|
283
|
|
|
|
|
|
|
} ## end while (my ($module, $version...)) |
|
284
|
|
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
|
DEBUG "FINAL SCORE $score"; |
|
286
|
|
|
|
|
|
|
|
|
287
|
0
|
0
|
|
|
|
|
if ($score < 0) { # didn't win against something already in |
|
288
|
0
|
|
|
|
|
|
DEBUG "marking $file as obsolete"; |
|
289
|
0
|
|
|
|
|
|
$data_for{obsolete}{$file} = 1; |
|
290
|
0
|
|
|
|
|
|
next; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
0
|
|
|
|
|
|
DEBUG "getting $file data as winner (for the moment)"; |
|
294
|
0
|
0
|
|
|
|
|
if ($previous) { |
|
295
|
0
|
|
|
|
|
|
my $oip = $previous->{distro}; |
|
296
|
0
|
|
|
|
|
|
DEBUG "marking $oip as obsolete"; |
|
297
|
0
|
|
|
|
|
|
$data_for{obsolete}{$previous->{_file}} = 1; |
|
298
|
|
|
|
|
|
|
delete $data_for{module}{$_} |
|
299
|
0
|
|
|
|
|
|
for keys %{$data_for{distro}{$oip}}; |
|
|
0
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
# copy stuff over to the "official" data for modules |
|
302
|
0
|
|
|
|
|
|
$data_for{module}{$_} = $_localdata_for{$_} for keys %_localdata_for; |
|
303
|
|
|
|
|
|
|
} ## end for my $file (File::Find::Rule...) |
|
304
|
0
|
|
|
|
|
|
$self->last_index(\%data_for); |
|
305
|
0
|
0
|
|
|
|
|
return %data_for if wantarray(); |
|
306
|
0
|
|
|
|
|
|
return \%data_for; |
|
307
|
|
|
|
|
|
|
} ## end sub _collect_index_for |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub _index_body_for { |
|
310
|
0
|
|
|
0
|
|
|
my ($self, $path) = @_; |
|
311
|
0
|
|
0
|
|
|
|
$path //= $self->target_dir; |
|
312
|
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
|
my $data_for = $self->_collect_index_for($path); |
|
314
|
0
|
|
|
|
|
|
my $module_data_for = $data_for->{module}; |
|
315
|
0
|
|
|
|
|
|
my @retval; |
|
316
|
0
|
|
|
|
|
|
for my $module (sort keys %{$module_data_for}) { |
|
|
0
|
|
|
|
|
|
|
|
317
|
0
|
|
|
|
|
|
my $md = $module_data_for->{$module}; |
|
318
|
0
|
|
0
|
|
|
|
my $version = $md->{version} || 'undef'; |
|
319
|
0
|
|
|
|
|
|
my $index_path = $md->{distro}; |
|
320
|
0
|
|
|
|
|
|
my $fw = 38 - length $version; |
|
321
|
0
|
0
|
|
|
|
|
$fw = length $module if $fw < length $module; |
|
322
|
0
|
|
|
|
|
|
push @retval, sprintf "%-${fw}s %s %s", $module, $version, |
|
323
|
|
|
|
|
|
|
$index_path; |
|
324
|
|
|
|
|
|
|
} ## end for my $module (sort keys...) |
|
325
|
0
|
0
|
|
|
|
|
return @retval if wantarray(); |
|
326
|
0
|
|
|
|
|
|
return \@retval; |
|
327
|
|
|
|
|
|
|
} ## end sub _index_body_for |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub action_create { |
|
330
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
|
331
|
|
|
|
|
|
|
|
|
332
|
0
|
|
|
|
|
|
my $target = $self->target_dir; |
|
333
|
0
|
0
|
|
|
|
|
LOGDIE "target directory $target exists, use update instead" |
|
334
|
|
|
|
|
|
|
if -d $target; |
|
335
|
0
|
|
|
|
|
|
$target->mkpath(); |
|
336
|
|
|
|
|
|
|
|
|
337
|
0
|
|
|
|
|
|
return $self->action_update; |
|
338
|
|
|
|
|
|
|
} ## end sub action_create |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub action_update { |
|
341
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
|
342
|
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
|
my $target = $self->target_dir; |
|
344
|
0
|
0
|
|
|
|
|
$target->mkpath() unless -d $target; |
|
345
|
|
|
|
|
|
|
|
|
346
|
0
|
|
|
|
|
|
my $dists = $target->stringify(); |
|
347
|
0
|
|
|
|
|
|
my $local = $target->subdir('local')->stringify(); |
|
348
|
0
|
0
|
|
|
|
|
my @command = ( |
|
349
|
|
|
|
|
|
|
qw< cpanm --reinstall --quiet --self-contained >, |
|
350
|
|
|
|
|
|
|
($self->execute_tests ? () : '--notest'), |
|
351
|
|
|
|
|
|
|
'--local-lib-contained' => $local, |
|
352
|
|
|
|
|
|
|
'--save-dists' => $dists, |
|
353
|
|
|
|
|
|
|
$self->args(), |
|
354
|
|
|
|
|
|
|
); |
|
355
|
|
|
|
|
|
|
|
|
356
|
0
|
|
|
|
|
|
my ($out, $err); |
|
357
|
|
|
|
|
|
|
{ |
|
358
|
0
|
|
|
|
|
|
local $SIG{TERM} = sub { |
|
359
|
0
|
|
|
0
|
|
|
WARN "cpanm: received TERM signal, ignoring"; |
|
360
|
0
|
|
|
|
|
|
}; |
|
361
|
0
|
|
|
|
|
|
INFO "calling @command"; |
|
362
|
0
|
0
|
|
|
|
|
IPC::Run::run \@command, \undef, \*STDOUT, \*STDERR |
|
363
|
|
|
|
|
|
|
or LOGDIE "cpanm: $? ($err)"; |
|
364
|
|
|
|
|
|
|
} |
|
365
|
|
|
|
|
|
|
|
|
366
|
0
|
|
|
|
|
|
INFO 'onboarding completed, indexing...'; |
|
367
|
0
|
|
|
|
|
|
$self->_do_index($target); |
|
368
|
0
|
|
|
|
|
|
my $data_for = $self->last_index(); |
|
369
|
|
|
|
|
|
|
|
|
370
|
0
|
|
|
|
|
|
INFO 'saving distlist'; |
|
371
|
0
|
|
|
|
|
|
my @distros = $self->last_distlist(); |
|
372
|
0
|
|
|
|
|
|
$self->_save2($target->file('distlist.txt'), join "\n", @distros, ''); |
|
373
|
|
|
|
|
|
|
|
|
374
|
0
|
|
|
|
|
|
INFO 'saving modlist'; |
|
375
|
0
|
|
|
|
|
|
my @modules = $self->last_modlist(); |
|
376
|
0
|
|
|
|
|
|
$self->_save2($target->file('modlist.txt'), join "\n", @modules, ''); |
|
377
|
|
|
|
|
|
|
|
|
378
|
0
|
|
|
|
|
|
my $file = $target->file('install.sh'); |
|
379
|
0
|
0
|
|
|
|
|
if (!-e $file) { |
|
380
|
0
|
|
|
|
|
|
$self->_save2($file, <<'END_OF_INSTALL'); |
|
381
|
|
|
|
|
|
|
#!/bin/bash |
|
382
|
|
|
|
|
|
|
ME=$(readlink -f "$0") |
|
383
|
|
|
|
|
|
|
MYDIR=$(dirname "$ME") |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
TARGET="$MYDIR/local" |
|
386
|
|
|
|
|
|
|
[ $# -gt 0 ] && TARGET=$1 |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
if [ -n "$TARGET" ]; then |
|
389
|
|
|
|
|
|
|
"$MYDIR/cpanm" --mirror "file://$MYDIR" --mirror-only \ |
|
390
|
|
|
|
|
|
|
-L "$TARGET" \ |
|
391
|
|
|
|
|
|
|
$(<"$MYDIR/modlist.txt") |
|
392
|
|
|
|
|
|
|
else |
|
393
|
|
|
|
|
|
|
"$MYDIR/cpanm" --mirror "file://$MYDIR" --mirror-only \ |
|
394
|
|
|
|
|
|
|
$(<"$MYDIR/modlist.txt") |
|
395
|
|
|
|
|
|
|
fi |
|
396
|
|
|
|
|
|
|
END_OF_INSTALL |
|
397
|
0
|
|
|
|
|
|
chmod 0777 & ~umask(), $file->stringify(); |
|
398
|
|
|
|
|
|
|
} ## end if (!-e $file) |
|
399
|
|
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
|
$file = $target->file('cpanm'); |
|
401
|
0
|
0
|
|
|
|
|
if (!-e $file) { |
|
402
|
0
|
|
|
|
|
|
my $cpanm = which('cpanm'); |
|
403
|
0
|
|
|
|
|
|
File::Copy::copy($cpanm, $file->stringify()); |
|
404
|
0
|
|
|
|
|
|
chmod 0777 & ~umask(), $file->stringify(); |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
} ## end sub action_update |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
{ |
|
409
|
1
|
|
|
1
|
|
8
|
no strict 'subs'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
504
|
|
|
410
|
|
|
|
|
|
|
*action_install = \&action_update; |
|
411
|
|
|
|
|
|
|
*action_add = \&action_update; |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub action_inject { |
|
415
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
|
416
|
|
|
|
|
|
|
|
|
417
|
0
|
|
|
|
|
|
my $target = $self->target_dir; |
|
418
|
0
|
0
|
|
|
|
|
$target->mkpath() unless -d $target; |
|
419
|
|
|
|
|
|
|
|
|
420
|
0
|
|
0
|
|
|
|
my $author = $self->config('author') // $ENV{EPAN_AUTHOR} // 'LOCAL'; |
|
|
|
|
0
|
|
|
|
|
|
421
|
0
|
|
|
|
|
|
my $first = substr $author, 0, 1; |
|
422
|
0
|
|
|
|
|
|
my $first_two = substr $author, 0, 2; |
|
423
|
0
|
|
|
|
|
|
my $repo = $target->subdir(qw< authors id >, $first, $first_two, $author); |
|
424
|
0
|
|
|
|
|
|
$repo->mkpath; |
|
425
|
0
|
|
|
|
|
|
$repo = $repo->stringify; |
|
426
|
|
|
|
|
|
|
|
|
427
|
0
|
|
|
|
|
|
File::Copy::copy($_, $repo) for $self->args; |
|
428
|
|
|
|
|
|
|
|
|
429
|
0
|
|
|
|
|
|
INFO 'onboarding completed, indexing...'; |
|
430
|
0
|
|
|
|
|
|
$self->_do_index($target); |
|
431
|
|
|
|
|
|
|
|
|
432
|
0
|
|
|
|
|
|
return; |
|
433
|
|
|
|
|
|
|
} |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub _list_obsoletes { |
|
436
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
|
437
|
0
|
|
|
|
|
|
my $basedir = $self->target_dir; |
|
438
|
0
|
|
|
|
|
|
my $data_for = $self->_collect_index_for($basedir); |
|
439
|
0
|
|
|
|
|
|
return sort {$a cmp $b} keys %{$data_for->{obsolete}}; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
sub action_list_obsoletes { |
|
443
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
|
444
|
0
|
|
|
|
|
|
say for $self->_list_obsoletes; |
|
445
|
0
|
|
|
|
|
|
return; |
|
446
|
|
|
|
|
|
|
} |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
sub action_purge_obsoletes { |
|
449
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
|
450
|
0
|
|
|
|
|
|
for my $file ($self->_list_obsoletes) { |
|
451
|
0
|
|
|
|
|
|
INFO "removing $file"; |
|
452
|
0
|
|
|
|
|
|
unlink $file; |
|
453
|
|
|
|
|
|
|
} |
|
454
|
0
|
|
|
|
|
|
return; |
|
455
|
|
|
|
|
|
|
} |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
sub action_list_actions { |
|
458
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
459
|
1
|
|
|
1
|
|
8
|
no strict 'refs'; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
324
|
|
|
460
|
0
|
|
|
|
|
|
say 'Available actions:'; |
|
461
|
0
|
|
|
|
|
|
say for |
|
462
|
0
|
|
|
|
|
|
sort {$a cmp $b} |
|
463
|
0
|
|
|
|
|
|
map {s/^action_/- /; s/_/-/g; $_ } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
464
|
0
|
0
|
|
|
|
|
grep {/^action_/ && $self->can($_)} |
|
465
|
0
|
|
|
|
|
|
keys %{ref($self)."::"}; |
|
466
|
0
|
|
|
|
|
|
return; |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
sub last_distlist { |
|
470
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
|
471
|
0
|
|
|
|
|
|
return keys %{$self->last_index()->{bare_distro}}; |
|
|
0
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
sub last_modlist { |
|
475
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
|
476
|
|
|
|
|
|
|
my @retval = |
|
477
|
0
|
|
|
|
|
|
map { (sort keys %$_)[0] } |
|
478
|
0
|
|
|
|
|
|
values %{$self->last_index()->{bare_distro}}; |
|
|
0
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
} ## end sub last_modlist |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
1; |
|
482
|
|
|
|
|
|
|
__END__ |