line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
33
|
|
|
33
|
|
138671
|
use strict; |
|
33
|
|
|
|
|
78
|
|
|
33
|
|
|
|
|
1706
|
|
2
|
|
|
|
|
|
|
package CPAN::Reporter; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
our $VERSION = '1.2019'; |
5
|
|
|
|
|
|
|
|
6
|
33
|
|
|
33
|
|
192
|
use Config; |
|
33
|
|
|
|
|
57
|
|
|
33
|
|
|
|
|
1628
|
|
7
|
33
|
|
|
33
|
|
797
|
use Capture::Tiny qw/ capture tee_merged /; |
|
33
|
|
|
|
|
6638
|
|
|
33
|
|
|
|
|
2178
|
|
8
|
33
|
|
|
33
|
|
233
|
use CPAN 1.94 (); |
|
33
|
|
|
|
|
703
|
|
|
33
|
|
|
|
|
859
|
|
9
|
|
|
|
|
|
|
#CPAN.pm was split into separate files in this version |
10
|
|
|
|
|
|
|
#set minimum to it for simplicity |
11
|
33
|
|
|
33
|
|
15580
|
use CPAN::Version (); |
|
33
|
|
|
|
|
43351
|
|
|
33
|
|
|
|
|
900
|
|
12
|
33
|
|
|
33
|
|
263
|
use File::Basename qw/basename dirname/; |
|
33
|
|
|
|
|
68
|
|
|
33
|
|
|
|
|
1958
|
|
13
|
33
|
|
|
33
|
|
235
|
use File::Find (); |
|
33
|
|
|
|
|
70
|
|
|
33
|
|
|
|
|
457
|
|
14
|
33
|
|
|
33
|
|
171
|
use File::HomeDir (); |
|
33
|
|
|
|
|
72
|
|
|
33
|
|
|
|
|
580
|
|
15
|
33
|
|
|
33
|
|
178
|
use File::Path qw/mkpath rmtree/; |
|
33
|
|
|
|
|
84
|
|
|
33
|
|
|
|
|
1749
|
|
16
|
33
|
|
|
33
|
|
213
|
use File::Spec 3.19 (); |
|
33
|
|
|
|
|
733
|
|
|
33
|
|
|
|
|
828
|
|
17
|
33
|
|
|
33
|
|
198
|
use File::Temp 0.16 qw/tempdir/; |
|
33
|
|
|
|
|
859
|
|
|
33
|
|
|
|
|
1505
|
|
18
|
33
|
|
|
33
|
|
1575
|
use IO::File (); |
|
33
|
|
|
|
|
3280
|
|
|
33
|
|
|
|
|
500
|
|
19
|
33
|
|
|
33
|
|
16325
|
use Parse::CPAN::Meta (); |
|
33
|
|
|
|
|
54372
|
|
|
33
|
|
|
|
|
751
|
|
20
|
33
|
|
|
33
|
|
1146
|
use Probe::Perl (); |
|
33
|
|
|
|
|
2362
|
|
|
33
|
|
|
|
|
628
|
|
21
|
33
|
|
|
33
|
|
1696
|
use Test::Reporter 1.54 (); |
|
33
|
|
|
|
|
36395
|
|
|
33
|
|
|
|
|
594
|
|
22
|
33
|
|
|
33
|
|
18481
|
use CPAN::Reporter::Config (); |
|
33
|
|
|
|
|
124
|
|
|
33
|
|
|
|
|
925
|
|
23
|
33
|
|
|
33
|
|
17549
|
use CPAN::Reporter::History (); |
|
33
|
|
|
|
|
177
|
|
|
33
|
|
|
|
|
849
|
|
24
|
33
|
|
|
33
|
|
16002
|
use CPAN::Reporter::PrereqCheck (); |
|
33
|
|
|
|
|
126
|
|
|
33
|
|
|
|
|
872
|
|
25
|
|
|
|
|
|
|
|
26
|
33
|
|
|
33
|
|
244
|
use constant MAX_OUTPUT_LENGTH => 1_000_000; |
|
33
|
|
|
|
|
71
|
|
|
33
|
|
|
|
|
2279
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
29
|
|
|
|
|
|
|
# create temp lib dir for Devel::Autoflush |
30
|
|
|
|
|
|
|
# so that PERL5OPT=-MDevel::Autoflush is found by any perl |
31
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
32
|
|
|
|
|
|
|
|
33
|
33
|
|
|
33
|
|
16169
|
use Devel::Autoflush 0.04 (); |
|
33
|
|
|
|
|
2310
|
|
|
33
|
|
|
|
|
273783
|
|
34
|
|
|
|
|
|
|
# directory fixture |
35
|
|
|
|
|
|
|
my $Autoflush_Lib = tempdir( |
36
|
|
|
|
|
|
|
"CPAN-Reporter-lib-XXXX", TMPDIR => 1, CLEANUP => 1 |
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
# copy Devel::Autoflush to directory or clear autoflush_lib variable |
39
|
|
|
|
|
|
|
_file_copy_quiet( |
40
|
|
|
|
|
|
|
$INC{'Devel/Autoflush.pm'}, |
41
|
|
|
|
|
|
|
File::Spec->catfile( $Autoflush_Lib, qw/Devel Autoflush.pm/ ) |
42
|
|
|
|
|
|
|
) or undef $Autoflush_Lib; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
45
|
|
|
|
|
|
|
# public API |
46
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub configure { |
49
|
2
|
|
|
2
|
0
|
12857
|
goto &CPAN::Reporter::Config::_configure; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub grade_make { |
53
|
16
|
|
|
16
|
0
|
2712
|
my @args = @_; |
54
|
16
|
100
|
|
|
|
264
|
my $result = _init_result( 'make', @args ) or return; |
55
|
15
|
|
|
|
|
198
|
_compute_make_grade($result); |
56
|
15
|
100
|
|
|
|
150
|
if ( $result->{grade} eq 'discard' ) { |
57
|
|
|
|
|
|
|
$CPAN::Frontend->myprint( |
58
|
|
|
|
|
|
|
"\nCPAN::Reporter: test results were not valid, $result->{grade_msg}.\n\n", |
59
|
4
|
|
|
|
|
364
|
$result->{prereq_pm}, "\n", |
60
|
|
|
|
|
|
|
"Test report will not be sent" |
61
|
|
|
|
|
|
|
); |
62
|
4
|
100
|
|
|
|
306
|
CPAN::Reporter::History::_record_history( $result ) |
63
|
|
|
|
|
|
|
if not CPAN::Reporter::History::_is_duplicate( $result ); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
else { |
66
|
11
|
|
|
|
|
192
|
_print_grade_msg($result->{make_cmd}, $result); |
67
|
11
|
100
|
|
|
|
128
|
if ( $result->{grade} ne 'pass' ) { _dispatch_report( $result ) } |
|
9
|
|
|
|
|
121
|
|
68
|
|
|
|
|
|
|
} |
69
|
15
|
|
|
|
|
1537
|
return $result->{success}; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub grade_PL { |
73
|
34
|
|
|
34
|
0
|
12081
|
my @args = @_; |
74
|
34
|
100
|
|
|
|
645
|
my $result = _init_result( 'PL', @args ) or return; |
75
|
33
|
|
|
|
|
344
|
_compute_PL_grade($result); |
76
|
33
|
100
|
|
|
|
225
|
if ( $result->{grade} eq 'discard' ) { |
77
|
|
|
|
|
|
|
$CPAN::Frontend->myprint( |
78
|
|
|
|
|
|
|
"\nCPAN::Reporter: test results were not valid, $result->{grade_msg}.\n\n", |
79
|
9
|
|
|
|
|
688
|
$result->{prereq_pm}, "\n", |
80
|
|
|
|
|
|
|
"Test report will not be sent" |
81
|
|
|
|
|
|
|
); |
82
|
9
|
100
|
|
|
|
663
|
CPAN::Reporter::History::_record_history( $result ) |
83
|
|
|
|
|
|
|
if not CPAN::Reporter::History::_is_duplicate( $result ); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
else { |
86
|
24
|
|
|
|
|
417
|
_print_grade_msg($result->{PL_file} , $result); |
87
|
24
|
100
|
|
|
|
216
|
if ( $result->{grade} ne 'pass' ) { _dispatch_report( $result ) } |
|
18
|
|
|
|
|
301
|
|
88
|
|
|
|
|
|
|
} |
89
|
33
|
|
|
|
|
3460
|
return $result->{success}; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub grade_test { |
93
|
119
|
|
|
119
|
0
|
5400
|
my @args = @_; |
94
|
119
|
100
|
|
|
|
2590
|
my $result = _init_result( 'test', @args ) or return; |
95
|
118
|
|
|
|
|
1463
|
_compute_test_grade($result); |
96
|
118
|
100
|
|
|
|
827
|
if ( $result->{grade} eq 'discard' ) { |
97
|
|
|
|
|
|
|
$CPAN::Frontend->myprint( |
98
|
|
|
|
|
|
|
"\nCPAN::Reporter: test results were not valid, $result->{grade_msg}.\n\n", |
99
|
15
|
|
|
|
|
912
|
$result->{prereq_pm}, "\n", |
100
|
|
|
|
|
|
|
"Test report will not be sent" |
101
|
|
|
|
|
|
|
); |
102
|
15
|
100
|
|
|
|
1142
|
CPAN::Reporter::History::_record_history( $result ) |
103
|
|
|
|
|
|
|
if not CPAN::Reporter::History::_is_duplicate( $result ); |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
else { |
106
|
103
|
|
|
|
|
1516
|
_print_grade_msg( "Test", $result ); |
107
|
103
|
|
|
|
|
1046
|
_dispatch_report( $result ); |
108
|
|
|
|
|
|
|
} |
109
|
118
|
|
|
|
|
12658
|
return $result->{success}; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub record_command { |
113
|
186
|
|
|
186
|
0
|
44566638
|
my ($command, $timeout) = @_; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# XXX refactor this! |
116
|
|
|
|
|
|
|
# Get configuration options |
117
|
186
|
100
|
|
|
|
4255
|
if ( -r CPAN::Reporter::Config::_get_config_file() ) { |
118
|
170
|
|
|
|
|
2424
|
my $config_obj = CPAN::Reporter::Config::_open_config_file(); |
119
|
170
|
|
|
|
|
624
|
my $config; |
120
|
170
|
50
|
|
|
|
2031
|
$config = CPAN::Reporter::Config::_get_config_options( $config_obj ) |
121
|
|
|
|
|
|
|
if $config_obj; |
122
|
|
|
|
|
|
|
|
123
|
170
|
|
100
|
|
|
3174
|
$timeout ||= $config->{command_timeout}; # might still be undef |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
186
|
|
|
|
|
2208
|
my ($cmd, $redirect) = _split_redirect($command); |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Teeing a command loses its exit value so we must wrap the command |
129
|
|
|
|
|
|
|
# and print the exit code so we can read it off of output |
130
|
186
|
|
|
|
|
607
|
my $wrap_code; |
131
|
186
|
100
|
|
|
|
869
|
if ( $timeout ) { |
132
|
15
|
50
|
|
|
|
183
|
$wrap_code = $^O eq 'MSWin32' |
133
|
|
|
|
|
|
|
? _timeout_wrapper_win32($cmd, $timeout) |
134
|
|
|
|
|
|
|
: _timeout_wrapper($cmd, $timeout); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
# if no timeout or timeout wrap code wasn't available |
137
|
186
|
100
|
|
|
|
839
|
if ( ! $wrap_code ) { |
138
|
171
|
|
|
|
|
870
|
my $safecmd = quotemeta($cmd); |
139
|
171
|
|
|
|
|
1235
|
$wrap_code = << "HERE"; |
140
|
|
|
|
|
|
|
my \$rc = system("$safecmd"); |
141
|
|
|
|
|
|
|
my \$ec = \$rc == -1 ? -1 : \$?; |
142
|
|
|
|
|
|
|
print "($safecmd exited with \$ec)\\n"; |
143
|
|
|
|
|
|
|
HERE |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# write code to a tempfile for execution |
147
|
186
|
|
|
|
|
1373
|
my $wrapper_name = _temp_filename( 'CPAN-Reporter-CW-' ); |
148
|
186
|
50
|
|
|
|
5223
|
my $wrapper_fh = IO::File->new( $wrapper_name, 'w' ) |
149
|
|
|
|
|
|
|
or die "Could not create a wrapper for $cmd\: $!"; |
150
|
|
|
|
|
|
|
|
151
|
186
|
|
|
|
|
57172
|
$wrapper_fh->print( $wrap_code ); |
152
|
186
|
|
|
|
|
4729
|
$wrapper_fh->close; |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# tee the command wrapper |
155
|
186
|
|
|
|
|
16105
|
my @tee_input = ( Probe::Perl->find_perl_interpreter, $wrapper_name ); |
156
|
186
|
100
|
|
|
|
6708
|
push @tee_input, $redirect if defined $redirect; |
157
|
186
|
|
|
|
|
483
|
my $tee_out; |
158
|
|
|
|
|
|
|
{ |
159
|
|
|
|
|
|
|
# ensure autoflush if we can |
160
|
186
|
100
|
|
|
|
477
|
local $ENV{PERL5OPT} = _get_perl5opt() if _is_PL($command); |
|
186
|
|
|
|
|
1815
|
|
161
|
186
|
|
|
186
|
|
10353
|
$tee_out = tee_merged { system( @tee_input ) }; |
|
186
|
|
|
|
|
132174946
|
|
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# cleanup |
165
|
186
|
50
|
|
|
|
650691
|
unlink $wrapper_name unless $ENV{PERL_CR_NO_CLEANUP}; |
166
|
|
|
|
|
|
|
|
167
|
186
|
|
|
|
|
34931
|
my @cmd_output = split qr{(?<=$/)}, $tee_out; |
168
|
186
|
50
|
|
|
|
2200
|
if ( ! @cmd_output ) { |
169
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( |
170
|
|
|
|
|
|
|
"CPAN::Reporter: didn't capture command results for '$cmd'\n" |
171
|
|
|
|
|
|
|
); |
172
|
0
|
|
|
|
|
0
|
return; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# extract the exit value |
176
|
186
|
|
|
|
|
917
|
my $exit_value; |
177
|
186
|
50
|
|
|
|
4339
|
if ( $cmd_output[-1] =~ m{exited with} ) { |
178
|
186
|
|
|
|
|
4587
|
($exit_value) = $cmd_output[-1] =~ m{exited with ([-0-9]+)}; |
179
|
186
|
|
|
|
|
1246
|
pop @cmd_output; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# bail out on some errors |
183
|
186
|
50
|
|
|
|
2292
|
if ( ! defined $exit_value ) { |
|
|
50
|
|
|
|
|
|
184
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( |
185
|
|
|
|
|
|
|
"CPAN::Reporter: couldn't determine exit value for '$cmd'\n" |
186
|
|
|
|
|
|
|
); |
187
|
0
|
|
|
|
|
0
|
return; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
elsif ( $exit_value == -1 ) { |
190
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( |
191
|
|
|
|
|
|
|
"CPAN::Reporter: couldn't execute '$cmd'\n" |
192
|
|
|
|
|
|
|
); |
193
|
0
|
|
|
|
|
0
|
return; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
186
|
|
|
|
|
8039
|
return \@cmd_output, $exit_value; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub test { |
200
|
76
|
|
|
76
|
0
|
18081161
|
my ($dist, $system_command) = @_; |
201
|
76
|
|
|
|
|
992
|
my ($output, $exit_value) = record_command( $system_command ); |
202
|
76
|
|
|
|
|
973
|
return grade_test( $dist, $system_command, $output, $exit_value ); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
206
|
|
|
|
|
|
|
# private functions |
207
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
210
|
|
|
|
|
|
|
# _compute_make_grade |
211
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub _compute_make_grade { |
214
|
15
|
|
|
15
|
|
73
|
my $result = shift; |
215
|
15
|
|
|
|
|
77
|
my ($grade,$msg); |
216
|
15
|
100
|
|
|
|
106
|
if ( $result->{exit_value} ) { |
217
|
13
|
|
|
|
|
197
|
$result->{grade} = "unknown"; |
218
|
13
|
|
|
|
|
153
|
$result->{grade_msg} = "Stopped with an error" |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
else { |
221
|
2
|
|
|
|
|
37
|
$result->{grade} = "pass"; |
222
|
2
|
|
|
|
|
31
|
$result->{grade_msg} = "No errors" |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
15
|
|
|
|
|
261
|
_downgrade_known_causes( $result ); |
226
|
|
|
|
|
|
|
|
227
|
15
|
|
|
|
|
234
|
$result->{success} = $result->{grade} eq 'pass'; |
228
|
15
|
|
|
|
|
129
|
return; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
232
|
|
|
|
|
|
|
# _compute_PL_grade |
233
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub _compute_PL_grade { |
236
|
33
|
|
|
33
|
|
149
|
my $result = shift; |
237
|
33
|
|
|
|
|
122
|
my ($grade,$msg); |
238
|
33
|
100
|
|
|
|
243
|
if ( $result->{exit_value} ) { |
239
|
23
|
|
|
|
|
370
|
$result->{grade} = "unknown"; |
240
|
23
|
|
|
|
|
310
|
$result->{grade_msg} = "Stopped with an error" |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
else { |
243
|
10
|
|
|
|
|
150
|
$result->{grade} = "pass"; |
244
|
10
|
|
|
|
|
104
|
$result->{grade_msg} = "No errors" |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
33
|
|
|
|
|
555
|
_downgrade_known_causes( $result ); |
248
|
|
|
|
|
|
|
|
249
|
33
|
|
|
|
|
495
|
$result->{success} = $result->{grade} eq 'pass'; |
250
|
33
|
|
|
|
|
286
|
return; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
254
|
|
|
|
|
|
|
# _compute_test_grade |
255
|
|
|
|
|
|
|
# |
256
|
|
|
|
|
|
|
# Don't shortcut to unknown unless _has_tests because a custom |
257
|
|
|
|
|
|
|
# Makefile.PL or Build.PL might define tests in a non-standard way |
258
|
|
|
|
|
|
|
# |
259
|
|
|
|
|
|
|
# With test.pl and 'make test', any t/*.t might pass Test::Harness, but |
260
|
|
|
|
|
|
|
# test.pl might still fail, or there might only be test.pl, |
261
|
|
|
|
|
|
|
# so use exit code directly |
262
|
|
|
|
|
|
|
# |
263
|
|
|
|
|
|
|
# Likewise, if we have recursive Makefile.PL, then we don't trust the |
264
|
|
|
|
|
|
|
# reverse-order parsing and should just take the exit code directly |
265
|
|
|
|
|
|
|
# |
266
|
|
|
|
|
|
|
# Otherwise, parse in reverse order for Test::Harness output or a couple |
267
|
|
|
|
|
|
|
# other significant strings and stop after the first match. Going in |
268
|
|
|
|
|
|
|
# reverse and stopping is done to (hopefully) avoid picking up spurious |
269
|
|
|
|
|
|
|
# results from any test output. But then we have to check for |
270
|
|
|
|
|
|
|
# unsupported OS strings in case those were printed but were not fatal. |
271
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub _compute_test_grade { |
274
|
118
|
|
|
118
|
|
544
|
my $result = shift; |
275
|
118
|
|
|
|
|
517
|
my ($grade,$msg); |
276
|
118
|
|
|
|
|
446
|
my $output = $result->{output}; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
# In some cases, get a result straight from the exit code |
279
|
118
|
100
|
100
|
|
|
2834
|
if ( $result->{is_make} && ( -f "test.pl" || _has_recursive_make() ) ) { |
|
|
|
100
|
|
|
|
|
280
|
16
|
100
|
|
|
|
228
|
if ( $result->{exit_value} ) { |
281
|
10
|
|
|
|
|
131
|
$grade = "fail"; |
282
|
10
|
|
|
|
|
59
|
$msg = "'make test' error detected"; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
else { |
285
|
6
|
|
|
|
|
28
|
$grade = "pass"; |
286
|
6
|
|
|
|
|
43
|
$msg = "'make test' no errors"; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
# Otherwise, get a result from Test::Harness output |
290
|
|
|
|
|
|
|
else { |
291
|
|
|
|
|
|
|
# figure out the right harness parser |
292
|
102
|
|
|
|
|
1230
|
_expand_result( $result ); |
293
|
102
|
|
|
|
|
1269
|
my $harness_version = $result->{toolchain}{'Test::Harness'}{have}; |
294
|
102
|
50
|
|
|
|
4563
|
my $harness_parser = CPAN::Version->vgt($harness_version, '2.99_01') |
295
|
|
|
|
|
|
|
? \&_parse_tap_harness |
296
|
|
|
|
|
|
|
: \&_parse_test_harness; |
297
|
|
|
|
|
|
|
# parse lines in reverse |
298
|
102
|
|
|
|
|
16667
|
for my $i ( reverse 0 .. $#{$output} ) { |
|
102
|
|
|
|
|
1376
|
|
299
|
308
|
100
|
|
|
|
4370
|
if ( $output->[$i] =~ m{No support for OS|OS unsupported}ims ) { # from any *.t file |
|
|
100
|
|
|
|
|
|
300
|
6
|
|
|
|
|
61
|
$grade = 'na'; |
301
|
6
|
|
|
|
|
35
|
$msg = 'This platform is not supported'; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
elsif ( $output->[$i] =~ m{^.?No tests defined}ms ) { # from M::B |
304
|
8
|
|
|
|
|
67
|
$grade = 'unknown'; |
305
|
8
|
|
|
|
|
51
|
$msg = 'No tests provided'; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
else { |
308
|
294
|
|
|
|
|
1189
|
($grade, $msg) = $harness_parser->( $output->[$i] ); |
309
|
|
|
|
|
|
|
} |
310
|
308
|
100
|
|
|
|
1210
|
last if $grade; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
# fallback on exit value if no recognizable Test::Harness output |
313
|
102
|
100
|
|
|
|
884
|
if ( ! $grade ) { |
314
|
12
|
100
|
|
|
|
235
|
$grade = $result->{exit_value} ? "fail" : "pass"; |
315
|
|
|
|
|
|
|
$msg = ( $result->{is_make} ? "'make test' " : "'Build test' " ) |
316
|
12
|
100
|
|
|
|
209
|
. ( $result->{exit_value} ? "error detected" : "no errors"); |
|
|
100
|
|
|
|
|
|
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
118
|
|
|
|
|
1404
|
$result->{grade} = $grade; |
321
|
118
|
|
|
|
|
1222
|
$result->{grade_msg} = $msg; |
322
|
|
|
|
|
|
|
|
323
|
118
|
|
|
|
|
1658
|
_downgrade_known_causes( $result ); |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
$result->{success} = $result->{grade} eq 'pass' |
326
|
118
|
|
100
|
|
|
1728
|
|| $result->{grade} eq 'unknown'; |
327
|
118
|
|
|
|
|
816
|
return; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
331
|
|
|
|
|
|
|
# _dispatch_report |
332
|
|
|
|
|
|
|
# |
333
|
|
|
|
|
|
|
# Set up Test::Reporter and prompt user for edit, send |
334
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub _dispatch_report { |
337
|
131
|
|
|
131
|
|
10686
|
my $result = shift; |
338
|
131
|
|
|
|
|
903
|
my $phase = $result->{phase}; |
339
|
|
|
|
|
|
|
|
340
|
131
|
|
|
|
|
1512
|
$CPAN::Frontend->myprint( |
341
|
|
|
|
|
|
|
"CPAN::Reporter: preparing a CPAN Testers report for $result->{dist_name}\n" |
342
|
|
|
|
|
|
|
); |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# Get configuration options |
345
|
131
|
|
|
|
|
4882
|
my $config_obj = CPAN::Reporter::Config::_open_config_file(); |
346
|
131
|
|
|
|
|
501
|
my $config; |
347
|
131
|
100
|
|
|
|
1439
|
$config = CPAN::Reporter::Config::_get_config_options( $config_obj ) |
348
|
|
|
|
|
|
|
if $config_obj; |
349
|
131
|
100
|
|
|
|
994
|
if ( ! $config->{email_from} ) { |
350
|
5
|
|
|
|
|
27
|
$CPAN::Frontend->mywarn( << "EMAIL_REQUIRED"); |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
CPAN::Reporter: required 'email_from' option missing an email address, so |
353
|
|
|
|
|
|
|
test report will not be sent. See documentation for configuration details. |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Even though CPAN Testers no longer uses email, this email address will |
356
|
|
|
|
|
|
|
show up in the report and help identify the tester. This is required |
357
|
|
|
|
|
|
|
for compatibility with tools that process legacy reports for analysis. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
EMAIL_REQUIRED |
360
|
5
|
|
|
|
|
96
|
return; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# Need to know if this is a duplicate |
364
|
126
|
|
|
|
|
1048
|
my $is_duplicate = CPAN::Reporter::History::_is_duplicate( $result ); |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# Abort if the distribution name is not formatted according to |
367
|
|
|
|
|
|
|
# CPAN Testers requirements: Dist-Name-version.suffix |
368
|
|
|
|
|
|
|
# Regex from CPAN-Testers should extract name, separator, version |
369
|
|
|
|
|
|
|
# and extension |
370
|
|
|
|
|
|
|
my @format_checks = $result->{dist_basename} =~ |
371
|
126
|
|
|
|
|
3659
|
m{(.+)([\-\_])(v?\d.*)(\.(?:tar\.(?:gz|bz2)|tgz|zip))$}i; |
372
|
|
|
|
|
|
|
; |
373
|
126
|
100
|
|
|
|
621
|
if ( ! grep { length } @format_checks ) { |
|
492
|
|
|
|
|
1435
|
|
374
|
3
|
|
|
|
|
68
|
$CPAN::Frontend->mywarn( << "END_BAD_DISTNAME"); |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
CPAN::Reporter: the distribution name '$result->{dist_basename}' does not |
377
|
|
|
|
|
|
|
appear to be packaged according to CPAN tester guidelines. Perhaps it is |
378
|
|
|
|
|
|
|
not a normal CPAN distribution. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
Test report will not be sent. |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
END_BAD_DISTNAME |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# record this as a discard, instead |
385
|
3
|
|
|
|
|
117
|
$result->{grade} = 'discard'; |
386
|
3
|
50
|
|
|
|
70
|
CPAN::Reporter::History::_record_history( $result ) |
387
|
|
|
|
|
|
|
if not $is_duplicate; |
388
|
3
|
|
|
|
|
29
|
return; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# Gather 'expensive' data for the report |
392
|
123
|
|
|
|
|
671
|
_expand_result( $result); |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# Skip if distribution name matches the send_skipfile |
395
|
123
|
100
|
66
|
|
|
895
|
if ( $config->{send_skipfile} && -r $config->{send_skipfile} ) { |
396
|
4
|
|
|
|
|
68
|
my $send_skipfile = IO::File->new( $config->{send_skipfile}, "r" ); |
397
|
4
|
|
|
|
|
766
|
my $dist_id = $result->{dist}->pretty_id; |
398
|
4
|
|
|
|
|
168
|
while ( my $pattern = <$send_skipfile> ) { |
399
|
11
|
|
|
|
|
42
|
chomp($pattern); |
400
|
|
|
|
|
|
|
# ignore comments |
401
|
11
|
100
|
|
|
|
48
|
next if substr($pattern,0,1) eq '#'; |
402
|
|
|
|
|
|
|
# if it doesn't match, continue with next pattern |
403
|
7
|
100
|
|
|
|
188
|
next if $dist_id !~ /$pattern/i; |
404
|
|
|
|
|
|
|
# if it matches, warn and return |
405
|
3
|
|
|
|
|
51
|
$CPAN::Frontend->myprint( << "END_SKIP_DIST" ); |
406
|
|
|
|
|
|
|
CPAN::Reporter: '$dist_id' matched against the send_skipfile. |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
Test report will not be sent. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
END_SKIP_DIST |
411
|
|
|
|
|
|
|
|
412
|
3
|
|
|
|
|
154
|
return; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# Setup the test report |
417
|
120
|
|
|
|
|
3862
|
my $tr = Test::Reporter->new; |
418
|
120
|
|
|
|
|
4848
|
$tr->grade( $result->{grade} ); |
419
|
120
|
|
|
|
|
2452
|
$tr->distribution( $result->{dist_name} ); |
420
|
|
|
|
|
|
|
# Older Test::Reporter doesn't support distfile, but we need it for |
421
|
|
|
|
|
|
|
# Metabase transport |
422
|
|
|
|
|
|
|
$tr->distfile( $result->{dist}->pretty_id ) |
423
|
120
|
50
|
|
|
|
3946
|
if $Test::Reporter::VERSION >= 1.54; |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# Skip if duplicate and not sending duplicates |
426
|
120
|
100
|
|
|
|
3066
|
if ( $is_duplicate ) { |
427
|
74
|
100
|
|
|
|
515
|
if ( _prompt( $config, "send_duplicates", $tr->grade) =~ /^n/ ) { |
428
|
2
|
|
|
|
|
11
|
$CPAN::Frontend->myprint(<< "DUPLICATE_REPORT"); |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
CPAN::Reporter: this appears to be a duplicate report for the $phase phase: |
431
|
2
|
|
|
|
|
15
|
@{[$tr->subject]} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
Test report will not be sent. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
DUPLICATE_REPORT |
436
|
|
|
|
|
|
|
|
437
|
2
|
|
|
|
|
149
|
return; |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
# Set debug and transport options, if supported |
442
|
118
|
50
|
|
|
|
610
|
$tr->debug( $config->{debug} ) if defined $config->{debug}; |
443
|
118
|
|
|
|
|
726
|
my $transport = $config->{transport}; |
444
|
118
|
50
|
33
|
|
|
1646
|
unless ( defined $transport && length $transport ) { |
445
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( << "TRANSPORT_REQUIRED"); |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
CPAN::Reporter: required 'transport' option missing so the test report |
448
|
|
|
|
|
|
|
will not be sent. See documentation for configuration details. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
TRANSPORT_REQUIRED |
451
|
0
|
|
|
|
|
0
|
return; |
452
|
|
|
|
|
|
|
} |
453
|
118
|
|
|
|
|
1023
|
my @transport_args = split " ", $transport; |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# special hack for Metabase arguments |
456
|
118
|
100
|
|
|
|
602
|
if ($transport_args[0] eq 'Metabase') { |
457
|
116
|
|
|
|
|
612
|
@transport_args = _validate_metabase_args(@transport_args); |
458
|
116
|
50
|
|
|
|
668
|
unless (@transport_args) { |
459
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( "Test report will not be sent.\n\n" ); |
460
|
0
|
|
|
|
|
0
|
return; |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
118
|
|
|
|
|
312
|
eval { $tr->transport( @transport_args ) }; |
|
118
|
|
|
|
|
919
|
|
465
|
118
|
100
|
|
|
|
3883
|
if ($@) { |
466
|
1
|
|
|
|
|
23
|
$CPAN::Frontend->mywarn( |
467
|
|
|
|
|
|
|
"CPAN::Reporter: problem with Test::Reporter transport: \n" . |
468
|
|
|
|
|
|
|
"$@\n" . |
469
|
|
|
|
|
|
|
"Test report will not be sent\n" |
470
|
|
|
|
|
|
|
); |
471
|
1
|
|
|
|
|
55
|
return; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# prepare mail transport |
475
|
117
|
|
|
|
|
1098
|
$tr->from( $config->{email_from} ); |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
# Populate the test report |
478
|
117
|
|
|
|
|
1909
|
$tr->comments( _report_text( $result ) ); |
479
|
117
|
|
|
|
|
2575
|
$tr->via( 'CPAN::Reporter ' . $CPAN::Reporter::VERSION ); |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# prompt for editing report |
482
|
117
|
50
|
|
|
|
1389
|
if ( _prompt( $config, "edit_report", $tr->grade ) =~ /^y/ ) { |
483
|
0
|
|
|
|
|
0
|
my $editor = $config->{editor}; |
484
|
0
|
0
|
|
|
|
0
|
local $ENV{VISUAL} = $editor if $editor; ## no critic |
485
|
0
|
|
|
|
|
0
|
$tr->edit_comments; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
# send_*_report can override send_report |
489
|
117
|
100
|
|
|
|
1370
|
my $send_config = defined $config->{"send_$phase\_report"} |
490
|
|
|
|
|
|
|
? "send_$phase\_report" |
491
|
|
|
|
|
|
|
: "send_report" ; |
492
|
117
|
100
|
|
|
|
1103
|
if ( _prompt( $config, $send_config, $tr->grade ) =~ /^y/ ) { |
493
|
114
|
|
|
|
|
845
|
$CPAN::Frontend->myprint( "CPAN::Reporter: sending test report with '" . $tr->grade . |
494
|
|
|
|
|
|
|
"' via " . $transport_args[0] . "\n"); |
495
|
114
|
50
|
|
|
|
5381
|
if ( $tr->send() ) { |
496
|
114
|
100
|
|
|
|
1726
|
CPAN::Reporter::History::_record_history( $result ) |
497
|
|
|
|
|
|
|
if not $is_duplicate; |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
else { |
500
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( "CPAN::Reporter: " . $tr->errstr . "\n"); |
501
|
|
|
|
|
|
|
|
502
|
0
|
0
|
|
|
|
0
|
if ( $config->{retry_submission} ) { |
503
|
0
|
|
|
|
|
0
|
sleep(3); |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( "CPAN::Reporter: second attempt\n"); |
506
|
0
|
|
|
|
|
0
|
$tr->errstr(''); |
507
|
|
|
|
|
|
|
|
508
|
0
|
0
|
|
|
|
0
|
if ( $tr->send() ) { |
509
|
0
|
0
|
|
|
|
0
|
CPAN::Reporter::History::_record_history( $result ) |
510
|
|
|
|
|
|
|
if not $is_duplicate; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
else { |
513
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( "CPAN::Reporter: " . $tr->errstr . "\n"); |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
else { |
520
|
3
|
|
|
|
|
20
|
$CPAN::Frontend->myprint("CPAN::Reporter: test report will not be sent\n"); |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
117
|
|
|
|
|
1827
|
return; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
sub _report_timeout { |
527
|
129
|
|
|
129
|
|
697
|
my $result = shift; |
528
|
129
|
100
|
|
|
|
1025
|
if ($result->{exit_value} == 9) { |
529
|
2
|
|
|
|
|
38
|
my $config_obj = CPAN::Reporter::Config::_open_config_file(); |
530
|
2
|
|
|
|
|
15
|
my $config; |
531
|
2
|
50
|
|
|
|
43
|
$config = CPAN::Reporter::Config::_get_config_options( $config_obj ) |
532
|
|
|
|
|
|
|
if $config_obj; |
533
|
|
|
|
|
|
|
|
534
|
2
|
50
|
|
|
|
26
|
if ($config->{'_store_problems_in_dir'}) { |
535
|
0
|
|
|
|
|
0
|
my $distribution = $result->{dist}->base_id; |
536
|
0
|
|
|
|
|
0
|
my $file = "e9.$distribution.${\(time)}.$$.log"; |
|
0
|
|
|
|
|
0
|
|
537
|
0
|
0
|
|
|
|
0
|
if (open my $to_log_fh, '>>', $config->{'_store_problems_in_dir'}.'/'.$file) { |
538
|
0
|
|
|
|
|
0
|
print $to_log_fh $distribution,"\n"; |
539
|
0
|
|
|
|
|
0
|
print $to_log_fh "stage: ",$result->{phase},"\n"; |
540
|
0
|
|
|
|
|
0
|
print $to_log_fh $Config{archname},"\n"; |
541
|
0
|
|
|
|
|
0
|
print $to_log_fh _report_text( $result ); |
542
|
|
|
|
|
|
|
} else { |
543
|
|
|
|
|
|
|
$CPAN::Frontend->mywarn( "CPAN::Reporter: writing ". |
544
|
0
|
|
|
|
|
0
|
$config->{'_store_problems_in_dir'}.'/'.$file. " failed\n"); |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
} |
547
|
2
|
50
|
|
|
|
35
|
if ($config->{'_problem_log'}) { |
548
|
0
|
|
|
|
|
0
|
my $distribution = $result->{dist}->base_id; |
549
|
0
|
0
|
|
|
|
0
|
if (open my $to_log_fh, '>>', $config->{'_problem_log'}) { |
550
|
0
|
|
|
|
|
0
|
print $to_log_fh "$result->{phase} $distribution $Config{archname}\n"; |
551
|
|
|
|
|
|
|
} else { |
552
|
|
|
|
|
|
|
$CPAN::Frontend->mywarn( "CPAN::Reporter: writing ". |
553
|
0
|
|
|
|
|
0
|
$config->{'_store_problems_in_dir'}. " failed\n"); |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
560
|
|
|
|
|
|
|
# _downgrade_known_causes |
561
|
|
|
|
|
|
|
# Downgrade failure/unknown grade if we can determine a cause |
562
|
|
|
|
|
|
|
# If platform not supported => 'na' |
563
|
|
|
|
|
|
|
# If perl version is too low => 'na' |
564
|
|
|
|
|
|
|
# If stated prereqs missing => 'discard' |
565
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
sub _downgrade_known_causes { |
568
|
169
|
|
|
169
|
|
1025
|
my ($result) = @_; |
569
|
169
|
|
|
|
|
1116
|
my ($grade, $output) = ( $result->{grade}, $result->{output} ); |
570
|
169
|
|
50
|
|
|
1118
|
my $msg = $result->{grade_msg} || q{}; |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
# shortcut unless fail/unknown; but PL might look like pass but actually |
573
|
|
|
|
|
|
|
# have "OS Unsupported" messages if someone printed message and then |
574
|
|
|
|
|
|
|
# did "exit 0" |
575
|
169
|
100
|
|
|
|
1013
|
return if $grade eq 'na'; |
576
|
163
|
100
|
100
|
|
|
1746
|
return if $grade eq 'pass' && $result->{phase} ne 'PL'; |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
# get prereqs |
579
|
129
|
|
|
|
|
1085
|
_expand_result( $result ); |
580
|
|
|
|
|
|
|
|
581
|
129
|
|
|
|
|
2375
|
_report_timeout( $result ); |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
# if process was halted with a signal, just set for discard and return |
584
|
129
|
100
|
|
|
|
1033
|
if ( $result->{exit_value} & 127 ) { |
585
|
2
|
|
|
|
|
23
|
$result->{grade} = 'discard'; |
586
|
2
|
|
|
|
|
22
|
$result->{grade_msg} = 'Command interrupted'; |
587
|
2
|
|
|
|
|
14
|
return; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# look for perl version error messages from various programs |
591
|
|
|
|
|
|
|
# "Error evaling..." type errors happen on Perl < 5.006 when modules |
592
|
|
|
|
|
|
|
# define their version with "our $VERSION = ..." |
593
|
127
|
|
|
|
|
515
|
my ($harness_error, $version_error, $unsupported) ; |
594
|
127
|
|
|
|
|
1366
|
for my $line ( @$output ) { |
595
|
3245
|
100
|
100
|
|
|
11383
|
if ( $result->{phase} eq 'test' |
596
|
|
|
|
|
|
|
&& $line =~ m{open3: IO::Pipe: Can't spawn.*?TAP/Parser/Iterator/Process.pm} |
597
|
|
|
|
|
|
|
) { |
598
|
2
|
|
|
|
|
10
|
$harness_error++; |
599
|
2
|
|
|
|
|
15
|
last; |
600
|
|
|
|
|
|
|
} |
601
|
3243
|
50
|
66
|
|
|
29373
|
if( $line =~ /(?
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
602
|
|
|
|
|
|
|
#?
|
603
|
|
|
|
|
|
|
$line =~ /Perl version .*? or higher required\. We run/ims || #EU::MM |
604
|
|
|
|
|
|
|
$line =~ /ERROR: perl: Version .*? is installed, but we need version/ims || |
605
|
|
|
|
|
|
|
$line =~ /ERROR: perl \(.*?\) is installed, but we need version/ims || |
606
|
|
|
|
|
|
|
$line =~ /Error evaling version line 'BEGIN/ims || |
607
|
|
|
|
|
|
|
$line =~ /Could not eval '/ims |
608
|
|
|
|
|
|
|
) { |
609
|
8
|
|
|
|
|
80
|
$version_error++; |
610
|
8
|
|
|
|
|
59
|
last; |
611
|
|
|
|
|
|
|
} |
612
|
3235
|
100
|
|
|
|
15160
|
if ( $line =~ /No support for OS|OS unsupported/ims ) { |
613
|
6
|
|
|
|
|
92
|
$unsupported++; |
614
|
6
|
|
|
|
|
57
|
last; |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
# if the test harness had an error, discard the report |
619
|
127
|
100
|
100
|
|
|
7586
|
if ( $harness_error ) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
620
|
2
|
|
|
|
|
18
|
$grade = 'discard'; |
621
|
2
|
|
|
|
|
29
|
$msg = 'Test harness failure'; |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
# check for explicit version error or just a perl version prerequisite |
624
|
|
|
|
|
|
|
elsif ( $version_error || $result->{prereq_pm} =~ m{^\s+!\s+perl\s}ims ) { |
625
|
12
|
|
|
|
|
195
|
$grade = 'na'; |
626
|
12
|
|
|
|
|
108
|
$msg = 'Perl version too low'; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
# check again for unsupported OS in case we took 'fail' from exit value |
629
|
|
|
|
|
|
|
elsif ( $unsupported ) { |
630
|
6
|
|
|
|
|
91
|
$grade = 'na'; |
631
|
6
|
|
|
|
|
58
|
$msg = 'This platform is not supported'; |
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
# check for Makefile without 'test' target; there are lots |
634
|
|
|
|
|
|
|
# of variations on the error message, e.g. "target test", "target 'test'", |
635
|
|
|
|
|
|
|
# "'test'", "`test'" and so on. |
636
|
|
|
|
|
|
|
elsif ( |
637
|
|
|
|
|
|
|
$result->{is_make} && $result->{phase} eq 'test' && ! _has_test_target() |
638
|
|
|
|
|
|
|
) { |
639
|
1
|
|
|
|
|
14
|
$grade = 'unknown'; |
640
|
1
|
|
|
|
|
11
|
$msg = 'No make test target'; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
# check the prereq report for missing or failure flag '!' |
643
|
|
|
|
|
|
|
elsif ( $grade ne 'pass' && $result->{prereq_pm} =~ m{n/a}ims ) { |
644
|
14
|
|
|
|
|
150
|
$grade = 'discard'; |
645
|
14
|
|
|
|
|
145
|
$msg = "Prerequisite missing:\n$result->{prereq_pm}"; |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
elsif ( $grade ne 'pass' && $result->{prereq_pm} =~ m{^\s+!}ims ) { |
648
|
8
|
|
|
|
|
160
|
$grade = 'discard'; |
649
|
8
|
|
|
|
|
114
|
$msg = "Prerequisite version too low:\n$result->{prereq_pm}"; |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
# in PL stage -- if pass but no Makefile or Build, then this should |
652
|
|
|
|
|
|
|
# be recorded as a discard |
653
|
|
|
|
|
|
|
elsif ( $result->{phase} eq 'PL' && $grade eq 'pass' |
654
|
|
|
|
|
|
|
&& ! -f 'Makefile' && ! -f 'Build' |
655
|
|
|
|
|
|
|
) { |
656
|
2
|
|
|
|
|
46
|
$grade = 'discard'; |
657
|
2
|
|
|
|
|
18
|
$msg = 'No Makefile or Build file found'; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
elsif ( $result->{command} =~ /Build.*?-j/ ) { |
660
|
2
|
|
|
|
|
20
|
$grade = 'discard'; |
661
|
2
|
|
|
|
|
18
|
$msg = '-j is not a valid option for Module::Build (upgrade your CPAN.pm)'; |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
elsif ( |
664
|
|
|
|
|
|
|
$result->{is_make} && $result->{phase} eq 'make' && |
665
|
45
|
|
|
|
|
277
|
grep { /Makefile out-of-date with respect to Makefile.PL/ } @$output |
666
|
|
|
|
|
|
|
) { |
667
|
1
|
|
|
|
|
11
|
$grade = 'discard'; |
668
|
1
|
|
|
|
|
10
|
$msg = 'Makefile out-of-date'; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
# store results |
672
|
127
|
|
|
|
|
2948
|
$result->{grade} = $grade; |
673
|
127
|
|
|
|
|
625
|
$result->{grade_msg} = $msg; |
674
|
|
|
|
|
|
|
|
675
|
127
|
|
|
|
|
643
|
return; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
679
|
|
|
|
|
|
|
# _expand_result - add expensive information like prerequisites and |
680
|
|
|
|
|
|
|
# toolchain that should only be generated if a report will actually |
681
|
|
|
|
|
|
|
# be sent |
682
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
sub _expand_result { |
685
|
354
|
|
|
354
|
|
1579
|
my $result = shift; |
686
|
354
|
100
|
|
|
|
3619
|
return if $result->{expanded}++; # only do this once |
687
|
167
|
|
|
|
|
2064
|
$result->{prereq_pm} = _prereq_report( $result->{dist} ); |
688
|
|
|
|
|
|
|
{ |
689
|
|
|
|
|
|
|
# mirror PERL5OPT as in record_command |
690
|
167
|
100
|
|
|
|
801
|
local $ENV{PERL5OPT} = _get_perl5opt() if _is_PL($result->{command}); |
|
167
|
|
|
|
|
2103
|
|
691
|
167
|
|
|
|
|
1352
|
$result->{env_vars} = _env_report(); |
692
|
|
|
|
|
|
|
} |
693
|
167
|
|
|
|
|
2012
|
$result->{special_vars} = _special_vars_report(); |
694
|
167
|
|
|
|
|
1356
|
$result->{toolchain_versions} = _toolchain_report( $result ); |
695
|
167
|
|
|
|
|
4147
|
$result->{perl_version} = CPAN::Reporter::History::_format_perl_version(); |
696
|
167
|
|
|
|
|
2037
|
return; |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
700
|
|
|
|
|
|
|
# _env_report |
701
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
# Entries bracketed with "/" are taken to be a regex; otherwise literal |
704
|
|
|
|
|
|
|
my @env_vars= qw( |
705
|
|
|
|
|
|
|
/HARNESS/ |
706
|
|
|
|
|
|
|
/LC_/ |
707
|
|
|
|
|
|
|
/PERL/ |
708
|
|
|
|
|
|
|
/_TEST/ |
709
|
|
|
|
|
|
|
CCFLAGS |
710
|
|
|
|
|
|
|
COMSPEC |
711
|
|
|
|
|
|
|
INCLUDE |
712
|
|
|
|
|
|
|
INSTALL_BASE |
713
|
|
|
|
|
|
|
LANG |
714
|
|
|
|
|
|
|
LANGUAGE |
715
|
|
|
|
|
|
|
LD_LIBRARY_PATH |
716
|
|
|
|
|
|
|
LDFLAGS |
717
|
|
|
|
|
|
|
LIB |
718
|
|
|
|
|
|
|
NON_INTERACTIVE |
719
|
|
|
|
|
|
|
NUMBER_OF_PROCESSORS |
720
|
|
|
|
|
|
|
PATH |
721
|
|
|
|
|
|
|
PREFIX |
722
|
|
|
|
|
|
|
PROCESSOR_IDENTIFIER |
723
|
|
|
|
|
|
|
SHELL |
724
|
|
|
|
|
|
|
TERM |
725
|
|
|
|
|
|
|
TEMP |
726
|
|
|
|
|
|
|
TMPDIR |
727
|
|
|
|
|
|
|
); |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
sub _env_report { |
730
|
176
|
|
|
176
|
|
27979
|
my @vars_found; |
731
|
176
|
|
|
|
|
2385
|
for my $var ( @env_vars ) { |
732
|
3872
|
100
|
|
|
|
16400
|
if ( $var =~ m{^/(.+)/$} ) { |
733
|
704
|
|
|
|
|
10395
|
push @vars_found, grep { /$1/ } keys %ENV; |
|
24772
|
|
|
|
|
81040
|
|
734
|
|
|
|
|
|
|
} |
735
|
|
|
|
|
|
|
else { |
736
|
3168
|
100
|
|
|
|
11164
|
push @vars_found, $var if exists $ENV{$var}; |
737
|
|
|
|
|
|
|
} |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
|
740
|
176
|
|
|
|
|
1136
|
my $report = ""; |
741
|
176
|
|
|
|
|
2096
|
for my $var ( sort @vars_found ) { |
742
|
2497
|
|
|
|
|
6117
|
my $value = $ENV{$var}; |
743
|
2497
|
50
|
|
|
|
5073
|
$value = '[undef]' if ! defined $value; |
744
|
2497
|
|
|
|
|
7304
|
$report .= " $var = $value\n"; |
745
|
|
|
|
|
|
|
} |
746
|
176
|
|
|
|
|
1649
|
return $report; |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
750
|
|
|
|
|
|
|
# _file_copy_quiet |
751
|
|
|
|
|
|
|
# |
752
|
|
|
|
|
|
|
# manual file copy -- quietly return undef on failure |
753
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
sub _file_copy_quiet { |
756
|
33
|
|
|
33
|
|
118
|
my ($source, $target) = @_; |
757
|
|
|
|
|
|
|
# ensure we have a target directory |
758
|
33
|
50
|
|
|
|
9913
|
mkpath( dirname($target) ) or return; |
759
|
|
|
|
|
|
|
# read source |
760
|
33
|
|
|
|
|
242
|
local *FH; |
761
|
33
|
50
|
|
|
|
1395
|
open FH, "<$source" or return; ## no critic |
762
|
33
|
|
|
|
|
120
|
my $pm_guts = do { local $/; }; |
|
33
|
|
|
|
|
223
|
|
|
33
|
|
|
|
|
1386
|
|
763
|
33
|
|
|
|
|
483
|
close FH; |
764
|
|
|
|
|
|
|
# write target |
765
|
33
|
50
|
|
|
|
2448
|
open FH, ">$target" or return; ## no critic |
766
|
33
|
|
|
|
|
351
|
print FH $pm_guts; |
767
|
33
|
|
|
|
|
1695
|
close FH; |
768
|
33
|
|
|
|
|
285
|
return 1; |
769
|
|
|
|
|
|
|
} |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
772
|
|
|
|
|
|
|
# _get_perl5opt |
773
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
sub _get_perl5opt { |
776
|
76
|
|
50
|
76
|
|
1077
|
my $perl5opt = $ENV{PERL5OPT} || q{}; |
777
|
76
|
50
|
|
|
|
379
|
if ( $Autoflush_Lib ) { |
778
|
76
|
50
|
|
|
|
306
|
$perl5opt .= q{ } if length $perl5opt; |
779
|
76
|
50
|
|
|
|
607
|
$perl5opt .= "-I$Autoflush_Lib " if $] >= 5.008; |
780
|
76
|
|
|
|
|
242
|
$perl5opt .= "-MDevel::Autoflush"; |
781
|
|
|
|
|
|
|
} |
782
|
76
|
|
|
|
|
1374
|
return $perl5opt; |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
786
|
|
|
|
|
|
|
# _has_recursive_make |
787
|
|
|
|
|
|
|
# |
788
|
|
|
|
|
|
|
# Ignore Makefile.PL in t directories |
789
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
sub _has_recursive_make { |
792
|
67
|
|
|
67
|
|
333
|
my $PL_count = 0; |
793
|
|
|
|
|
|
|
File::Find::find( |
794
|
|
|
|
|
|
|
sub { |
795
|
2373
|
100
|
|
2373
|
|
135121
|
if ( $_ eq 't' ) { |
|
|
100
|
|
|
|
|
|
796
|
63
|
|
|
|
|
708
|
$File::Find::prune = 1; |
797
|
|
|
|
|
|
|
} |
798
|
|
|
|
|
|
|
elsif ( $_ eq 'Makefile.PL' ) { |
799
|
73
|
|
|
|
|
596
|
$PL_count++; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
}, |
802
|
67
|
|
|
|
|
17322
|
File::Spec->curdir() |
803
|
|
|
|
|
|
|
); |
804
|
67
|
|
|
|
|
1028
|
return $PL_count > 1; |
805
|
|
|
|
|
|
|
} |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
808
|
|
|
|
|
|
|
# _has_test_target |
809
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
sub _has_test_target { |
812
|
47
|
50
|
|
47
|
|
1609
|
my $fh = IO::File->new("Makefile") or return; |
813
|
47
|
|
|
|
|
37527
|
return scalar grep { /^test[ ]*:/ } <$fh>; |
|
41836
|
|
|
|
|
74691
|
|
814
|
|
|
|
|
|
|
} |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
817
|
|
|
|
|
|
|
# _init_result -- create and return a hash of values for use in |
818
|
|
|
|
|
|
|
# report evaluation and dispatch |
819
|
|
|
|
|
|
|
# |
820
|
|
|
|
|
|
|
# takes same argument format as grade_*() |
821
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
sub _init_result { |
824
|
173
|
|
|
173
|
|
14139
|
my ($phase, $dist, $system_command, $output, $exit_value) = @_; |
825
|
|
|
|
|
|
|
|
826
|
173
|
50
|
33
|
|
|
3426
|
unless ( defined $output && defined $exit_value ) { |
827
|
0
|
|
|
|
|
0
|
my $missing; |
828
|
0
|
0
|
0
|
|
|
0
|
if ( ! defined $output && ! defined $exit_value ) { |
|
|
0
|
0
|
|
|
|
|
829
|
0
|
|
|
|
|
0
|
$missing = "exit value and output" |
830
|
|
|
|
|
|
|
} |
831
|
|
|
|
|
|
|
elsif ( defined $output && !defined $exit_value ) { |
832
|
0
|
|
|
|
|
0
|
$missing = "exit value" |
833
|
|
|
|
|
|
|
} |
834
|
|
|
|
|
|
|
else { |
835
|
0
|
|
|
|
|
0
|
$missing = "output"; |
836
|
|
|
|
|
|
|
} |
837
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( |
838
|
|
|
|
|
|
|
"CPAN::Reporter: had errors capturing $missing. Tests abandoned" |
839
|
|
|
|
|
|
|
); |
840
|
0
|
|
|
|
|
0
|
return; |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
|
843
|
173
|
100
|
|
|
|
4421
|
if ( $dist->pretty_id =~ m{\w+/Perl6/} ) { |
844
|
3
|
|
|
|
|
63
|
$CPAN::Frontend->mywarn( |
845
|
|
|
|
|
|
|
"CPAN::Reporter: Won't report a Perl6 distribution." |
846
|
|
|
|
|
|
|
); |
847
|
3
|
|
|
|
|
165
|
return; |
848
|
|
|
|
|
|
|
} |
849
|
|
|
|
|
|
|
|
850
|
170
|
100
|
|
|
|
5956
|
my $result = { |
851
|
|
|
|
|
|
|
phase => $phase, |
852
|
|
|
|
|
|
|
dist => $dist, |
853
|
|
|
|
|
|
|
command => $system_command, |
854
|
|
|
|
|
|
|
is_make => _is_make( $system_command ), |
855
|
|
|
|
|
|
|
output => ref $output eq 'ARRAY' ? $output : [ split /\n/, $output ], |
856
|
|
|
|
|
|
|
exit_value => $exit_value, |
857
|
|
|
|
|
|
|
# Note: pretty_id is like "DAGOLDEN/CPAN-Reporter-0.40.tar.gz" |
858
|
|
|
|
|
|
|
dist_basename => basename($dist->pretty_id), |
859
|
|
|
|
|
|
|
dist_name => $dist->base_id, |
860
|
|
|
|
|
|
|
}; |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
# Used in messages to user |
863
|
170
|
100
|
|
|
|
53296
|
$result->{PL_file} = $result->{is_make} ? "Makefile.PL" : "Build.PL"; |
864
|
170
|
100
|
|
|
|
8510
|
$result->{make_cmd} = $result->{is_make} ? $Config{make} : "Build"; |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
# CPAN might fail to find an author object for some strange dists |
867
|
170
|
|
|
|
|
2080
|
my $author = $dist->author; |
868
|
170
|
50
|
|
|
|
2396
|
$result->{author} = defined $author ? $author->fullname : "Author"; |
869
|
170
|
50
|
|
|
|
4258
|
$result->{author_id} = defined $author ? $author->id : "" ; |
870
|
|
|
|
|
|
|
|
871
|
170
|
|
|
|
|
3691
|
return $result; |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
875
|
|
|
|
|
|
|
# _is_make |
876
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
sub _is_make { |
879
|
190
|
|
|
190
|
|
14837
|
my $command = shift; |
880
|
190
|
100
|
|
|
|
5114
|
return $command =~ m{\b(?:\S*make|Makefile.PL)\b}ims ? 1 : 0; |
881
|
|
|
|
|
|
|
} |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
884
|
|
|
|
|
|
|
# _is_PL |
885
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
sub _is_PL { |
888
|
353
|
|
|
353
|
|
2112
|
my $command = shift; |
889
|
353
|
100
|
|
|
|
8154
|
return $command =~ m{\b(?:Makefile|Build)\.PL\b}ims ? 1 : 0; |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
893
|
|
|
|
|
|
|
# _max_length |
894
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
sub _max_length { |
897
|
352
|
|
|
352
|
|
3252
|
my ($first, @rest) = @_; |
898
|
352
|
|
|
|
|
1545
|
my $max = length $first; |
899
|
352
|
|
|
|
|
1776
|
for my $term ( @rest ) { |
900
|
7040
|
100
|
|
|
|
15428
|
$max = length $term if length $term > $max; |
901
|
|
|
|
|
|
|
} |
902
|
352
|
|
|
|
|
2666
|
return $max; |
903
|
|
|
|
|
|
|
} |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
907
|
|
|
|
|
|
|
# _parse_tap_harness |
908
|
|
|
|
|
|
|
# |
909
|
|
|
|
|
|
|
# As of Test::Harness 2.99_02, the final line is provided by TAP::Harness |
910
|
|
|
|
|
|
|
# as "Result: STATUS" where STATUS is "PASS", "FAIL" or "NOTESTS" |
911
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
912
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
sub _parse_tap_harness { |
915
|
294
|
|
|
294
|
|
1045
|
my ($line) = @_; |
916
|
294
|
100
|
|
|
|
3134
|
if ( $line =~ m{^Result:\s+([A-Z]+)} ) { |
|
|
100
|
|
|
|
|
|
917
|
74
|
100
|
|
|
|
971
|
if ( $1 eq 'PASS' ) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
918
|
20
|
|
|
|
|
181
|
return ('pass', 'All tests successful'); |
919
|
|
|
|
|
|
|
} |
920
|
|
|
|
|
|
|
elsif ( $1 eq 'FAIL' ) { |
921
|
51
|
|
|
|
|
636
|
return ('fail', 'One or more tests failed'); |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
elsif ( $1 eq 'NOTESTS' ) { |
924
|
3
|
|
|
|
|
64
|
return ('unknown', 'No tests were run'); |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
} |
927
|
|
|
|
|
|
|
elsif ( $line =~ m{Bailout called\.\s+Further testing stopped}ms ) { |
928
|
2
|
|
|
|
|
18
|
return ( 'fail', 'Bailed out of tests'); |
929
|
|
|
|
|
|
|
} |
930
|
218
|
|
|
|
|
757
|
return; |
931
|
|
|
|
|
|
|
} |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
934
|
|
|
|
|
|
|
# _parse_test_harness |
935
|
|
|
|
|
|
|
# |
936
|
|
|
|
|
|
|
# Output strings taken from Test::Harness:: |
937
|
|
|
|
|
|
|
# _show_results() -- for versions < 2.57_03 |
938
|
|
|
|
|
|
|
# get_results() -- for versions >= 2.57_03 |
939
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
sub _parse_test_harness { |
942
|
0
|
|
|
0
|
|
0
|
my ($line) = @_; |
943
|
0
|
0
|
|
|
|
0
|
if ( $line =~ m{^All tests successful}ms ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
944
|
0
|
|
|
|
|
0
|
return ( 'pass', 'All tests successful' ); |
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
elsif ( $line =~ m{^FAILED--no tests were run}ms ) { |
947
|
0
|
|
|
|
|
0
|
return ( 'unknown', 'No tests were run' ); |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
elsif ( $line =~ m{^FAILED--.*--no output}ms ) { |
950
|
0
|
|
|
|
|
0
|
return ( 'unknown', 'No tests were run'); |
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
elsif ( $line =~ m{FAILED--Further testing stopped}ms ) { |
953
|
0
|
|
|
|
|
0
|
return ( 'fail', 'Bailed out of tests'); |
954
|
|
|
|
|
|
|
} |
955
|
|
|
|
|
|
|
elsif ( $line =~ m{^Failed }ms ) { # must be lowercase |
956
|
0
|
|
|
|
|
0
|
return ( 'fail', 'One or more tests failed'); |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
else { |
959
|
0
|
|
|
|
|
0
|
return; |
960
|
|
|
|
|
|
|
} |
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
964
|
|
|
|
|
|
|
# _prereq_report |
965
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
my @prereq_sections = qw( |
968
|
|
|
|
|
|
|
requires build_requires configure_requires opt_requires opt_build_requires |
969
|
|
|
|
|
|
|
); |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
sub _prereq_report { |
972
|
179
|
|
|
179
|
|
166913
|
my $dist = shift; |
973
|
179
|
|
|
|
|
713
|
my (%need, %have, %prereq_met, $report); |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
# Extract requires/build_requires from CPAN dist |
976
|
179
|
|
|
|
|
1476
|
my $prereq_pm = $dist->prereq_pm; |
977
|
|
|
|
|
|
|
|
978
|
179
|
50
|
|
|
|
2992
|
if ( ref $prereq_pm eq 'HASH' ) { |
979
|
|
|
|
|
|
|
# CPAN 1.94 returns hash with requires/build_requires # so no need to support old style |
980
|
179
|
|
|
|
|
1748
|
foreach (values %$prereq_pm) { |
981
|
711
|
50
|
66
|
|
|
5215
|
if (defined && ref ne 'HASH') { |
982
|
0
|
|
|
|
|
0
|
require Data::Dumper; |
983
|
0
|
|
|
|
|
0
|
warn "Data error detecting prerequisites. Please report it to CPAN::Reporter bug tracker:"; |
984
|
0
|
|
|
|
|
0
|
warn Data::Dumper::Dumper($prereq_pm); |
985
|
0
|
|
|
|
|
0
|
die "Stopping"; |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
} |
988
|
|
|
|
|
|
|
|
989
|
179
|
|
|
|
|
2146
|
for my $sec ( @prereq_sections ) { |
990
|
895
|
100
|
|
|
|
1894
|
$need{$sec} = $prereq_pm->{$sec} if keys %{ $prereq_pm->{$sec} }; |
|
895
|
|
|
|
|
7537
|
|
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
} |
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
# Extract configure_requires from META.yml if it exists |
995
|
179
|
100
|
66
|
|
|
2789
|
if ( $dist->{build_dir} && -d $dist->{build_dir} ) { |
996
|
72
|
|
|
|
|
2563
|
my $meta_yml = File::Spec->catfile($dist->{build_dir}, 'META.yml'); |
997
|
72
|
100
|
|
|
|
1682
|
if ( -f $meta_yml ) { |
998
|
4
|
|
|
|
|
33
|
my @yaml = eval { Parse::CPAN::Meta::LoadFile($meta_yml) }; |
|
4
|
|
|
|
|
82
|
|
999
|
4
|
100
|
|
|
|
12750
|
if ( $@ ) { |
1000
|
2
|
|
|
|
|
100
|
$CPAN::Frontend->mywarn( |
1001
|
|
|
|
|
|
|
"CPAN::Reporter: error parsing META.yml\n" |
1002
|
|
|
|
|
|
|
); |
1003
|
|
|
|
|
|
|
} |
1004
|
4
|
100
|
66
|
|
|
124
|
if ( ref $yaml[0] eq 'HASH' && |
1005
|
|
|
|
|
|
|
ref $yaml[0]{configure_requires} eq 'HASH' |
1006
|
|
|
|
|
|
|
) { |
1007
|
2
|
|
|
|
|
29
|
$need{configure_requires} = $yaml[0]{configure_requires}; |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
} |
1010
|
|
|
|
|
|
|
} |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
# see what prereqs are satisfied in subprocess |
1013
|
179
|
|
|
|
|
980
|
for my $section ( @prereq_sections ) { |
1014
|
895
|
100
|
|
|
|
4650
|
next unless ref $need{$section} eq 'HASH'; |
1015
|
137
|
|
|
|
|
471
|
my @prereq_list = %{ $need{$section} }; |
|
137
|
|
|
|
|
1290
|
|
1016
|
137
|
50
|
|
|
|
868
|
next unless @prereq_list; |
1017
|
137
|
|
|
|
|
1633
|
my $prereq_results = _version_finder( @prereq_list ); |
1018
|
137
|
|
|
|
|
845
|
for my $mod ( keys %{$prereq_results} ) { |
|
137
|
|
|
|
|
1326
|
|
1019
|
185
|
|
|
|
|
2652
|
$have{$section}{$mod} = $prereq_results->{$mod}{have}; |
1020
|
185
|
|
|
|
|
3153
|
$prereq_met{$section}{$mod} = $prereq_results->{$mod}{met}; |
1021
|
|
|
|
|
|
|
} |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
# find formatting widths |
1025
|
179
|
|
|
|
|
1338
|
my ($name_width, $need_width, $have_width) = (6, 4, 4); |
1026
|
179
|
|
|
|
|
871
|
for my $section ( @prereq_sections ) { |
1027
|
895
|
|
|
|
|
1932
|
for my $module ( keys %{ $need{$section} } ) { |
|
895
|
|
|
|
|
6801
|
|
1028
|
185
|
|
|
|
|
753
|
my $name_length = length $module; |
1029
|
185
|
|
|
|
|
1141
|
my $need_length = length $need{$section}{$module}; |
1030
|
185
|
|
|
|
|
622
|
my $have_length = length $have{$section}{$module}; |
1031
|
185
|
100
|
|
|
|
825
|
$name_width = $name_length if $name_length > $name_width; |
1032
|
185
|
100
|
|
|
|
801
|
$need_width = $need_length if $need_length > $need_width; |
1033
|
185
|
100
|
|
|
|
961
|
$have_width = $have_length if $have_length > $have_width; |
1034
|
|
|
|
|
|
|
} |
1035
|
|
|
|
|
|
|
} |
1036
|
|
|
|
|
|
|
|
1037
|
179
|
|
|
|
|
2226
|
my $format_str = |
1038
|
|
|
|
|
|
|
" \%1s \%-${name_width}s \%-${need_width}s \%-${have_width}s\n"; |
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
# generate the report |
1041
|
179
|
|
|
|
|
1027
|
for my $section ( @prereq_sections ) { |
1042
|
895
|
100
|
|
|
|
1675
|
if ( keys %{ $need{$section} } ) { |
|
895
|
|
|
|
|
3197
|
|
1043
|
137
|
|
|
|
|
921
|
$report .= "$section:\n\n"; |
1044
|
137
|
|
|
|
|
1681
|
$report .= sprintf( $format_str, " ", qw/Module Need Have/ ); |
1045
|
137
|
|
|
|
|
1552
|
$report .= sprintf( $format_str, " ", |
1046
|
|
|
|
|
|
|
"-" x $name_width, |
1047
|
|
|
|
|
|
|
"-" x $need_width, |
1048
|
|
|
|
|
|
|
"-" x $have_width ); |
1049
|
137
|
|
|
|
|
590
|
for my $module (sort {lc $a cmp lc $b} keys %{ $need{$section} } ) { |
|
137
|
|
|
|
|
300
|
|
|
137
|
|
|
|
|
1099
|
|
1050
|
185
|
|
|
|
|
812
|
my $need = $need{$section}{$module}; |
1051
|
185
|
|
|
|
|
653
|
my $have = $have{$section}{$module}; |
1052
|
185
|
100
|
|
|
|
1377
|
my $bad = $prereq_met{$section}{$module} ? " " : "!"; |
1053
|
185
|
|
|
|
|
1364
|
$report .= |
1054
|
|
|
|
|
|
|
sprintf( $format_str, $bad, $module, $need, $have); |
1055
|
|
|
|
|
|
|
} |
1056
|
137
|
|
|
|
|
627
|
$report .= "\n"; |
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
} |
1059
|
|
|
|
|
|
|
|
1060
|
179
|
|
100
|
|
|
6042
|
return $report || " No requirements found\n"; |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1064
|
|
|
|
|
|
|
# _print_grade_msg - |
1065
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
sub _print_grade_msg { |
1068
|
138
|
|
|
138
|
|
1532
|
my ($phase, $result) = @_; |
1069
|
138
|
|
|
|
|
946
|
my ($grade, $msg) = ($result->{grade}, $result->{grade_msg}); |
1070
|
138
|
|
|
|
|
7079
|
$CPAN::Frontend->myprint( "CPAN::Reporter: $phase result is '$grade'"); |
1071
|
138
|
50
|
33
|
|
|
10865
|
$CPAN::Frontend->myprint(", $msg") if defined $msg && length $msg; |
1072
|
138
|
|
|
|
|
3268
|
$CPAN::Frontend->myprint(".\n"); |
1073
|
138
|
|
|
|
|
2297
|
return; |
1074
|
|
|
|
|
|
|
} |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1077
|
|
|
|
|
|
|
# _prompt |
1078
|
|
|
|
|
|
|
# |
1079
|
|
|
|
|
|
|
# Note: always returns lowercase |
1080
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
sub _prompt { |
1083
|
328
|
|
|
328
|
|
42210
|
my ($config, $option, $grade, $extra) = @_; |
1084
|
328
|
|
50
|
|
|
2884
|
$extra ||= q{}; |
1085
|
|
|
|
|
|
|
|
1086
|
328
|
|
|
|
|
1284
|
my %spec = CPAN::Reporter::Config::_config_spec(); |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
my $dispatch = CPAN::Reporter::Config::_validate_grade_action_pair( |
1089
|
328
|
|
50
|
|
|
2628
|
$option, join(q{ }, "default:no", $config->{$option} || '') |
1090
|
|
|
|
|
|
|
); |
1091
|
328
|
|
66
|
|
|
1996
|
my $action = $dispatch->{$grade} || $dispatch->{default}; |
1092
|
328
|
|
|
|
|
1695
|
my $intro = $spec{$option}{prompt} . $extra . " (yes/no)"; |
1093
|
328
|
|
|
|
|
669
|
my $prompt; |
1094
|
328
|
100
|
|
|
|
2388
|
if ( $action =~ m{^ask/yes}i ) { |
|
|
100
|
|
|
|
|
|
1095
|
10
|
|
|
|
|
47
|
$prompt = CPAN::Shell::colorable_makemaker_prompt( $intro, "yes" ); |
1096
|
|
|
|
|
|
|
} |
1097
|
|
|
|
|
|
|
elsif ( $action =~ m{^ask(/no)?}i ) { |
1098
|
72
|
|
|
|
|
726
|
$prompt = CPAN::Shell::colorable_makemaker_prompt( $intro, "no" ); |
1099
|
|
|
|
|
|
|
} |
1100
|
|
|
|
|
|
|
else { |
1101
|
246
|
|
|
|
|
644
|
$prompt = $action; |
1102
|
|
|
|
|
|
|
} |
1103
|
328
|
|
|
|
|
14124
|
return lc $prompt; |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1107
|
|
|
|
|
|
|
# _report_text |
1108
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
my %intro_para = ( |
1111
|
|
|
|
|
|
|
'pass' => <<'HERE', |
1112
|
|
|
|
|
|
|
Thank you for uploading your work to CPAN. Congratulations! |
1113
|
|
|
|
|
|
|
All tests were successful. |
1114
|
|
|
|
|
|
|
HERE |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
'fail' => <<'HERE', |
1117
|
|
|
|
|
|
|
Thank you for uploading your work to CPAN. However, there was a problem |
1118
|
|
|
|
|
|
|
testing your distribution. |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
If you think this report is invalid, please consult the CPAN Testers Wiki |
1121
|
|
|
|
|
|
|
for suggestions on how to avoid getting FAIL reports for missing library |
1122
|
|
|
|
|
|
|
or binary dependencies, unsupported operating systems, and so on: |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
http://wiki.cpantesters.org/wiki/CPANAuthorNotes |
1125
|
|
|
|
|
|
|
HERE |
1126
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
'unknown' => <<'HERE', |
1128
|
|
|
|
|
|
|
Thank you for uploading your work to CPAN. However, attempting to |
1129
|
|
|
|
|
|
|
test your distribution gave an inconclusive result. |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
This could be because your distribution had an error during the make/build |
1132
|
|
|
|
|
|
|
stage, did not define tests, tests could not be found, because your tests were |
1133
|
|
|
|
|
|
|
interrupted before they finished, or because the results of the tests could not |
1134
|
|
|
|
|
|
|
be parsed. You may wish to consult the CPAN Testers Wiki: |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
http://wiki.cpantesters.org/wiki/CPANAuthorNotes |
1137
|
|
|
|
|
|
|
HERE |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
'na' => <<'HERE', |
1140
|
|
|
|
|
|
|
Thank you for uploading your work to CPAN. While attempting to build or test |
1141
|
|
|
|
|
|
|
this distribution, the distribution signaled that support is not available |
1142
|
|
|
|
|
|
|
either for this operating system or this version of Perl. Nevertheless, any |
1143
|
|
|
|
|
|
|
diagnostic output produced is provided below for reference. If this is not |
1144
|
|
|
|
|
|
|
what you expect, you may wish to consult the CPAN Testers Wiki: |
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
http://wiki.cpantesters.org/wiki/CPANAuthorNotes |
1147
|
|
|
|
|
|
|
HERE |
1148
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
); |
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
sub _comment_text { |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
# We assemble the completed comment as a series of "parts" which |
1154
|
|
|
|
|
|
|
# will get joined together |
1155
|
117
|
|
|
117
|
|
252
|
my @comment_parts; |
1156
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
# All automated testing gets a preamble |
1158
|
117
|
100
|
|
|
|
635
|
if ($ENV{AUTOMATED_TESTING}) { |
1159
|
111
|
|
|
|
|
428
|
push @comment_parts, |
1160
|
|
|
|
|
|
|
"this report is from an automated smoke testing program\n" |
1161
|
|
|
|
|
|
|
. "and was not reviewed by a human for accuracy" |
1162
|
|
|
|
|
|
|
} |
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
# If a comment file is provided, read it and add it to the comment |
1165
|
117
|
|
|
|
|
477
|
my $confdir = CPAN::Reporter::Config::_get_config_dir(); |
1166
|
117
|
|
|
|
|
1380
|
my $comment_file = File::Spec->catfile($confdir, 'comment.txt'); |
1167
|
117
|
100
|
66
|
|
|
4331
|
if ( -d $confdir && -f $comment_file && -r $comment_file ) { |
|
|
|
66
|
|
|
|
|
1168
|
2
|
50
|
|
1
|
|
180
|
open my $fh, '<:encoding(UTF-8)', $comment_file or die($!); |
|
1
|
|
|
|
|
9
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
35
|
|
1169
|
2
|
|
|
|
|
2207
|
my $text; |
1170
|
2
|
|
|
|
|
9
|
do { |
1171
|
2
|
|
|
|
|
15
|
local $/ = undef; # No record (line) seperator on input |
1172
|
2
|
50
|
|
|
|
84
|
defined( $text = <$fh> ) or die($!); |
1173
|
|
|
|
|
|
|
}; |
1174
|
2
|
|
|
|
|
71
|
chomp($text); |
1175
|
2
|
|
|
|
|
10
|
push @comment_parts, $text; |
1176
|
2
|
|
|
|
|
34
|
close $fh; |
1177
|
|
|
|
|
|
|
} |
1178
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
# If we have an empty comment so far, add a default value |
1180
|
117
|
100
|
|
|
|
744
|
if (scalar(@comment_parts) == 0) { |
1181
|
5
|
|
|
|
|
52
|
push @comment_parts, 'none provided'; |
1182
|
|
|
|
|
|
|
} |
1183
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
# Join the parts seperated by a blank line |
1185
|
117
|
|
|
|
|
814
|
return join "\n\n", @comment_parts; |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
sub _report_text { |
1189
|
117
|
|
|
117
|
|
403
|
my $data = shift; |
1190
|
117
|
|
|
|
|
283
|
my $test_log = join(q{},@{$data->{output}}); |
|
117
|
|
|
|
|
1213
|
|
1191
|
117
|
50
|
|
|
|
670
|
if ( length $test_log > MAX_OUTPUT_LENGTH ) { |
1192
|
0
|
|
|
|
|
0
|
my $max_k = int(MAX_OUTPUT_LENGTH/1000) . "K"; |
1193
|
0
|
|
|
|
|
0
|
$test_log = substr( $test_log, 0, MAX_OUTPUT_LENGTH/2 ) . "\n\n" |
1194
|
|
|
|
|
|
|
. "[Output truncated because it exceeded $max_k]\n\n" |
1195
|
|
|
|
|
|
|
. substr( $test_log, -(MAX_OUTPUT_LENGTH/2) ); |
1196
|
|
|
|
|
|
|
} |
1197
|
|
|
|
|
|
|
|
1198
|
117
|
|
|
|
|
551
|
my $comment_body = _comment_text(); |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
# generate report |
1201
|
117
|
|
|
|
|
3236
|
my $output = << "ENDREPORT"; |
1202
|
|
|
|
|
|
|
Dear $data->{author}, |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
This is a computer-generated report for $data->{dist_name} |
1205
|
|
|
|
|
|
|
on perl $data->{perl_version}, created by CPAN-Reporter-$CPAN::Reporter::VERSION\. |
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
$intro_para{ $data->{grade} } |
1208
|
|
|
|
|
|
|
Sections of this report: |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
* Tester comments |
1211
|
|
|
|
|
|
|
* Program output |
1212
|
|
|
|
|
|
|
* Prerequisites |
1213
|
|
|
|
|
|
|
* Environment and other context |
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
------------------------------ |
1216
|
|
|
|
|
|
|
TESTER COMMENTS |
1217
|
|
|
|
|
|
|
------------------------------ |
1218
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
Additional comments from tester: |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
$comment_body |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
------------------------------ |
1224
|
|
|
|
|
|
|
PROGRAM OUTPUT |
1225
|
|
|
|
|
|
|
------------------------------ |
1226
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
Output from '$data->{command}': |
1228
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
$test_log |
1230
|
|
|
|
|
|
|
------------------------------ |
1231
|
|
|
|
|
|
|
PREREQUISITES |
1232
|
|
|
|
|
|
|
------------------------------ |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
Prerequisite modules loaded: |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
$data->{prereq_pm} |
1237
|
|
|
|
|
|
|
------------------------------ |
1238
|
|
|
|
|
|
|
ENVIRONMENT AND OTHER CONTEXT |
1239
|
|
|
|
|
|
|
------------------------------ |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
Environment variables: |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
$data->{env_vars} |
1244
|
|
|
|
|
|
|
Perl special variables (and OS-specific diagnostics, for MSWin32): |
1245
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
$data->{special_vars} |
1247
|
|
|
|
|
|
|
Perl module toolchain versions installed: |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
$data->{toolchain_versions} |
1250
|
|
|
|
|
|
|
ENDREPORT |
1251
|
|
|
|
|
|
|
|
1252
|
117
|
|
|
|
|
1009
|
return $output; |
1253
|
|
|
|
|
|
|
} |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1256
|
|
|
|
|
|
|
# _special_vars_report |
1257
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1258
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
sub _special_vars_report { |
1260
|
176
|
|
|
176
|
|
16633
|
my $special_vars = << "HERE"; |
1261
|
|
|
|
|
|
|
\$^X = $^X |
1262
|
|
|
|
|
|
|
\$UID/\$EUID = $< / $> |
1263
|
|
|
|
|
|
|
\$GID = $( |
1264
|
|
|
|
|
|
|
\$EGID = $) |
1265
|
|
|
|
|
|
|
HERE |
1266
|
176
|
50
|
33
|
|
|
1623
|
if ( $^O eq 'MSWin32' && eval "require Win32" ) { ## no critic |
1267
|
0
|
|
|
|
|
0
|
my @getosversion = Win32::GetOSVersion(); |
1268
|
0
|
|
|
|
|
0
|
my $getosversion = join(", ", @getosversion); |
1269
|
0
|
|
|
|
|
0
|
$special_vars .= " Win32::GetOSName = " . Win32::GetOSName() . "\n"; |
1270
|
0
|
|
|
|
|
0
|
$special_vars .= " Win32::GetOSVersion = $getosversion\n"; |
1271
|
0
|
|
|
|
|
0
|
$special_vars .= " Win32::FsType = " . Win32::FsType() . "\n"; |
1272
|
0
|
|
|
|
|
0
|
$special_vars .= " Win32::IsAdminUser = " . Win32::IsAdminUser() . "\n"; |
1273
|
|
|
|
|
|
|
} |
1274
|
176
|
|
|
|
|
1304
|
return $special_vars; |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1278
|
|
|
|
|
|
|
# _split_redirect |
1279
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1280
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
sub _split_redirect { |
1282
|
186
|
|
|
186
|
|
792
|
my $command = shift; |
1283
|
186
|
|
|
|
|
1608
|
my ($cmd, $prefix) = ($command =~ m{\A(.+?)(\|.*)\z}); |
1284
|
186
|
100
|
|
|
|
854
|
if (defined $cmd) { |
1285
|
1
|
|
|
|
|
19
|
return ($cmd, $prefix); |
1286
|
|
|
|
|
|
|
} |
1287
|
|
|
|
|
|
|
else { # didn't match a redirection |
1288
|
185
|
|
|
|
|
803
|
return $command |
1289
|
|
|
|
|
|
|
} |
1290
|
|
|
|
|
|
|
} |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1293
|
|
|
|
|
|
|
# _temp_filename -- stand-in for File::Temp for backwards compatibility |
1294
|
|
|
|
|
|
|
# |
1295
|
|
|
|
|
|
|
# takes an optional prefix, adds 8 random chars and returns |
1296
|
|
|
|
|
|
|
# an absolute pathname |
1297
|
|
|
|
|
|
|
# |
1298
|
|
|
|
|
|
|
# NOTE -- manual unlink required |
1299
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
# @CHARS from File::Temp |
1302
|
|
|
|
|
|
|
my @CHARS = (qw/ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z |
1303
|
|
|
|
|
|
|
a b c d e f g h i j k l m n o p q r s t u v w x y z |
1304
|
|
|
|
|
|
|
0 1 2 3 4 5 6 7 8 9 _ |
1305
|
|
|
|
|
|
|
/); |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
sub _temp_filename { |
1308
|
500
|
|
|
500
|
|
3485
|
my ($prefix) = @_; |
1309
|
500
|
50
|
|
|
|
2315
|
$prefix = q{} unless defined $prefix; |
1310
|
500
|
|
|
|
|
10470
|
$prefix .= $CHARS[ int( rand(@CHARS) ) ] for 0 .. 7; |
1311
|
500
|
|
|
|
|
27556
|
return File::Spec->catfile(File::Spec->tmpdir(), $prefix); |
1312
|
|
|
|
|
|
|
} |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1315
|
|
|
|
|
|
|
# _timeout_wrapper |
1316
|
|
|
|
|
|
|
# Timeout technique adapted from App::cpanminus (thank you Miyagawa!) |
1317
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1318
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
sub _timeout_wrapper { |
1320
|
15
|
|
|
15
|
|
88
|
my ($cmd, $timeout) = @_; |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
# protect shell quotes |
1323
|
15
|
|
|
|
|
68
|
$cmd = quotemeta($cmd); |
1324
|
|
|
|
|
|
|
|
1325
|
15
|
|
|
|
|
154
|
my $wrapper = sprintf << 'HERE', $timeout, $cmd, $cmd; |
1326
|
|
|
|
|
|
|
use strict; |
1327
|
|
|
|
|
|
|
my ($pid, $exitcode); |
1328
|
|
|
|
|
|
|
eval { |
1329
|
|
|
|
|
|
|
$pid = fork; |
1330
|
|
|
|
|
|
|
if ($pid) { |
1331
|
|
|
|
|
|
|
local $SIG{CHLD}; |
1332
|
|
|
|
|
|
|
local $SIG{ALRM} = sub {die 'Timeout'}; |
1333
|
|
|
|
|
|
|
alarm %s; |
1334
|
|
|
|
|
|
|
my $wstat = waitpid $pid, 0; |
1335
|
|
|
|
|
|
|
alarm 0; |
1336
|
|
|
|
|
|
|
$exitcode = $wstat == -1 ? -1 : $?; |
1337
|
|
|
|
|
|
|
} elsif ( $pid == 0 ) { |
1338
|
|
|
|
|
|
|
setpgrp(0,0); # new process group |
1339
|
|
|
|
|
|
|
exec "%s"; |
1340
|
|
|
|
|
|
|
} |
1341
|
|
|
|
|
|
|
else { |
1342
|
|
|
|
|
|
|
die "Cannot fork: $!\n" unless defined $pid; |
1343
|
|
|
|
|
|
|
} |
1344
|
|
|
|
|
|
|
}; |
1345
|
|
|
|
|
|
|
if ($pid && $@ =~ /Timeout/){ |
1346
|
|
|
|
|
|
|
kill -9 => $pid; # and send to our child's whole process group |
1347
|
|
|
|
|
|
|
waitpid $pid, 0; |
1348
|
|
|
|
|
|
|
$exitcode = 9; # force result to look like SIGKILL |
1349
|
|
|
|
|
|
|
} |
1350
|
|
|
|
|
|
|
elsif ($@) { |
1351
|
|
|
|
|
|
|
die $@; |
1352
|
|
|
|
|
|
|
} |
1353
|
|
|
|
|
|
|
print "(%s exited with $exitcode)\n"; |
1354
|
|
|
|
|
|
|
HERE |
1355
|
15
|
|
|
|
|
75
|
return $wrapper; |
1356
|
|
|
|
|
|
|
} |
1357
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1359
|
|
|
|
|
|
|
# _timeout_wrapper_win32 |
1360
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
sub _timeout_wrapper_win32 { |
1363
|
0
|
|
|
0
|
|
0
|
my ($cmd, $timeout) = @_; |
1364
|
|
|
|
|
|
|
|
1365
|
0
|
|
0
|
|
|
0
|
$timeout ||= 0; # just in case upstream doesn't guarantee it |
1366
|
|
|
|
|
|
|
|
1367
|
0
|
|
|
|
|
0
|
eval "use Win32::Job ();"; |
1368
|
0
|
0
|
|
|
|
0
|
if ($@) { |
1369
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( << 'HERE' ); |
1370
|
|
|
|
|
|
|
CPAN::Reporter: you need Win32::Job for inactivity_timeout support. |
1371
|
|
|
|
|
|
|
Continuing without timeout... |
1372
|
|
|
|
|
|
|
HERE |
1373
|
0
|
|
|
|
|
0
|
return; |
1374
|
|
|
|
|
|
|
} |
1375
|
|
|
|
|
|
|
|
1376
|
0
|
|
|
|
|
0
|
my ($program) = split " ", $cmd; |
1377
|
0
|
0
|
|
|
|
0
|
if (! File::Spec->file_name_is_absolute( $program ) ) { |
1378
|
0
|
|
|
|
|
0
|
my $exe = $program . ".exe"; |
1379
|
0
|
|
|
|
|
0
|
my ($path) = grep { -e File::Spec->catfile($_,$exe) } |
1380
|
0
|
|
|
|
|
0
|
split /$Config{path_sep}/, $ENV{PATH}; |
1381
|
0
|
0
|
|
|
|
0
|
if (! $path) { |
1382
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( << "HERE" ); |
1383
|
|
|
|
|
|
|
CPAN::Reporter: can't locate $exe in the PATH. |
1384
|
|
|
|
|
|
|
Continuing without timeout... |
1385
|
|
|
|
|
|
|
HERE |
1386
|
0
|
|
|
|
|
0
|
return; |
1387
|
|
|
|
|
|
|
} |
1388
|
0
|
|
|
|
|
0
|
$program = File::Spec->catfile($path,$exe); |
1389
|
|
|
|
|
|
|
} |
1390
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
# protect shell quotes and other things |
1392
|
0
|
|
|
|
|
0
|
$_ = quotemeta($_) for ($program, $cmd); |
1393
|
|
|
|
|
|
|
|
1394
|
0
|
|
|
|
|
0
|
my $wrapper = sprintf << 'HERE', $program, $cmd, $timeout; |
1395
|
|
|
|
|
|
|
use strict; |
1396
|
|
|
|
|
|
|
use Win32::Job; |
1397
|
|
|
|
|
|
|
my $executable = "%s"; |
1398
|
|
|
|
|
|
|
my $cmd_line = "%s"; |
1399
|
|
|
|
|
|
|
my $timeout = %s; |
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
my $job = Win32::Job->new() or die $^E; |
1402
|
|
|
|
|
|
|
my $ppid = $job->spawn($executable, $cmd_line); |
1403
|
|
|
|
|
|
|
$job->run($timeout); |
1404
|
|
|
|
|
|
|
my $status = $job->status; |
1405
|
|
|
|
|
|
|
my $exitcode = $status->{$ppid}{exitcode}; |
1406
|
|
|
|
|
|
|
if ( $exitcode == 293 ) { |
1407
|
|
|
|
|
|
|
$exitcode = 9; # map Win32::Job kill (293) to SIGKILL (9) |
1408
|
|
|
|
|
|
|
} |
1409
|
|
|
|
|
|
|
elsif ( $exitcode & 255 ) { |
1410
|
|
|
|
|
|
|
$exitcode = $exitcode << 8; # how perl expects it |
1411
|
|
|
|
|
|
|
} |
1412
|
|
|
|
|
|
|
print "($cmd_line exited with $exitcode)\n"; |
1413
|
|
|
|
|
|
|
HERE |
1414
|
0
|
|
|
|
|
0
|
return $wrapper; |
1415
|
|
|
|
|
|
|
} |
1416
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
#--------------------------------------------------------------------------#- |
1418
|
|
|
|
|
|
|
# _toolchain_report |
1419
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
my @toolchain_mods= qw( |
1422
|
|
|
|
|
|
|
CPAN |
1423
|
|
|
|
|
|
|
CPAN::Meta |
1424
|
|
|
|
|
|
|
Cwd |
1425
|
|
|
|
|
|
|
ExtUtils::CBuilder |
1426
|
|
|
|
|
|
|
ExtUtils::Command |
1427
|
|
|
|
|
|
|
ExtUtils::Install |
1428
|
|
|
|
|
|
|
ExtUtils::MakeMaker |
1429
|
|
|
|
|
|
|
ExtUtils::Manifest |
1430
|
|
|
|
|
|
|
ExtUtils::ParseXS |
1431
|
|
|
|
|
|
|
File::Spec |
1432
|
|
|
|
|
|
|
JSON |
1433
|
|
|
|
|
|
|
JSON::PP |
1434
|
|
|
|
|
|
|
Module::Build |
1435
|
|
|
|
|
|
|
Module::Signature |
1436
|
|
|
|
|
|
|
Parse::CPAN::Meta |
1437
|
|
|
|
|
|
|
Test::Harness |
1438
|
|
|
|
|
|
|
Test::More |
1439
|
|
|
|
|
|
|
Test2 |
1440
|
|
|
|
|
|
|
YAML |
1441
|
|
|
|
|
|
|
YAML::Syck |
1442
|
|
|
|
|
|
|
version |
1443
|
|
|
|
|
|
|
); |
1444
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
sub _toolchain_report { |
1446
|
176
|
|
|
176
|
|
3414
|
my ($result) = @_; |
1447
|
|
|
|
|
|
|
|
1448
|
176
|
|
|
|
|
983
|
my $installed = _version_finder( map { $_ => 0 } @toolchain_mods ); |
|
3696
|
|
|
|
|
12075
|
|
1449
|
176
|
|
|
|
|
7577
|
$result->{toolchain} = $installed; |
1450
|
|
|
|
|
|
|
|
1451
|
176
|
|
|
|
|
4838
|
my $mod_width = _max_length( keys %$installed ); |
1452
|
|
|
|
|
|
|
my $ver_width = _max_length( |
1453
|
176
|
|
|
|
|
1694
|
map { $installed->{$_}{have} } keys %$installed |
|
3696
|
|
|
|
|
8082
|
|
1454
|
|
|
|
|
|
|
); |
1455
|
|
|
|
|
|
|
|
1456
|
176
|
|
|
|
|
2498
|
my $format = " \%-${mod_width}s \%-${ver_width}s\n"; |
1457
|
|
|
|
|
|
|
|
1458
|
176
|
|
|
|
|
1098
|
my $report = ""; |
1459
|
176
|
|
|
|
|
1967
|
$report .= sprintf( $format, "Module", "Have" ); |
1460
|
176
|
|
|
|
|
2031
|
$report .= sprintf( $format, "-" x $mod_width, "-" x $ver_width ); |
1461
|
|
|
|
|
|
|
|
1462
|
176
|
|
|
|
|
3989
|
for my $var ( sort keys %$installed ) { |
1463
|
|
|
|
|
|
|
$report .= sprintf(" \%-${mod_width}s \%-${ver_width}s\n", |
1464
|
3696
|
|
|
|
|
12732
|
$var, $installed->{$var}{have} ); |
1465
|
|
|
|
|
|
|
} |
1466
|
|
|
|
|
|
|
|
1467
|
176
|
|
|
|
|
4012
|
return $report; |
1468
|
|
|
|
|
|
|
} |
1469
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1472
|
|
|
|
|
|
|
# _validate_metabase_args |
1473
|
|
|
|
|
|
|
# |
1474
|
|
|
|
|
|
|
# This is a kludge to make metabase transport args a little less |
1475
|
|
|
|
|
|
|
# clunky for novice users |
1476
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
sub _validate_metabase_args { |
1479
|
116
|
|
|
116
|
|
1013
|
my @transport_args = @_; |
1480
|
116
|
|
|
|
|
298
|
shift @transport_args; # drop leading 'Metabase' |
1481
|
116
|
|
|
|
|
319
|
my (%args, $error); |
1482
|
|
|
|
|
|
|
|
1483
|
116
|
50
|
|
|
|
694
|
if ( @transport_args % 2 != 0 ) { |
1484
|
0
|
|
|
|
|
0
|
$error = << "TRANSPORT_ARGS"; |
1485
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
CPAN::Reporter: Metabase 'transport' option had odd number of |
1487
|
|
|
|
|
|
|
parameters in the config file. See documentation for proper |
1488
|
|
|
|
|
|
|
configuration format. |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
TRANSPORT_ARGS |
1491
|
|
|
|
|
|
|
} |
1492
|
|
|
|
|
|
|
else { |
1493
|
116
|
|
|
|
|
1272
|
%args = @transport_args; |
1494
|
|
|
|
|
|
|
|
1495
|
116
|
|
|
|
|
830
|
for my $key ( qw/uri id_file/ ) { |
1496
|
232
|
50
|
|
|
|
1042
|
if ( ! $args{$key} ) { |
1497
|
0
|
|
|
|
|
0
|
$error = << "TRANSPORT_ARGS"; |
1498
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
CPAN::Reporter: Metabase 'transport' option did not have |
1500
|
|
|
|
|
|
|
a '$key' parameter in the config file. See documentation for |
1501
|
|
|
|
|
|
|
proper configuration format. |
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
TRANSPORT_ARGS |
1504
|
|
|
|
|
|
|
} |
1505
|
|
|
|
|
|
|
} |
1506
|
|
|
|
|
|
|
} |
1507
|
|
|
|
|
|
|
|
1508
|
116
|
50
|
|
|
|
460
|
if ( $error ) { |
1509
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( $error ); |
1510
|
0
|
|
|
|
|
0
|
return; |
1511
|
|
|
|
|
|
|
} |
1512
|
|
|
|
|
|
|
|
1513
|
116
|
|
|
|
|
635
|
$args{id_file} = CPAN::Reporter::Config::_normalize_id_file( $args{id_file} ); |
1514
|
|
|
|
|
|
|
|
1515
|
116
|
50
|
|
|
|
2736
|
if ( ! -r $args{id_file} ) { |
1516
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( <<"TRANSPORT_ARGS" ); |
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
CPAN::Reporter: Could not find Metabase transport 'id_file' parameter |
1519
|
|
|
|
|
|
|
located at '$args{id_file}'. |
1520
|
|
|
|
|
|
|
See documentation for proper configuration of the 'transport' setting. |
1521
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
TRANSPORT_ARGS |
1523
|
0
|
|
|
|
|
0
|
return; |
1524
|
|
|
|
|
|
|
} |
1525
|
|
|
|
|
|
|
|
1526
|
116
|
|
|
|
|
1311
|
return ('Metabase', %args); |
1527
|
|
|
|
|
|
|
} |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1531
|
|
|
|
|
|
|
# _version_finder |
1532
|
|
|
|
|
|
|
# |
1533
|
|
|
|
|
|
|
# module => version pairs |
1534
|
|
|
|
|
|
|
# |
1535
|
|
|
|
|
|
|
# This is done via an external program to show installed versions exactly |
1536
|
|
|
|
|
|
|
# the way they would be found when test programs are run. This means that |
1537
|
|
|
|
|
|
|
# any updates to PERL5LIB will be reflected in the results. |
1538
|
|
|
|
|
|
|
# |
1539
|
|
|
|
|
|
|
# File-finding logic taken from CPAN::Module::inst_file(). Logic to |
1540
|
|
|
|
|
|
|
# handle newer Module::Build prereq syntax is taken from |
1541
|
|
|
|
|
|
|
# CPAN::Distribution::unsat_prereq() |
1542
|
|
|
|
|
|
|
# |
1543
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
my $version_finder = $INC{'CPAN/Reporter/PrereqCheck.pm'}; |
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
sub _version_finder { |
1548
|
314
|
|
|
314
|
|
17353
|
my %prereqs = @_; |
1549
|
|
|
|
|
|
|
|
1550
|
314
|
|
|
|
|
12963
|
my $perl = Probe::Perl->find_perl_interpreter(); |
1551
|
314
|
|
|
|
|
18254
|
my @prereq_results; |
1552
|
|
|
|
|
|
|
|
1553
|
314
|
|
|
|
|
3295
|
my $prereq_input = _temp_filename( 'CPAN-Reporter-PI-' ); |
1554
|
314
|
50
|
|
|
|
10805
|
my $fh = IO::File->new( $prereq_input, "w" ) |
1555
|
|
|
|
|
|
|
or die "Could not create temporary '$prereq_input' for prereq analysis: $!"; |
1556
|
314
|
|
|
|
|
124711
|
$fh->print( map { "$_ $prereqs{$_}\n" } keys %prereqs ); |
|
3895
|
|
|
|
|
17063
|
|
1557
|
314
|
|
|
|
|
9330
|
$fh->close; |
1558
|
|
|
|
|
|
|
|
1559
|
314
|
|
|
314
|
|
54704
|
my $prereq_result = capture { system( $perl, $version_finder, '<', $prereq_input ) }; |
|
314
|
|
|
|
|
123483425
|
|
1560
|
|
|
|
|
|
|
|
1561
|
314
|
|
|
|
|
672624
|
unlink $prereq_input; |
1562
|
|
|
|
|
|
|
|
1563
|
314
|
|
|
|
|
2699
|
my %result; |
1564
|
314
|
|
|
|
|
5465
|
for my $line ( split "\n", $prereq_result ) { |
1565
|
3895
|
50
|
|
|
|
12377
|
next unless length $line; |
1566
|
3895
|
|
|
|
|
17515
|
my ($mod, $met, $have) = split " ", $line; |
1567
|
3895
|
50
|
33
|
|
|
26181
|
unless ( defined($mod) && defined($met) && defined($have) ) { |
|
|
|
33
|
|
|
|
|
1568
|
0
|
|
|
|
|
0
|
$CPAN::Frontend->mywarn( |
1569
|
|
|
|
|
|
|
"Error parsing output from CPAN::Reporter::PrereqCheck:\n" . |
1570
|
|
|
|
|
|
|
$line |
1571
|
|
|
|
|
|
|
); |
1572
|
0
|
|
|
|
|
0
|
next; |
1573
|
|
|
|
|
|
|
} |
1574
|
3895
|
|
|
|
|
40142
|
$result{$mod}{have} = $have; |
1575
|
3895
|
|
|
|
|
15135
|
$result{$mod}{met} = $met; |
1576
|
|
|
|
|
|
|
} |
1577
|
314
|
|
|
|
|
13677
|
return \%result; |
1578
|
|
|
|
|
|
|
} |
1579
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
1; |
1581
|
|
|
|
|
|
|
|
1582
|
|
|
|
|
|
|
# ABSTRACT: Adds CPAN Testers reporting to CPAN.pm |
1583
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
=pod |
1585
|
|
|
|
|
|
|
|
1586
|
|
|
|
|
|
|
=encoding UTF-8 |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
=head1 NAME |
1589
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
CPAN::Reporter - Adds CPAN Testers reporting to CPAN.pm |
1591
|
|
|
|
|
|
|
|
1592
|
|
|
|
|
|
|
=head1 VERSION |
1593
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
version 1.2019 |
1595
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1597
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
From the CPAN shell: |
1599
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
cpan> install Task::CPAN::Reporter |
1601
|
|
|
|
|
|
|
cpan> reload cpan |
1602
|
|
|
|
|
|
|
cpan> o conf init test_report |
1603
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
Installing L will pull in additional dependencies |
1605
|
|
|
|
|
|
|
that new CPAN Testers will need. |
1606
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
Advanced CPAN Testers with custom L setups |
1608
|
|
|
|
|
|
|
may wish to install only CPAN::Reporter, which has fewer dependencies. |
1609
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1611
|
|
|
|
|
|
|
|
1612
|
|
|
|
|
|
|
The CPAN Testers project captures and analyzes detailed results from building |
1613
|
|
|
|
|
|
|
and testing CPAN distributions on multiple operating systems and multiple |
1614
|
|
|
|
|
|
|
versions of Perl. This provides valuable feedback to module authors and |
1615
|
|
|
|
|
|
|
potential users to identify bugs or platform compatibility issues and improves |
1616
|
|
|
|
|
|
|
the overall quality and value of CPAN. |
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
One way individuals can contribute is to send a report for each module that |
1619
|
|
|
|
|
|
|
they test or install. CPAN::Reporter is an add-on for the CPAN.pm module to |
1620
|
|
|
|
|
|
|
send the results of building and testing modules to the CPAN Testers project. |
1621
|
|
|
|
|
|
|
Full support for CPAN::Reporter is available in CPAN.pm as of version 1.92. |
1622
|
|
|
|
|
|
|
|
1623
|
|
|
|
|
|
|
=for Pod::Coverage configure |
1624
|
|
|
|
|
|
|
grade_PL |
1625
|
|
|
|
|
|
|
grade_make |
1626
|
|
|
|
|
|
|
grade_test |
1627
|
|
|
|
|
|
|
record_command |
1628
|
|
|
|
|
|
|
test |
1629
|
|
|
|
|
|
|
|
1630
|
|
|
|
|
|
|
=head1 GETTING STARTED |
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
=head2 Installation |
1633
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
The first step in using CPAN::Reporter is to install it using whatever |
1635
|
|
|
|
|
|
|
version of CPAN.pm is already installed. CPAN.pm will be upgraded as |
1636
|
|
|
|
|
|
|
a dependency if necessary. |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
cpan> install CPAN::Reporter |
1639
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
If CPAN.pm was upgraded, it needs to be reloaded. |
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
cpan> reload cpan |
1643
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
=head2 Configuration |
1645
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
If upgrading from a very old version of CPAN.pm, users may be prompted to renew |
1647
|
|
|
|
|
|
|
their configuration settings, including the 'test_report' option to enable |
1648
|
|
|
|
|
|
|
CPAN::Reporter. |
1649
|
|
|
|
|
|
|
|
1650
|
|
|
|
|
|
|
If not prompted automatically, users should manually initialize CPAN::Reporter |
1651
|
|
|
|
|
|
|
support. After enabling CPAN::Reporter, CPAN.pm will automatically continue |
1652
|
|
|
|
|
|
|
with interactive configuration of CPAN::Reporter options. |
1653
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
cpan> o conf init test_report |
1655
|
|
|
|
|
|
|
|
1656
|
|
|
|
|
|
|
Users will need to enter an email address in one of the following formats: |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
johndoe@example.com |
1659
|
|
|
|
|
|
|
John Doe |
1660
|
|
|
|
|
|
|
"John Q. Public" |
1661
|
|
|
|
|
|
|
|
1662
|
|
|
|
|
|
|
Users that are new to CPAN::Reporter should accept the recommended values |
1663
|
|
|
|
|
|
|
for other configuration options. |
1664
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
Users will be prompted to create a I file that uniquely |
1666
|
|
|
|
|
|
|
identifies their test reports. See L"The Metabase"> below for details. |
1667
|
|
|
|
|
|
|
|
1668
|
|
|
|
|
|
|
After completing interactive configuration, be sure to commit (save) the CPAN |
1669
|
|
|
|
|
|
|
configuration changes. |
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
cpan> o conf commit |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
See L for advanced configuration settings. |
1674
|
|
|
|
|
|
|
|
1675
|
|
|
|
|
|
|
=head3 The Metabase |
1676
|
|
|
|
|
|
|
|
1677
|
|
|
|
|
|
|
CPAN::Reporter sends test reports to a server known as the Metabase. This |
1678
|
|
|
|
|
|
|
requires an active Internet connection and a profile file. To create the |
1679
|
|
|
|
|
|
|
profile, users will need to run C<<< metabase-profile >>> from a terminal window and |
1680
|
|
|
|
|
|
|
fill the information at the prompts. This will create a file called |
1681
|
|
|
|
|
|
|
C<<< metabase_id.json >>> in the current directory. That file should be moved to the |
1682
|
|
|
|
|
|
|
C<<< .cpanreporter >>> directory inside the user's home directory. |
1683
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
Users with an existing metabase profile file (e.g. from another machine), |
1685
|
|
|
|
|
|
|
should copy it into the C<<< .cpanreporter >>> directory instead of creating |
1686
|
|
|
|
|
|
|
a new one. Profile files may be located outside the C<<< .cpanreporter >>> |
1687
|
|
|
|
|
|
|
directory by following instructions in L. |
1688
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
=head3 Default Test Comments |
1690
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
This module puts default text into the "TESTER COMMENTS" section, typically, |
1692
|
|
|
|
|
|
|
"none provided" if doing interactive testing, or, if doing smoke testing that |
1693
|
|
|
|
|
|
|
sets CE$ENV{AUTOMATED_TESTING}E to a true value, "this report is from an |
1694
|
|
|
|
|
|
|
automated smoke testing program and was not reviewed by a human for |
1695
|
|
|
|
|
|
|
accuracy." If CECPAN::ReporterE is configured to allow editing of the |
1696
|
|
|
|
|
|
|
report, this can be edited during submission. |
1697
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
If you wish to override the default comment, you can create a file named |
1699
|
|
|
|
|
|
|
CEcomment.txtE in the configuration directory (typically C<<< .cpanreporter >>> |
1700
|
|
|
|
|
|
|
under the user's home directory), with the default comment you would |
1701
|
|
|
|
|
|
|
like to appear. |
1702
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
Note that if your test is an automated smoke |
1704
|
|
|
|
|
|
|
test (CE$ENV{AUTOMATED_TESTING}E is set to a true value), the smoke |
1705
|
|
|
|
|
|
|
test notice ("this report is from an automated smoke testing program and |
1706
|
|
|
|
|
|
|
was not reviewed by a human for accuracy") is included along with a blank |
1707
|
|
|
|
|
|
|
line before your CEcomment.txtE, so that it is always possible to |
1708
|
|
|
|
|
|
|
distinguish automated tests from non-automated tests that use this |
1709
|
|
|
|
|
|
|
module. |
1710
|
|
|
|
|
|
|
|
1711
|
|
|
|
|
|
|
=head2 Using CPAN::Reporter |
1712
|
|
|
|
|
|
|
|
1713
|
|
|
|
|
|
|
Once CPAN::Reporter is enabled and configured, test or install modules with |
1714
|
|
|
|
|
|
|
CPAN.pm as usual. |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
For example, to test the File::Marker module: |
1717
|
|
|
|
|
|
|
|
1718
|
|
|
|
|
|
|
cpan> test File::Marker |
1719
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
If a distribution's tests fail, users will be prompted to edit the report to |
1721
|
|
|
|
|
|
|
add additional information that might help the author understand the failure. |
1722
|
|
|
|
|
|
|
|
1723
|
|
|
|
|
|
|
=head1 UNDERSTANDING TEST GRADES |
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
CPAN::Reporter will assign one of the following grades to the report: |
1726
|
|
|
|
|
|
|
|
1727
|
|
|
|
|
|
|
=over |
1728
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
=item * |
1730
|
|
|
|
|
|
|
|
1731
|
|
|
|
|
|
|
C<<< pass >>> -- distribution built and tested correctly |
1732
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
=item * |
1734
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
C<<< fail >>> -- distribution failed to test correctly |
1736
|
|
|
|
|
|
|
|
1737
|
|
|
|
|
|
|
=item * |
1738
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
C<<< unknown >>> -- distribution failed to build, had no test suite or outcome was |
1740
|
|
|
|
|
|
|
inconclusive |
1741
|
|
|
|
|
|
|
|
1742
|
|
|
|
|
|
|
=item * |
1743
|
|
|
|
|
|
|
|
1744
|
|
|
|
|
|
|
C<<< na >>> --- distribution is not applicable to this platform andEor |
1745
|
|
|
|
|
|
|
version of Perl |
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
=back |
1748
|
|
|
|
|
|
|
|
1749
|
|
|
|
|
|
|
In returning results of the test suite to CPAN.pm, "pass" and "unknown" are |
1750
|
|
|
|
|
|
|
considered successful attempts to "make test" or "Build test" and will not |
1751
|
|
|
|
|
|
|
prevent installation. "fail" and "na" are considered to be failures and |
1752
|
|
|
|
|
|
|
CPAN.pm will not install unless forced. |
1753
|
|
|
|
|
|
|
|
1754
|
|
|
|
|
|
|
An error from Makefile.PLEBuild.PL or makeEBuild will also be graded as |
1755
|
|
|
|
|
|
|
"unknown" and a failure will be signaled to CPAN.pm. |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
If prerequisites specified in C<<< Makefile.PL >>> or C<<< Build.PL >>> are not available, |
1758
|
|
|
|
|
|
|
no report will be generated and a failure will be signaled to CPAN.pm. |
1759
|
|
|
|
|
|
|
|
1760
|
|
|
|
|
|
|
=head1 PRIVACY WARNING |
1761
|
|
|
|
|
|
|
|
1762
|
|
|
|
|
|
|
CPAN::Reporter includes information in the test report about environment |
1763
|
|
|
|
|
|
|
variables and special Perl variables that could be affecting test results in |
1764
|
|
|
|
|
|
|
order to help module authors interpret the results of the tests. This includes |
1765
|
|
|
|
|
|
|
information about paths, terminal, locale, userEgroup ID, installed toolchain |
1766
|
|
|
|
|
|
|
modules (e.g. ExtUtils::MakeMaker) and so on. |
1767
|
|
|
|
|
|
|
|
1768
|
|
|
|
|
|
|
These have been intentionally limited to items that should not cause harmful |
1769
|
|
|
|
|
|
|
personal information to be revealed -- it does I include your entire |
1770
|
|
|
|
|
|
|
environment. Nevertheless, please do not use CPAN::Reporter if you are |
1771
|
|
|
|
|
|
|
concerned about the disclosure of this information as part of your test report. |
1772
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
Users wishing to review this information may choose to edit the report |
1774
|
|
|
|
|
|
|
prior to sending it. |
1775
|
|
|
|
|
|
|
|
1776
|
|
|
|
|
|
|
=head1 BUGS |
1777
|
|
|
|
|
|
|
|
1778
|
|
|
|
|
|
|
Using command_timeout on Linux may cause problems. See |
1779
|
|
|
|
|
|
|
L |
1780
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
Please report any bugs or feature using the CPAN Request Tracker. |
1782
|
|
|
|
|
|
|
Bugs can be submitted through the web interface at |
1783
|
|
|
|
|
|
|
L |
1784
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
When submitting a bug or request, please include a test-file or a patch to an |
1786
|
|
|
|
|
|
|
existing test-file that illustrates the bug or desired feature. |
1787
|
|
|
|
|
|
|
|
1788
|
|
|
|
|
|
|
=head1 SEE ALSO |
1789
|
|
|
|
|
|
|
|
1790
|
|
|
|
|
|
|
Information about CPAN::Testers: |
1791
|
|
|
|
|
|
|
|
1792
|
|
|
|
|
|
|
=over |
1793
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
=item * |
1795
|
|
|
|
|
|
|
|
1796
|
|
|
|
|
|
|
L -- overview of CPAN Testers architecture stack |
1797
|
|
|
|
|
|
|
|
1798
|
|
|
|
|
|
|
=item * |
1799
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
L -- project home with all reports |
1801
|
|
|
|
|
|
|
|
1802
|
|
|
|
|
|
|
=item * |
1803
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
L -- documentation and wiki |
1805
|
|
|
|
|
|
|
|
1806
|
|
|
|
|
|
|
=back |
1807
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
Additional Documentation: |
1809
|
|
|
|
|
|
|
|
1810
|
|
|
|
|
|
|
=over |
1811
|
|
|
|
|
|
|
|
1812
|
|
|
|
|
|
|
=item * |
1813
|
|
|
|
|
|
|
|
1814
|
|
|
|
|
|
|
L -- advanced configuration settings |
1815
|
|
|
|
|
|
|
|
1816
|
|
|
|
|
|
|
=item * |
1817
|
|
|
|
|
|
|
|
1818
|
|
|
|
|
|
|
L -- hints and tips |
1819
|
|
|
|
|
|
|
|
1820
|
|
|
|
|
|
|
=back |
1821
|
|
|
|
|
|
|
|
1822
|
|
|
|
|
|
|
=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan |
1823
|
|
|
|
|
|
|
|
1824
|
|
|
|
|
|
|
=head1 SUPPORT |
1825
|
|
|
|
|
|
|
|
1826
|
|
|
|
|
|
|
=head2 Bugs / Feature Requests |
1827
|
|
|
|
|
|
|
|
1828
|
|
|
|
|
|
|
Please report any bugs or feature requests through the issue tracker |
1829
|
|
|
|
|
|
|
at L. |
1830
|
|
|
|
|
|
|
You will be notified automatically of any progress on your issue. |
1831
|
|
|
|
|
|
|
|
1832
|
|
|
|
|
|
|
=head2 Source Code |
1833
|
|
|
|
|
|
|
|
1834
|
|
|
|
|
|
|
This is open source software. The code repository is available for |
1835
|
|
|
|
|
|
|
public review and contribution under the terms of the license. |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
L |
1838
|
|
|
|
|
|
|
|
1839
|
|
|
|
|
|
|
git clone https://github.com/cpan-testers/CPAN-Reporter.git |
1840
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
=head1 AUTHOR |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
David Golden |
1844
|
|
|
|
|
|
|
|
1845
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
1846
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
=for stopwords Alexandr Ciornii Breno G. de Oliveira Christian Walde David Cantrell Ed J Graham Knop James E Keenan J. Maslak José Joaquín Atria Kent Fredric Matthew Musgrove Patrice Clement Reini Urban Scott Wiersdorf Slaven Rezic |
1848
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
=over 4 |
1850
|
|
|
|
|
|
|
|
1851
|
|
|
|
|
|
|
=item * |
1852
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
Alexandr Ciornii |
1854
|
|
|
|
|
|
|
|
1855
|
|
|
|
|
|
|
=item * |
1856
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
Breno G. de Oliveira |
1858
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
=item * |
1860
|
|
|
|
|
|
|
|
1861
|
|
|
|
|
|
|
Christian Walde |
1862
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
=item * |
1864
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
David Cantrell |
1866
|
|
|
|
|
|
|
|
1867
|
|
|
|
|
|
|
=item * |
1868
|
|
|
|
|
|
|
|
1869
|
|
|
|
|
|
|
Ed J |
1870
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
=item * |
1872
|
|
|
|
|
|
|
|
1873
|
|
|
|
|
|
|
Graham Knop |
1874
|
|
|
|
|
|
|
|
1875
|
|
|
|
|
|
|
=item * |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
James E Keenan |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
=item * |
1880
|
|
|
|
|
|
|
|
1881
|
|
|
|
|
|
|
J. Maslak |
1882
|
|
|
|
|
|
|
|
1883
|
|
|
|
|
|
|
=item * |
1884
|
|
|
|
|
|
|
|
1885
|
|
|
|
|
|
|
José Joaquín Atria |
1886
|
|
|
|
|
|
|
|
1887
|
|
|
|
|
|
|
=item * |
1888
|
|
|
|
|
|
|
|
1889
|
|
|
|
|
|
|
Kent Fredric |
1890
|
|
|
|
|
|
|
|
1891
|
|
|
|
|
|
|
=item * |
1892
|
|
|
|
|
|
|
|
1893
|
|
|
|
|
|
|
Matthew Musgrove |
1894
|
|
|
|
|
|
|
|
1895
|
|
|
|
|
|
|
=item * |
1896
|
|
|
|
|
|
|
|
1897
|
|
|
|
|
|
|
Patrice Clement |
1898
|
|
|
|
|
|
|
|
1899
|
|
|
|
|
|
|
=item * |
1900
|
|
|
|
|
|
|
|
1901
|
|
|
|
|
|
|
Reini Urban |
1902
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
=item * |
1904
|
|
|
|
|
|
|
|
1905
|
|
|
|
|
|
|
Scott Wiersdorf |
1906
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
=item * |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
Slaven Rezic |
1910
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
=back |
1912
|
|
|
|
|
|
|
|
1913
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
1914
|
|
|
|
|
|
|
|
1915
|
|
|
|
|
|
|
This software is Copyright (c) 2023 by David Golden. |
1916
|
|
|
|
|
|
|
|
1917
|
|
|
|
|
|
|
This is free software, licensed under: |
1918
|
|
|
|
|
|
|
|
1919
|
|
|
|
|
|
|
The Apache License, Version 2.0, January 2004 |
1920
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
=cut |
1922
|
|
|
|
|
|
|
|
1923
|
|
|
|
|
|
|
__END__ |