line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CPAN::Testers::Common::Client::Config; |
2
|
5
|
|
|
5
|
|
692
|
use strict; |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
173
|
|
3
|
5
|
|
|
5
|
|
24
|
use warnings; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
107
|
|
4
|
|
|
|
|
|
|
|
5
|
5
|
|
|
5
|
|
20
|
use Carp (); |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
87
|
|
6
|
5
|
|
|
5
|
|
46
|
use File::Glob (); |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
104
|
|
7
|
5
|
|
|
5
|
|
21
|
use File::Spec 3.19 (); |
|
5
|
|
|
|
|
163
|
|
|
5
|
|
|
|
|
126
|
|
8
|
5
|
|
|
5
|
|
1878
|
use File::HomeDir 0.58 (); |
|
5
|
|
|
|
|
19068
|
|
|
5
|
|
|
|
|
107
|
|
9
|
5
|
|
|
5
|
|
27
|
use File::Path qw( mkpath ); |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
204
|
|
10
|
5
|
|
|
5
|
|
2643
|
use IPC::Cmd; |
|
5
|
|
|
|
|
201552
|
|
|
5
|
|
|
|
|
18104
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub new { |
13
|
1
|
|
|
1
|
1
|
589
|
my ($class, %args) = @_; |
14
|
1
|
|
|
|
|
4
|
my $self = bless { |
15
|
|
|
|
|
|
|
_prompt => undef, |
16
|
|
|
|
|
|
|
_warn => undef, |
17
|
|
|
|
|
|
|
_print => undef, |
18
|
|
|
|
|
|
|
_config => {}, |
19
|
|
|
|
|
|
|
}, $class; |
20
|
|
|
|
|
|
|
|
21
|
1
|
50
|
|
0
|
|
4
|
my $warn = exists $args{'warn'} ? $args{'warn'} : sub { warn @_ }; |
|
0
|
|
|
|
|
0
|
|
22
|
1
|
50
|
|
|
|
2
|
$self->_set_mywarn( $warn ) |
23
|
|
|
|
|
|
|
or Carp::croak q(the 'warn' parameter must be a coderef); |
24
|
|
|
|
|
|
|
|
25
|
1
|
50
|
|
0
|
|
3
|
my $print = exists $args{'print'} ? $args{'print'} : sub { print @_ }; |
|
0
|
|
|
|
|
0
|
|
26
|
1
|
50
|
|
|
|
2
|
$self->_set_myprint( $print ) |
27
|
|
|
|
|
|
|
or Carp::croak q(the 'print' parameter must be a coderef); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# prompt is optional |
30
|
1
|
50
|
|
|
|
2
|
if (exists $args{'prompt'}) { |
31
|
1
|
50
|
|
|
|
2
|
$self->_set_myprompt( $args{'prompt'} ) |
32
|
|
|
|
|
|
|
or Carp::croak q(the 'prompt' parameter must be a coderef); |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
1
|
|
|
|
|
3
|
return $self; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub read { |
39
|
1
|
|
|
1
|
1
|
630
|
my $self = shift; |
40
|
1
|
50
|
|
|
|
3
|
my $config = $self->_read_config_file or return; |
41
|
1
|
|
|
|
|
3
|
my $options = $self->_get_config_options( $config ); |
42
|
1
|
|
|
|
|
3
|
$self->_config_data( $options ); |
43
|
1
|
|
|
|
|
19
|
return 1; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
####################### |
47
|
|
|
|
|
|
|
### basic accessors ### |
48
|
|
|
|
|
|
|
####################### |
49
|
|
|
|
|
|
|
|
50
|
1
|
|
|
1
|
1
|
440
|
sub email_from { return shift->{_config}{email_from} } |
51
|
0
|
|
|
0
|
1
|
0
|
sub edit_report { return shift->_config_data_for('edit_report', @_) } |
52
|
0
|
|
|
0
|
1
|
0
|
sub send_report { return shift->_config_data_for('send_report', @_) } |
53
|
0
|
|
|
0
|
1
|
0
|
sub send_duplicates { return shift->_config_data_for('send_duplicates', @_) } |
54
|
0
|
|
|
0
|
1
|
0
|
sub transport { return shift->{_config}{transport} } |
55
|
1
|
|
|
1
|
1
|
4
|
sub transport_name { return shift->{_transport_name} } |
56
|
2
|
|
|
2
|
1
|
431
|
sub transport_args { return shift->{_transport_args} } |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub get_config_dir { |
59
|
21
|
100
|
66
|
21
|
1
|
313
|
if ( defined $ENV{PERL_CPAN_REPORTER_DIR} && |
60
|
|
|
|
|
|
|
length $ENV{PERL_CPAN_REPORTER_DIR} |
61
|
|
|
|
|
|
|
) { |
62
|
2
|
|
|
|
|
20
|
return $ENV{PERL_CPAN_REPORTER_DIR}; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
19
|
|
|
|
|
75
|
my $conf_dir = File::Spec->catdir(File::HomeDir->my_home, ".cpanreporter"); |
66
|
|
|
|
|
|
|
|
67
|
19
|
50
|
|
|
|
342
|
if ($^O eq 'MSWin32') { |
68
|
0
|
|
|
|
|
0
|
my $alt_dir = File::Spec->catdir(File::HomeDir->my_documents, ".cpanreporter"); |
69
|
0
|
0
|
0
|
|
|
0
|
$conf_dir = $alt_dir if -d $alt_dir && ! -d $conf_dir; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
19
|
|
|
|
|
98
|
return $conf_dir; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub get_config_filename { |
76
|
1
|
50
|
33
|
1
|
1
|
5
|
if ( defined $ENV{PERL_CPAN_REPORTER_CONFIG} && |
77
|
|
|
|
|
|
|
length $ENV{PERL_CPAN_REPORTER_CONFIG} |
78
|
|
|
|
|
|
|
) { |
79
|
0
|
|
|
|
|
0
|
return $ENV{PERL_CPAN_REPORTER_CONFIG}; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
else { |
82
|
1
|
|
|
|
|
2
|
return File::Spec->catdir( get_config_dir, 'config.ini' ); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# the provided subrefs do not know about $self. |
87
|
2
|
|
|
2
|
1
|
782
|
sub mywarn { my $r = shift->{_warn}; return $r->(@_) } |
|
2
|
|
|
|
|
5
|
|
88
|
1
|
|
|
1
|
1
|
681
|
sub myprint { my $r = shift->{_print}; return $r->(@_) } |
|
1
|
|
|
|
|
3
|
|
89
|
1
|
|
|
1
|
1
|
1401
|
sub myprompt { my $r = shift->{_prompt}; return $r->(@_) } |
|
1
|
|
|
|
|
3
|
|
90
|
0
|
|
|
0
|
|
0
|
sub _has_prompt { return exists $_[0]->{_prompt} } |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub setup { |
93
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
94
|
|
|
|
|
|
|
|
95
|
0
|
0
|
|
|
|
0
|
Carp::croak q{please provide a 'prompt' coderef to new()} |
96
|
|
|
|
|
|
|
unless $self->_has_prompt; |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
0
|
my $config_dir = $self->get_config_dir; |
99
|
0
|
0
|
|
|
|
0
|
mkpath $config_dir unless -d $config_dir; |
100
|
|
|
|
|
|
|
|
101
|
0
|
0
|
|
|
|
0
|
unless ( -d $config_dir ) { |
102
|
0
|
|
|
|
|
0
|
$self->myprint( |
103
|
|
|
|
|
|
|
"\nCPAN Testers: couldn't create configuration directory '$config_dir': $!" |
104
|
|
|
|
|
|
|
); |
105
|
0
|
|
|
|
|
0
|
return; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
0
|
|
|
|
|
0
|
my $config_file = $self->get_config_filename; |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# explain grade:action pairs to the user |
111
|
0
|
|
|
|
|
0
|
$self->myprint( _grade_action_prompt() ); |
112
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
0
|
my ($config, $existing_options) = ( {}, {} ); |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# read or create the config file |
116
|
0
|
0
|
|
|
|
0
|
if ( -f $config_file ) { |
117
|
0
|
|
|
|
|
0
|
$self->myprint("\nCPAN Testers: found your config file at:\n$config_file\n"); |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# bail out if we can't read it |
120
|
0
|
|
|
|
|
0
|
$existing_options = $self->_read_config_file; |
121
|
0
|
0
|
|
|
|
0
|
if ( !$existing_options ) { |
122
|
0
|
|
|
|
|
0
|
$self->mywarn("\nCPAN Testers: configuration will not be changed\n"); |
123
|
0
|
|
|
|
|
0
|
return; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
0
|
$self->myprint("\nCPAN Testers: Updating your configuration settings:\n"); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
else { |
129
|
0
|
|
|
|
|
0
|
$self->myprint("\nCPAN Testers: no config file found; creating a new one.\n"); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
0
|
|
|
|
|
0
|
my %spec = $self->_config_spec; |
133
|
|
|
|
|
|
|
|
134
|
0
|
|
|
|
|
0
|
foreach my $k ( $self->_config_order ) { |
135
|
0
|
|
|
|
|
0
|
my $option_data = $spec{$k}; |
136
|
0
|
|
|
|
|
0
|
$self->myprint("\n$option_data->{info}\n"); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# options with defaults are mandatory |
139
|
0
|
0
|
|
|
|
0
|
if (defined $option_data->{default}) { |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# as a side-effect, people may use '' without |
142
|
|
|
|
|
|
|
# an actual default value to mark the option |
143
|
|
|
|
|
|
|
# as mandatory. So we only show de default value |
144
|
|
|
|
|
|
|
# if there is one. |
145
|
0
|
0
|
|
|
|
0
|
if (length $option_data->{default}) { |
146
|
0
|
|
|
|
|
0
|
$self->myprint("(Recommended: '$option_data->{default}')\n\n"); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
# repeat until validated |
149
|
|
|
|
|
|
|
PROMPT: |
150
|
0
|
|
0
|
|
|
0
|
while ( defined ( |
151
|
|
|
|
|
|
|
my $answer = $self->myprompt( |
152
|
|
|
|
|
|
|
"$k?", |
153
|
|
|
|
|
|
|
$existing_options->{$k} || $option_data->{default} |
154
|
|
|
|
|
|
|
) |
155
|
|
|
|
|
|
|
)) { |
156
|
|
|
|
|
|
|
# TODO: I don't think _validate() is being used |
157
|
|
|
|
|
|
|
# because of this. Should we remove it? |
158
|
0
|
0
|
0
|
|
|
0
|
if ( ! $option_data->{validate} || |
159
|
|
|
|
|
|
|
$option_data->{validate}->($self, $k, $answer, $config) |
160
|
|
|
|
|
|
|
) { |
161
|
0
|
|
|
|
|
0
|
$config->{$k} = $answer; |
162
|
0
|
|
|
|
|
0
|
last PROMPT; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
else { |
167
|
|
|
|
|
|
|
# only initialize options without defaults if the answer |
168
|
|
|
|
|
|
|
# matches non white space and validates properly. |
169
|
|
|
|
|
|
|
# Otherwise, just ignore it. |
170
|
0
|
|
0
|
|
|
0
|
my $answer = $self->myprompt("$k?", $existing_options->{$k} || q{}); |
171
|
0
|
0
|
|
|
|
0
|
if ( $answer =~ /\S/ ) { |
172
|
0
|
|
|
|
|
0
|
$config->{$k} = $answer; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
# delete existing keys as we proceed so we know what's left |
176
|
0
|
|
|
|
|
0
|
delete $existing_options->{$k}; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# initialize remaining options |
180
|
|
|
|
|
|
|
$self->myprint( |
181
|
0
|
0
|
|
|
|
0
|
"\nYour CPAN Testers config file also contains these advanced options\n\n" |
182
|
|
|
|
|
|
|
) if keys %$existing_options; |
183
|
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
0
|
foreach my $k ( keys %$existing_options ) { |
185
|
0
|
|
|
|
|
0
|
$config->{$k} = $self->myprompt("$k?", $existing_options->{$k}); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
0
|
$self->myprint("\nCPAN Testers: writing config file to '$config_file'.\n"); |
189
|
0
|
0
|
|
|
|
0
|
if ( $self->_write_config_file( $config ) ) { |
190
|
0
|
|
|
|
|
0
|
$self->_config_data( $config ); |
191
|
0
|
|
|
|
|
0
|
return $config; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
else { |
194
|
0
|
|
|
|
|
0
|
return; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
199
|
|
|
|
|
|
|
# _config_spec -- returns configuration options information |
200
|
|
|
|
|
|
|
# |
201
|
|
|
|
|
|
|
# Keys include |
202
|
|
|
|
|
|
|
# default -- recommended value, used in prompts and as a fallback |
203
|
|
|
|
|
|
|
# if an options is not set; mandatory if defined |
204
|
|
|
|
|
|
|
# prompt -- short prompt for EU::MM prompting |
205
|
|
|
|
|
|
|
# info -- long description shown before prompting |
206
|
|
|
|
|
|
|
# validate -- CODE ref; return normalized option or undef if invalid |
207
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
208
|
|
|
|
|
|
|
sub _config_spec { |
209
|
|
|
|
|
|
|
return ( |
210
|
1
|
|
|
1
|
|
27
|
email_from => { |
211
|
|
|
|
|
|
|
default => '', |
212
|
|
|
|
|
|
|
prompt => 'What email address will be used to reference your reports?', |
213
|
|
|
|
|
|
|
validate => \&_validate_email, |
214
|
|
|
|
|
|
|
info => <<'HERE', |
215
|
|
|
|
|
|
|
CPAN Testers requires a valid email address to identify senders |
216
|
|
|
|
|
|
|
in the body of a test report. Please use a standard email format |
217
|
|
|
|
|
|
|
like: "John Doe" |
218
|
|
|
|
|
|
|
HERE |
219
|
|
|
|
|
|
|
}, |
220
|
|
|
|
|
|
|
smtp_server => { |
221
|
|
|
|
|
|
|
default => undef, # (deprecated) |
222
|
|
|
|
|
|
|
prompt => "[DEPRECATED] It's safe to remove this from your config file.", |
223
|
|
|
|
|
|
|
}, |
224
|
|
|
|
|
|
|
edit_report => { |
225
|
|
|
|
|
|
|
default => 'default:ask/no pass/na:no', |
226
|
|
|
|
|
|
|
prompt => 'Do you want to review or edit the test report?', |
227
|
|
|
|
|
|
|
validate => \&_validate_grade_action_pair, |
228
|
|
|
|
|
|
|
info => <<'HERE', |
229
|
|
|
|
|
|
|
Before test reports are sent, you may want to review or edit the test |
230
|
|
|
|
|
|
|
report and add additional comments about the result or about your system |
231
|
|
|
|
|
|
|
or Perl configuration. By default, we will ask after each report is |
232
|
|
|
|
|
|
|
generated whether or not you would like to edit the report. This option |
233
|
|
|
|
|
|
|
takes "grade:action" pairs. |
234
|
|
|
|
|
|
|
HERE |
235
|
|
|
|
|
|
|
}, |
236
|
|
|
|
|
|
|
send_report => { |
237
|
|
|
|
|
|
|
default => 'default:ask/yes pass/na:yes', |
238
|
|
|
|
|
|
|
prompt => 'Do you want to send the report?', |
239
|
|
|
|
|
|
|
validate => \&_validate_grade_action_pair, |
240
|
|
|
|
|
|
|
info => <<'HERE', |
241
|
|
|
|
|
|
|
By default, we will prompt you for confirmation that the test report |
242
|
|
|
|
|
|
|
should be sent before actually doing it. This gives the opportunity to |
243
|
|
|
|
|
|
|
skip sending particular reports if you need to (e.g. if you caused the |
244
|
|
|
|
|
|
|
failure). This option takes "grade:action" pairs. |
245
|
|
|
|
|
|
|
HERE |
246
|
|
|
|
|
|
|
}, |
247
|
|
|
|
|
|
|
transport => { |
248
|
|
|
|
|
|
|
default => 'Metabase uri https://metabase.cpantesters.org/api/v1/ id_file metabase_id.json', |
249
|
|
|
|
|
|
|
prompt => 'Which transport system will be used to transmit the reports?', |
250
|
|
|
|
|
|
|
validate => \&_validate_transport, |
251
|
|
|
|
|
|
|
info => <<'HERE', |
252
|
|
|
|
|
|
|
CPAN Testers gets your reports over HTTPS using Metabase. This option lets |
253
|
|
|
|
|
|
|
you set a different uri, transport mechanism and metabase profile path. If you |
254
|
|
|
|
|
|
|
are receiving HTTPS errors, you may change the uri to use plain HTTP, though |
255
|
|
|
|
|
|
|
this is not recommended. Unless you know what you're doing, just accept |
256
|
|
|
|
|
|
|
the default value. |
257
|
|
|
|
|
|
|
HERE |
258
|
|
|
|
|
|
|
}, |
259
|
|
|
|
|
|
|
send_duplicates => { |
260
|
|
|
|
|
|
|
default => 'default:no', |
261
|
|
|
|
|
|
|
prompt => 'This report is identical to a previous one. Send it anyway?', |
262
|
|
|
|
|
|
|
validate => \&_validate_grade_action_pair, |
263
|
|
|
|
|
|
|
info => <<'HERE', |
264
|
|
|
|
|
|
|
CPAN Testers records tests grades for each distribution, version and |
265
|
|
|
|
|
|
|
platform. By default, duplicates of previous results will not be sent at |
266
|
|
|
|
|
|
|
all, regardless of the value of the "send_report" option. This option takes |
267
|
|
|
|
|
|
|
"grade:action" pairs. |
268
|
|
|
|
|
|
|
HERE |
269
|
|
|
|
|
|
|
}, |
270
|
|
|
|
|
|
|
send_PL_report => { |
271
|
|
|
|
|
|
|
prompt => 'Do you want to send the PL report?', |
272
|
|
|
|
|
|
|
default => undef, |
273
|
|
|
|
|
|
|
validate => \&_validate_grade_action_pair, |
274
|
|
|
|
|
|
|
}, |
275
|
|
|
|
|
|
|
send_make_report => { |
276
|
|
|
|
|
|
|
prompt => 'Do you want to send the make/Build report?', |
277
|
|
|
|
|
|
|
default => undef, |
278
|
|
|
|
|
|
|
validate => \&_validate_grade_action_pair, |
279
|
|
|
|
|
|
|
}, |
280
|
|
|
|
|
|
|
send_test_report => { |
281
|
|
|
|
|
|
|
prompt => 'Do you want to send the test report?', |
282
|
|
|
|
|
|
|
default => undef, |
283
|
|
|
|
|
|
|
validate => \&_validate_grade_action_pair, |
284
|
|
|
|
|
|
|
}, |
285
|
|
|
|
|
|
|
send_skipfile => { |
286
|
|
|
|
|
|
|
prompt => "What file has patterns for things that shouldn't be reported?", |
287
|
|
|
|
|
|
|
default => undef, |
288
|
|
|
|
|
|
|
validate => \&_validate_skipfile, |
289
|
|
|
|
|
|
|
}, |
290
|
|
|
|
|
|
|
cc_skipfile => { |
291
|
|
|
|
|
|
|
prompt => "What file has patterns for things that shouldn't CC to authors?", |
292
|
|
|
|
|
|
|
default => undef, |
293
|
|
|
|
|
|
|
validate => \&_validate_skipfile, |
294
|
|
|
|
|
|
|
}, |
295
|
|
|
|
|
|
|
command_timeout => { |
296
|
|
|
|
|
|
|
prompt => 'If no timeout is set by CPAN, halt system commands after how many seconds?', |
297
|
|
|
|
|
|
|
default => undef, |
298
|
|
|
|
|
|
|
validate => \&_validate_seconds, |
299
|
|
|
|
|
|
|
}, |
300
|
|
|
|
|
|
|
email_to => { |
301
|
|
|
|
|
|
|
default => undef, |
302
|
|
|
|
|
|
|
validate => \&_validate_email, |
303
|
|
|
|
|
|
|
}, |
304
|
|
|
|
|
|
|
editor => { |
305
|
|
|
|
|
|
|
default => undef, |
306
|
|
|
|
|
|
|
}, |
307
|
|
|
|
|
|
|
debug => { |
308
|
|
|
|
|
|
|
default => undef, |
309
|
|
|
|
|
|
|
}, |
310
|
|
|
|
|
|
|
retry_submission => { |
311
|
|
|
|
|
|
|
default => undef, |
312
|
|
|
|
|
|
|
}, |
313
|
|
|
|
|
|
|
); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
317
|
|
|
|
|
|
|
# _config_order -- determines order of interactive config. Only items |
318
|
|
|
|
|
|
|
# in interactive config will be written to a starter config file |
319
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
320
|
|
|
|
|
|
|
sub _config_order { |
321
|
0
|
|
|
0
|
|
0
|
return qw( |
322
|
|
|
|
|
|
|
email_from |
323
|
|
|
|
|
|
|
edit_report |
324
|
|
|
|
|
|
|
send_report |
325
|
|
|
|
|
|
|
transport |
326
|
|
|
|
|
|
|
); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub _set_myprompt { |
331
|
1
|
|
|
1
|
|
2
|
my ($self, $prompt) = @_; |
332
|
1
|
50
|
33
|
|
|
5
|
if ($prompt and ref $prompt and ref $prompt eq 'CODE') { |
|
|
|
33
|
|
|
|
|
333
|
1
|
|
|
|
|
2
|
$self->{_prompt} = $prompt; |
334
|
1
|
|
|
|
|
2
|
return $self; |
335
|
|
|
|
|
|
|
} |
336
|
0
|
|
|
|
|
0
|
return; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub _set_mywarn { |
340
|
1
|
|
|
1
|
|
2
|
my ($self, $warn) = @_; |
341
|
1
|
50
|
33
|
|
|
8
|
if ($warn and ref $warn and ref $warn eq 'CODE') { |
|
|
|
33
|
|
|
|
|
342
|
1
|
|
|
|
|
4
|
$self->{_warn} = $warn; |
343
|
1
|
|
|
|
|
3
|
return $self; |
344
|
|
|
|
|
|
|
} |
345
|
0
|
|
|
|
|
0
|
return; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub _set_myprint { |
349
|
1
|
|
|
1
|
|
2
|
my ($self, $print) = @_; |
350
|
1
|
50
|
33
|
|
|
8
|
if ($print and ref $print and ref $print eq 'CODE') { |
|
|
|
33
|
|
|
|
|
351
|
1
|
|
|
|
|
2
|
$self->{_print} = $print; |
352
|
1
|
|
|
|
|
3
|
return $self; |
353
|
|
|
|
|
|
|
} |
354
|
0
|
|
|
|
|
0
|
return; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# _read_config_file() is a trimmed down version of |
358
|
|
|
|
|
|
|
# Adam Kennedy's great Config::Tiny to fit our needs |
359
|
|
|
|
|
|
|
# (while also avoiding the extra toolchain dep). |
360
|
|
|
|
|
|
|
sub _read_config_file { |
361
|
1
|
|
|
1
|
|
1
|
my $self = shift; |
362
|
1
|
|
|
|
|
2
|
my $file = $self->get_config_filename; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# check the file |
365
|
1
|
50
|
|
|
|
18
|
return $self->_config_error("File '$file' does not exist") unless -e $file; |
366
|
1
|
50
|
|
|
|
3
|
return $self->_config_error("'$file' is a directory, not a file") unless -f _; |
367
|
1
|
50
|
|
|
|
6
|
return $self->_config_error("Insufficient permissions to read '$file'") unless -r _; |
368
|
|
|
|
|
|
|
|
369
|
1
|
50
|
|
|
|
30
|
open my $fh, '<', $file |
370
|
|
|
|
|
|
|
or return $self->_config_error("Failed to open file '$file': $!"); |
371
|
1
|
|
|
|
|
2
|
my $contents = do { local $/; <$fh> }; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
25
|
|
372
|
1
|
|
|
|
|
13
|
close $fh; |
373
|
|
|
|
|
|
|
|
374
|
1
|
|
|
|
|
3
|
my $config = {}; |
375
|
1
|
|
|
|
|
1
|
my $counter = 0; |
376
|
1
|
|
|
|
|
26
|
foreach my $line ( split /(?:\015{1,2}\012|\015|\012)/, $contents ) { |
377
|
4
|
|
|
|
|
5
|
$counter++; |
378
|
4
|
50
|
|
|
|
13
|
next if $line =~ /^\s*(?:\#|\;|$)/; # skip comments and empty lines |
379
|
4
|
|
|
|
|
7
|
$line =~ s/\s\;\s.+$//g; # remove inline comments |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# handle properties |
382
|
4
|
50
|
|
|
|
24
|
if ( $line =~ /^\s*([^=]+?)\s*=\s*(.*?)\s*$/ ) { |
383
|
4
|
|
|
|
|
9
|
$config->{$1} = $2; |
384
|
4
|
|
|
|
|
12
|
next; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
0
|
|
|
|
|
0
|
return $self->_config_error( |
388
|
|
|
|
|
|
|
"Syntax error in config file '$file' at line $counter: '$_'" |
389
|
|
|
|
|
|
|
); |
390
|
|
|
|
|
|
|
} |
391
|
1
|
|
|
|
|
5
|
return $config; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub _write_config_file { |
395
|
0
|
|
|
0
|
|
0
|
my ($self, $config) = @_; |
396
|
|
|
|
|
|
|
|
397
|
0
|
|
|
|
|
0
|
my $contents = ''; |
398
|
0
|
|
|
|
|
0
|
foreach my $item ( sort keys %$config ) { |
399
|
0
|
0
|
|
|
|
0
|
if ( $config->{$item} =~ /(?:\012|\015)/s ) { |
400
|
0
|
|
|
|
|
0
|
return $self->_config_error("Illegal newlines in option '$item'"); |
401
|
|
|
|
|
|
|
} |
402
|
0
|
|
|
|
|
0
|
$contents .= "$item=$config->{$item}\n"; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
0
|
|
|
|
|
0
|
my $file = $self->get_config_filename; |
406
|
0
|
0
|
|
|
|
0
|
open my $fh, '>', $file |
407
|
|
|
|
|
|
|
or return $self->_config_error("Error writing config file '$file': $!"); |
408
|
|
|
|
|
|
|
|
409
|
0
|
|
|
|
|
0
|
print $fh $contents; |
410
|
0
|
|
|
|
|
0
|
close $fh; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
sub _config_error { |
414
|
0
|
|
|
0
|
|
0
|
my ($self, $msg) = @_; |
415
|
0
|
|
|
|
|
0
|
$self->mywarn( "\nCPAN Testers: $msg\n" ); |
416
|
0
|
|
|
|
|
0
|
return; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
sub _config_data { |
420
|
2
|
|
|
2
|
|
2
|
my ($self, $config) = @_; |
421
|
2
|
100
|
|
|
|
12
|
$self->{_config} = $config if $config; |
422
|
2
|
|
|
|
|
5
|
return $self->{_config}; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
sub _config_data_for { |
426
|
0
|
|
|
0
|
|
0
|
my ($self, $type, $grade) = @_; |
427
|
0
|
|
|
|
|
0
|
my %spec = $self->_config_spec; |
428
|
0
|
0
|
|
|
|
0
|
my $data = exists $self->{_config}{$type} ? $self->{_config}{$type} : q(); |
429
|
|
|
|
|
|
|
|
430
|
0
|
|
|
|
|
0
|
my $dispatch = $spec{$type}{validate}->( |
431
|
|
|
|
|
|
|
$self, |
432
|
|
|
|
|
|
|
$type, |
433
|
|
|
|
|
|
|
join( q{ }, 'default:no', $data ) |
434
|
|
|
|
|
|
|
); |
435
|
0
|
|
0
|
|
|
0
|
return lc( $dispatch->{$grade} || $dispatch->{default} ); |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# extract and return valid options, |
439
|
|
|
|
|
|
|
# with fallback to defaults |
440
|
|
|
|
|
|
|
sub _get_config_options { |
441
|
1
|
|
|
1
|
|
2
|
my ($self, $config) = @_; |
442
|
1
|
|
|
|
|
3
|
my %spec = $self->_config_spec; |
443
|
|
|
|
|
|
|
|
444
|
1
|
|
|
|
|
3
|
my %active; |
445
|
1
|
|
|
|
|
4
|
OPTION: foreach my $option (keys %spec) { |
446
|
16
|
100
|
|
|
|
31
|
if (exists $config->{$option} ) { |
447
|
4
|
|
|
|
|
5
|
my $val = $config->{$option}; |
448
|
4
|
50
|
33
|
|
|
11
|
if ( $spec{$option}{validate} |
449
|
|
|
|
|
|
|
&& !$spec{$option}{validate}->($self, $option, $val) |
450
|
|
|
|
|
|
|
) { |
451
|
0
|
|
|
|
|
0
|
$self->mywarn( "\nCPAN Testers: invalid option '$val' in '$option'. Using default value instead.\n\n" ); |
452
|
0
|
|
|
|
|
0
|
$active{$option} = $spec{$option}{default}; |
453
|
0
|
|
|
|
|
0
|
next OPTION; |
454
|
|
|
|
|
|
|
} |
455
|
4
|
|
|
|
|
12
|
$active{$option} = $val; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
else { |
458
|
|
|
|
|
|
|
$active{$option} = $spec{$option}{default} |
459
|
12
|
100
|
|
|
|
22
|
if defined $spec{$option}{default}; |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
} |
462
|
1
|
|
|
|
|
7
|
return \%active; |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
466
|
|
|
|
|
|
|
# _normalize_id_file |
467
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
sub _normalize_id_file { |
470
|
3
|
|
|
3
|
|
877
|
my ($self, $id_file) = @_; |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
# if file path is enclosed in quotes, remove them: |
473
|
3
|
100
|
|
|
|
15
|
if ($id_file =~ s/\A(['"])(.+)\1\z/$2/) { |
474
|
1
|
|
|
|
|
2
|
$id_file =~ s/\\(.)/$1/g; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
# Windows does not use ~ to signify a home directory |
478
|
3
|
50
|
33
|
|
|
13
|
if ( $^O eq 'MSWin32' && $id_file =~ m{^~/(.*)} ) { |
|
|
100
|
|
|
|
|
|
479
|
0
|
|
|
|
|
0
|
$id_file = File::Spec->catdir(File::HomeDir->my_home, $1); |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
elsif ( $id_file =~ /~/ ) { |
482
|
1
|
|
|
|
|
50
|
$id_file = File::Spec->canonpath(File::Glob::bsd_glob( $id_file )); |
483
|
|
|
|
|
|
|
} |
484
|
3
|
100
|
|
|
|
24
|
unless ( File::Spec->file_name_is_absolute( $id_file ) ) { |
485
|
1
|
|
|
|
|
3
|
$id_file = File::Spec->catfile( |
486
|
|
|
|
|
|
|
$self->get_config_dir, $id_file |
487
|
|
|
|
|
|
|
); |
488
|
|
|
|
|
|
|
} |
489
|
3
|
|
|
|
|
9
|
return $id_file; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub _generate_profile { |
493
|
0
|
|
|
0
|
|
0
|
my ($id_file, $email) = @_; |
494
|
|
|
|
|
|
|
|
495
|
0
|
|
|
|
|
0
|
my $cmd = IPC::Cmd::can_run('metabase-profile'); |
496
|
0
|
0
|
|
|
|
0
|
return unless $cmd; |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# XXX this is an evil assumption about email addresses, but |
499
|
|
|
|
|
|
|
# might do for simple cases that users might actually provide |
500
|
|
|
|
|
|
|
|
501
|
0
|
|
|
|
|
0
|
my @opts = ("--output" => $id_file); |
502
|
|
|
|
|
|
|
|
503
|
0
|
0
|
|
|
|
0
|
if ($email =~ /\A(.+)\s+<([^>]+)>\z/ ) { |
504
|
0
|
|
|
|
|
0
|
push @opts, "--email" => $2; |
505
|
0
|
|
|
|
|
0
|
my $name = $1; |
506
|
0
|
|
|
|
|
0
|
$name =~ s/\A["'](.*)["']\z/$1/; |
507
|
0
|
0
|
|
|
|
0
|
push ( @opts, "--name" => $1) |
508
|
|
|
|
|
|
|
if length $name; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
else { |
511
|
0
|
|
|
|
|
0
|
push @opts, "--email" => $email; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# XXX profile 'secret' is really just a generated API key, so we |
515
|
|
|
|
|
|
|
# can create something fairly random for the user and use that |
516
|
0
|
|
|
|
|
0
|
push @opts, "--secret" => sprintf("%08x", rand(2**31)); |
517
|
|
|
|
|
|
|
|
518
|
0
|
|
|
|
|
0
|
return scalar IPC::Cmd::run( |
519
|
|
|
|
|
|
|
command => [ $cmd, @opts ], |
520
|
|
|
|
|
|
|
verbose => 1, |
521
|
|
|
|
|
|
|
); |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
sub _grade_action_prompt { |
525
|
0
|
|
|
0
|
|
0
|
return << 'HERE'; |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
Some of the following configuration options require one or more "grade:action" |
528
|
|
|
|
|
|
|
pairs that determine what grade-specific action to take for that option. |
529
|
|
|
|
|
|
|
These pairs should be space-separated and are processed left-to-right. See |
530
|
|
|
|
|
|
|
CPAN::Testers::Common::Client::Config documentation for more details. |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
GRADE : ACTION ======> EXAMPLES |
533
|
|
|
|
|
|
|
------- ------- -------- |
534
|
|
|
|
|
|
|
pass yes default:no |
535
|
|
|
|
|
|
|
fail no default:yes pass:no |
536
|
|
|
|
|
|
|
unknown ask/no default:ask/no pass:yes fail:no |
537
|
|
|
|
|
|
|
na ask/yes |
538
|
|
|
|
|
|
|
default |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
HERE |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
sub _is_valid_action { |
544
|
4
|
|
|
4
|
|
5
|
my $action = shift; |
545
|
4
|
|
|
|
|
7
|
my @valid_actions = qw{ yes no ask/yes ask/no ask }; |
546
|
4
|
|
|
|
|
4
|
return grep { $action eq $_ } @valid_actions; |
|
20
|
|
|
|
|
32
|
|
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
sub _is_valid_grade { |
551
|
6
|
|
|
6
|
|
8
|
my $grade = shift; |
552
|
6
|
|
|
|
|
9
|
my @valid_grades = qw{ pass fail unknown na default }; |
553
|
6
|
|
|
|
|
10
|
return grep { $grade eq $_ } @valid_grades; |
|
30
|
|
|
|
|
55
|
|
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
557
|
|
|
|
|
|
|
# _validate |
558
|
|
|
|
|
|
|
# |
559
|
|
|
|
|
|
|
# anything is OK if there is no validation subroutine |
560
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
sub _validate { |
563
|
0
|
|
|
0
|
|
0
|
my ($self, $name, $value) = @_; |
564
|
0
|
|
|
|
|
0
|
my $specs = $self->_config_spec; |
565
|
0
|
0
|
|
|
|
0
|
return 1 if ! exists $specs->{$name}{validate}; |
566
|
0
|
|
|
|
|
0
|
return $specs->{$name}{validate}->($self, $name, $value); |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
570
|
|
|
|
|
|
|
# _validate_grade_action |
571
|
|
|
|
|
|
|
# returns hash of grade => action |
572
|
|
|
|
|
|
|
# returns undef |
573
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub _validate_grade_action_pair { |
576
|
2
|
|
|
2
|
|
5
|
my ($self, $name, $option) = @_; |
577
|
2
|
|
50
|
|
|
4
|
$option ||= 'no'; |
578
|
|
|
|
|
|
|
|
579
|
2
|
|
|
|
|
2
|
my %ga_map; # grade => action |
580
|
|
|
|
|
|
|
|
581
|
2
|
|
|
|
|
5
|
PAIR: for my $grade_action ( split q{ }, $option ) { |
582
|
4
|
|
|
|
|
7
|
my ($grade_list,$action); |
583
|
4
|
50
|
|
|
|
13
|
if ( $grade_action =~ m{.:.} ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
584
|
|
|
|
|
|
|
# parse pair for later check |
585
|
4
|
|
|
|
|
14
|
($grade_list, $action) = $grade_action =~ m{\A([^:]+):(.+)\z}; |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
elsif ( _is_valid_action($grade_action) ) { |
588
|
|
|
|
|
|
|
# action by itself |
589
|
0
|
|
|
|
|
0
|
$ga_map{default} = $grade_action; |
590
|
0
|
|
|
|
|
0
|
next PAIR; |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
elsif ( _is_valid_grade($grade_action) ) { |
593
|
|
|
|
|
|
|
# grade by itself |
594
|
0
|
|
|
|
|
0
|
$ga_map{$grade_action} = 'yes'; |
595
|
0
|
|
|
|
|
0
|
next PAIR; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
elsif( $grade_action =~ m{./.} ) { |
598
|
|
|
|
|
|
|
# gradelist by itself, so setup for later check |
599
|
0
|
|
|
|
|
0
|
$grade_list = $grade_action; |
600
|
0
|
|
|
|
|
0
|
$action = 'yes'; |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
else { |
603
|
|
|
|
|
|
|
# something weird, so warn and skip |
604
|
0
|
|
|
|
|
0
|
$self->mywarn( |
605
|
|
|
|
|
|
|
"\nignoring invalid grade:action '$grade_action' for '$name'.\n\n" |
606
|
|
|
|
|
|
|
); |
607
|
0
|
|
|
|
|
0
|
next PAIR; |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
# check gradelist |
611
|
4
|
|
|
|
|
9
|
my %grades = map { ($_,1) } split( "/", $grade_list); |
|
6
|
|
|
|
|
15
|
|
612
|
4
|
|
|
|
|
9
|
for my $g ( keys %grades ) { |
613
|
6
|
50
|
|
|
|
11
|
if ( ! _is_valid_grade($g) ) { |
614
|
0
|
|
|
|
|
0
|
$self->mywarn( |
615
|
|
|
|
|
|
|
"\nignoring invalid grade '$g' in '$grade_action' for '$name'.\n\n" |
616
|
|
|
|
|
|
|
); |
617
|
0
|
|
|
|
|
0
|
delete $grades{$g}; |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# check action |
622
|
4
|
50
|
|
|
|
8
|
if ( ! _is_valid_action($action) ) { |
623
|
0
|
|
|
|
|
0
|
$self->mywarn( |
624
|
|
|
|
|
|
|
"\nignoring invalid action '$action' in '$grade_action' for '$name'.\n\n" |
625
|
|
|
|
|
|
|
); |
626
|
0
|
|
|
|
|
0
|
next PAIR; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
# otherwise, it all must be OK |
630
|
4
|
|
|
|
|
13
|
$ga_map{$_} = $action for keys %grades; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
2
|
50
|
|
|
|
10
|
return scalar(keys %ga_map) ? \%ga_map : undef; |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
sub _validate_transport { |
637
|
1
|
|
|
1
|
|
3
|
my ($self, $name, $option, $config) = @_; |
638
|
1
|
50
|
|
|
|
3
|
$config = $self->_config_data unless $config; |
639
|
1
|
|
|
|
|
1
|
my $transport = ''; |
640
|
1
|
|
|
|
|
2
|
my $transport_args = ''; |
641
|
|
|
|
|
|
|
|
642
|
1
|
50
|
|
|
|
5
|
if ( $option =~ /^(\w+(?:::\w+)*)\s*(\S.*)$/ ) { |
643
|
1
|
|
|
|
|
4
|
($transport, $transport_args) = ($1, $2); |
644
|
1
|
|
|
|
|
2
|
my $full_class = "Test::Reporter::Transport::$transport"; |
645
|
1
|
|
|
1
|
|
65
|
eval "use $full_class ()"; |
|
1
|
|
|
|
|
156
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
646
|
1
|
50
|
|
|
|
4
|
if ($@) { |
647
|
1
|
|
|
|
|
5
|
$self->mywarn( |
648
|
|
|
|
|
|
|
"\nerror loading $full_class. Please install the missing module or choose a different transport mechanism.\n\n" |
649
|
|
|
|
|
|
|
); |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
else { |
653
|
0
|
|
|
|
|
0
|
$self->mywarn( |
654
|
|
|
|
|
|
|
"\nPlease provide a transport mechanism.\n\n" |
655
|
|
|
|
|
|
|
); |
656
|
0
|
|
|
|
|
0
|
return; |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
# we do extra validation for Metabase and offer to create the profile |
660
|
1
|
50
|
|
|
|
241
|
if ( $transport eq 'Metabase' ) { |
661
|
1
|
50
|
|
|
|
6
|
unless ( $transport_args =~ /\buri\s+\S+/ ) { |
662
|
0
|
|
|
|
|
0
|
$self->mywarn( |
663
|
|
|
|
|
|
|
"\nPlease provide a target uri.\n\n" |
664
|
|
|
|
|
|
|
); |
665
|
0
|
|
|
|
|
0
|
return; |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
|
668
|
1
|
50
|
|
|
|
6
|
unless ( $transport_args =~ /\bid_file\s+(\S.+?)\s*$/ ) { |
669
|
0
|
|
|
|
|
0
|
$self->mywarn( |
670
|
|
|
|
|
|
|
"\nPlease specify an id_file path.\n\n" |
671
|
|
|
|
|
|
|
); |
672
|
0
|
|
|
|
|
0
|
return; |
673
|
|
|
|
|
|
|
} |
674
|
|
|
|
|
|
|
|
675
|
1
|
|
|
|
|
3
|
my $id_file = $self->_normalize_id_file($1); |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
# Offer to create if it doesn't exist |
678
|
1
|
50
|
|
|
|
27
|
if ( ! -e $id_file ) { |
|
|
50
|
|
|
|
|
|
679
|
0
|
0
|
|
|
|
0
|
return unless $self->_has_prompt; # skip unless we have a prompt! |
680
|
|
|
|
|
|
|
|
681
|
0
|
|
|
|
|
0
|
my $answer = $self->myprompt( |
682
|
|
|
|
|
|
|
"\nWould you like to run 'metabase-profile' now to create '$id_file'?", "y" |
683
|
|
|
|
|
|
|
); |
684
|
0
|
0
|
|
|
|
0
|
if ( $answer =~ /^y/i ) { |
685
|
0
|
0
|
|
|
|
0
|
return unless _generate_profile( $id_file, $config->{email_from} ); |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
else { |
688
|
0
|
|
|
|
|
0
|
$self->mywarn( <<"END_ID_FILE" ); |
689
|
|
|
|
|
|
|
You can create a Metabase profile by typing 'metabase-profile' in your |
690
|
|
|
|
|
|
|
command prompt and moving the resulting file to the location you specified. |
691
|
|
|
|
|
|
|
If you did not specify an absolute path, put it in your .cpanreporter |
692
|
|
|
|
|
|
|
directory. You will need to do this before continuing. |
693
|
|
|
|
|
|
|
END_ID_FILE |
694
|
0
|
|
|
|
|
0
|
return; |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
# Warn and fail validation if there but not readable |
698
|
|
|
|
|
|
|
elsif (! -r $id_file) { |
699
|
0
|
|
|
|
|
0
|
$self->mywarn( |
700
|
|
|
|
|
|
|
"'$id_file' was not readable.\n\n" |
701
|
|
|
|
|
|
|
); |
702
|
0
|
|
|
|
|
0
|
return; |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
# when we store the transport args internally, |
706
|
|
|
|
|
|
|
# we should use the normalized id_file |
707
|
|
|
|
|
|
|
# (always quoted to support spaces). |
708
|
|
|
|
|
|
|
# Since _normalize_id_file removed '\' from the path in order |
709
|
|
|
|
|
|
|
# to test the real file path, we now need to put them back if we |
710
|
|
|
|
|
|
|
# have them, as _parse_transport_args expects '\\' instead of '\': |
711
|
1
|
|
|
|
|
3
|
$id_file =~ s/\\/\\\\/g; |
712
|
1
|
|
|
|
|
9
|
$transport_args =~ s/(\bid_file\s+)(\S.+?)\s*$/$1"$id_file"/; |
713
|
|
|
|
|
|
|
} # end Metabase |
714
|
|
|
|
|
|
|
|
715
|
1
|
|
|
|
|
3
|
$self->{_transport_name} = $transport; |
716
|
1
|
|
|
|
|
2
|
$self->{_transport_args} = _parse_transport_args($transport_args); |
717
|
1
|
|
|
|
|
4
|
return 1; |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
# converts a string into a list of arguments for the transport module. |
721
|
|
|
|
|
|
|
# arguments are separated by spaces. If an argument has space, enclose it |
722
|
|
|
|
|
|
|
# using ' or ". |
723
|
|
|
|
|
|
|
sub _parse_transport_args { |
724
|
7
|
|
|
7
|
|
477
|
my ($transport_args) = @_; |
725
|
7
|
|
|
|
|
11
|
my @args; |
726
|
7
|
|
|
|
|
37
|
while ($transport_args =~ /\s*((?:[^'"\s]\S*)|(["'])(?:(?>\\?).)*?\2)/g) { |
727
|
29
|
|
|
|
|
47
|
my $arg = $1; |
728
|
29
|
100
|
|
|
|
54
|
if ($2) { |
729
|
12
|
|
|
|
|
40
|
$arg =~ s/\A(['"])(.+)\1\z/$2/; |
730
|
12
|
|
|
|
|
23
|
$arg =~ s/\\(.)/$1/g; |
731
|
|
|
|
|
|
|
} |
732
|
29
|
|
|
|
|
99
|
push @args, $arg; |
733
|
|
|
|
|
|
|
} |
734
|
7
|
|
|
|
|
38
|
return \@args; |
735
|
|
|
|
|
|
|
} |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
sub _validate_seconds { |
738
|
0
|
|
|
0
|
|
0
|
my ($self, $name, $option) = @_; |
739
|
0
|
0
|
0
|
|
|
0
|
return unless defined($option) && length($option) |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
740
|
|
|
|
|
|
|
&& ($option =~ /^\d/) && $option >= 0; |
741
|
0
|
|
|
|
|
0
|
return $option; |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
sub _validate_skipfile { |
745
|
0
|
|
|
0
|
|
0
|
my ($self, $name, $option) = @_; |
746
|
0
|
0
|
|
|
|
0
|
return unless $option; |
747
|
0
|
0
|
|
|
|
0
|
my $skipfile = File::Spec->file_name_is_absolute( $option ) |
748
|
|
|
|
|
|
|
? $option : File::Spec->catfile( get_config_dir(), $option ); |
749
|
0
|
0
|
|
|
|
0
|
return -r $skipfile ? $skipfile : undef; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
# not really a validation, just making sure |
753
|
|
|
|
|
|
|
# it's not empty and contains a '@' |
754
|
|
|
|
|
|
|
sub _validate_email { |
755
|
1
|
|
|
1
|
|
2
|
my ($self, $name, $option) = @_; |
756
|
1
|
50
|
|
|
|
3
|
return unless $option; |
757
|
1
|
|
|
|
|
3
|
my @data = split '@', $option; |
758
|
1
|
50
|
|
|
|
12
|
return $option if scalar @data == 2; |
759
|
|
|
|
|
|
|
} |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
1; |
763
|
|
|
|
|
|
|
__END__ |