line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::DependentModules; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
176101
|
use strict; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
30
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
24
|
|
5
|
1
|
|
|
1
|
|
526
|
use autodie; |
|
1
|
|
|
|
|
14463
|
|
|
1
|
|
|
|
|
4
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.27'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# CPAN::Reporter spits out random output we don't want, and we don't want to |
10
|
|
|
|
|
|
|
# report these tests anyway. |
11
|
|
|
|
|
|
|
BEGIN { |
12
|
|
|
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars) |
13
|
1
|
|
|
1
|
|
6819
|
$INC{'CPAN/Reporter.pm'} = 0; |
14
|
|
|
|
|
|
|
} |
15
|
|
|
|
|
|
|
|
16
|
1
|
|
|
1
|
|
575
|
use Capture::Tiny qw( capture ); |
|
1
|
|
|
|
|
24810
|
|
|
1
|
|
|
|
|
62
|
|
17
|
1
|
|
|
1
|
|
8
|
use Cwd qw( abs_path ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
18
|
1
|
|
|
1
|
|
5
|
use Exporter qw( import ); |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
25
|
|
19
|
1
|
|
|
1
|
|
5
|
use File::Path qw( rmtree ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
35
|
|
20
|
1
|
|
|
1
|
|
5
|
use File::Spec; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
19
|
|
21
|
1
|
|
|
1
|
|
5
|
use File::Temp qw( tempdir ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
33
|
|
22
|
1
|
|
|
1
|
|
6
|
use File::chdir; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
93
|
|
23
|
1
|
|
|
1
|
|
582
|
use IO::Handle::Util qw( io_from_write_cb ); |
|
1
|
|
|
|
|
15961
|
|
|
1
|
|
|
|
|
7
|
|
24
|
1
|
|
|
1
|
|
816
|
use IPC::Run3 qw( run3 ); |
|
1
|
|
|
|
|
4941
|
|
|
1
|
|
|
|
|
77
|
|
25
|
1
|
|
|
1
|
|
509
|
use Log::Dispatch; |
|
1
|
|
|
|
|
226734
|
|
|
1
|
|
|
|
|
41
|
|
26
|
1
|
|
|
1
|
|
493
|
use MetaCPAN::Client; |
|
1
|
|
|
|
|
323624
|
|
|
1
|
|
|
|
|
36
|
|
27
|
1
|
|
|
1
|
|
19
|
use Test::Builder; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
25
|
|
28
|
1
|
|
|
1
|
|
5
|
use Try::Tiny; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2760
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
our @EXPORT_OK = qw( test_all_dependents test_module test_modules ); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars) |
33
|
|
|
|
|
|
|
$ENV{PERL5LIB} = join q{:}, ( $ENV{PERL5LIB} || q{} ), |
34
|
|
|
|
|
|
|
File::Spec->catdir( _temp_lib_dir(), 'lib', 'perl5' ); |
35
|
|
|
|
|
|
|
$ENV{PERL_AUTOINSTALL} = '--defaultdeps'; |
36
|
|
|
|
|
|
|
$ENV{PERL_MM_USE_DEFAULT} = 1; |
37
|
|
|
|
|
|
|
## use critic |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my $Test = Test::Builder->new; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub test_all_dependents { |
42
|
0
|
|
|
0
|
1
|
0
|
my $module = shift; |
43
|
0
|
|
|
|
|
0
|
my $params = shift; |
44
|
|
|
|
|
|
|
|
45
|
0
|
|
|
|
|
0
|
_load_cpan(); |
46
|
0
|
|
|
|
|
0
|
_make_logs(); |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
|
|
|
0
|
my @deps = _get_deps( $module, $params ); |
49
|
0
|
0
|
|
|
|
0
|
unless (@deps) { |
50
|
0
|
|
|
|
|
0
|
$Test->plan( |
51
|
|
|
|
|
|
|
skip_all => "Could not find any distros that depend on $module" ); |
52
|
0
|
|
|
|
|
0
|
return 0; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
0
|
$Test->plan( tests => scalar @deps ); |
56
|
|
|
|
|
|
|
|
57
|
0
|
|
|
|
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
58
|
0
|
|
|
|
|
0
|
test_modules(@deps); |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub _get_deps { |
62
|
0
|
|
|
0
|
|
0
|
my $module = shift; |
63
|
0
|
|
|
|
|
0
|
my $params = shift; |
64
|
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
0
|
$module =~ s/::/-/g; |
66
|
|
|
|
|
|
|
|
67
|
0
|
|
|
|
|
0
|
my $rev_deps = MetaCPAN::Client->new->rev_deps($module); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
my $allow |
70
|
|
|
|
|
|
|
= $params->{filter} ? $params->{filter} |
71
|
0
|
|
|
0
|
|
0
|
: $params->{exclude} ? sub { $_[0] !~ /$params->{exclude}/ } |
72
|
0
|
0
|
|
0
|
|
0
|
: sub {1}; |
|
0
|
0
|
|
|
|
0
|
|
73
|
|
|
|
|
|
|
|
74
|
0
|
|
|
|
|
0
|
my @deps; |
75
|
0
|
|
|
|
|
0
|
while ( my $dep = $rev_deps->next ) { |
76
|
0
|
|
|
|
|
0
|
my $dist = $dep->distribution; |
77
|
|
|
|
|
|
|
|
78
|
0
|
0
|
|
|
|
0
|
next unless $allow->($dist); |
79
|
0
|
0
|
|
|
|
0
|
next if $dist =~ /^(?:Task|Bundle)/; |
80
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
0
|
push @deps => $dist; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
## no critic (Subroutines::ProhibitReturnSort) |
85
|
0
|
|
|
|
|
0
|
return sort { lc $a cmp lc $b } @deps; |
|
0
|
|
|
|
|
0
|
|
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub test_modules { |
89
|
0
|
|
|
0
|
1
|
0
|
_load_cpan(); |
90
|
0
|
|
|
|
|
0
|
_make_logs(); |
91
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
0
|
my $parallel = 0; |
93
|
0
|
0
|
0
|
|
|
0
|
if ( $ENV{PERL_TEST_DM_PROCESSES} |
94
|
|
|
|
|
|
|
&& $ENV{PERL_TEST_DM_PROCESSES} > 1 ) { |
95
|
|
|
|
|
|
|
|
96
|
0
|
0
|
|
|
|
0
|
if ( eval { require Parallel::ForkManager; 1; } ) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
97
|
0
|
|
|
|
|
0
|
$parallel = 1; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
else { |
100
|
0
|
|
|
|
|
0
|
warn |
101
|
|
|
|
|
|
|
'Cannot run multiple processes without the Parallel::ForkManager module.'; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
0
|
0
|
|
|
|
0
|
if ($parallel) { |
106
|
0
|
|
|
|
|
0
|
_test_in_parallel(@_); |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
else { |
109
|
0
|
|
|
|
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
110
|
0
|
|
|
|
|
0
|
for my $module (@_) { |
111
|
0
|
|
|
|
|
0
|
test_module($module); |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub _test_in_parallel { |
117
|
0
|
|
|
0
|
|
0
|
my @modules = @_; |
118
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
0
|
my $pm = Parallel::ForkManager->new( $ENV{PERL_TEST_DM_PROCESSES} ); |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
$pm->run_on_finish( |
122
|
|
|
|
|
|
|
sub { |
123
|
0
|
|
|
0
|
|
0
|
shift; # pid |
124
|
0
|
|
|
|
|
0
|
shift; # program exit code |
125
|
0
|
|
|
|
|
0
|
shift; # ident |
126
|
0
|
|
|
|
|
0
|
shift; # exit signal |
127
|
0
|
|
|
|
|
0
|
shift; # core dump |
128
|
0
|
|
|
|
|
0
|
my $results = shift; |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
131
|
0
|
|
|
|
|
0
|
_test_report($results); |
132
|
|
|
|
|
|
|
} |
133
|
0
|
|
|
|
|
0
|
); |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
0
|
for my $module (@_) { |
136
|
0
|
0
|
|
|
|
0
|
$pm->start and next; |
137
|
|
|
|
|
|
|
|
138
|
0
|
|
|
|
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
139
|
0
|
|
|
|
|
0
|
test_module( $module, $pm ); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
0
|
$pm->wait_all_children; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub test_module { |
146
|
0
|
|
|
0
|
1
|
0
|
my $name = shift; |
147
|
0
|
|
|
|
|
0
|
my $pm = shift; |
148
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
0
|
_load_cpan(); |
150
|
0
|
|
|
|
|
0
|
_make_logs(); |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
0
|
$name =~ s/-/::/g; |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
0
|
my $dist = _get_distro($name); |
155
|
0
|
0
|
|
|
|
0
|
unless ($dist) { |
156
|
0
|
|
|
|
|
0
|
_finish_test( |
157
|
|
|
|
|
|
|
$pm, |
158
|
|
|
|
|
|
|
{ |
159
|
|
|
|
|
|
|
name => $name, |
160
|
|
|
|
|
|
|
skipped => qq{Could't find a distro for $name}, |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
); |
163
|
0
|
|
|
|
|
0
|
return; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
0
|
$Test->diag( 'Testing ' . $dist->base_id ); |
167
|
|
|
|
|
|
|
|
168
|
0
|
0
|
|
|
|
0
|
unless ($dist) { |
169
|
0
|
|
|
|
|
0
|
$name =~ s/::/-/g; |
170
|
0
|
0
|
|
|
|
0
|
my $todo |
171
|
|
|
|
|
|
|
= defined( $Test->todo ) |
172
|
|
|
|
|
|
|
? ' (TODO: ' . $Test->todo . ')' |
173
|
|
|
|
|
|
|
: q{}; |
174
|
0
|
|
|
|
|
0
|
my $summary = "FAIL${todo}: $name - ??? - ???"; |
175
|
0
|
|
|
|
|
0
|
my $output = "Could not find $name on CPAN\n"; |
176
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
0
|
_finish_test( |
178
|
|
|
|
|
|
|
$pm, { |
179
|
|
|
|
|
|
|
name => $name, |
180
|
|
|
|
|
|
|
passed => 0, |
181
|
|
|
|
|
|
|
summary => $summary, |
182
|
|
|
|
|
|
|
output => $output, |
183
|
|
|
|
|
|
|
stderr => $output, |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
); |
186
|
0
|
|
|
|
|
0
|
return; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
0
|
$name = $dist->base_id; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
my $success = try { |
192
|
0
|
|
|
0
|
|
0
|
capture { _install_prereqs($dist) }; |
|
0
|
|
|
|
|
0
|
|
193
|
0
|
|
|
|
|
0
|
1; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
catch { |
196
|
0
|
|
|
0
|
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
197
|
0
|
|
|
|
|
0
|
my $msg = "Installing prereqs for $name failed: $_"; |
198
|
0
|
|
|
|
|
0
|
$msg =~ s/\s*$//; |
199
|
0
|
|
|
|
|
0
|
$msg =~ s/\n/\t/g; |
200
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
0
|
_finish_test( |
202
|
|
|
|
|
|
|
$pm, |
203
|
|
|
|
|
|
|
, { |
204
|
|
|
|
|
|
|
name => $name, |
205
|
|
|
|
|
|
|
skipped => $msg, |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
); |
208
|
0
|
|
|
|
|
0
|
return; |
209
|
0
|
|
|
|
|
0
|
}; |
210
|
|
|
|
|
|
|
|
211
|
0
|
0
|
|
|
|
0
|
return unless $success; |
212
|
|
|
|
|
|
|
|
213
|
0
|
|
|
|
|
0
|
my ( $passed, $output, $stderr ) = _run_tests_for_dir( $dist->dir ); |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# A lot of modules seem to have cargo-culted a diag() that looks like this |
216
|
|
|
|
|
|
|
# ... |
217
|
|
|
|
|
|
|
# |
218
|
|
|
|
|
|
|
# Testing Foo::Bar 0.01, Perl 5.00801, /usr/bin/perl |
219
|
0
|
0
|
0
|
|
|
0
|
$stderr = q{} |
220
|
|
|
|
|
|
|
if defined $stderr && $stderr =~ /\A\# Testing [\w:]+ [^\n]+\Z/; |
221
|
|
|
|
|
|
|
|
222
|
0
|
0
|
0
|
|
|
0
|
my $status = $passed && $stderr ? 'WARN' : $passed ? 'PASS' : 'FAIL'; |
|
|
0
|
|
|
|
|
|
223
|
0
|
0
|
|
|
|
0
|
if ( my $reason = $Test->todo ) { |
224
|
0
|
|
|
|
|
0
|
$status .= " (TODO: $reason)"; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
0
|
my $summary |
228
|
|
|
|
|
|
|
= "$status: $name - " . $dist->base_id . ' - ' . $dist->author->id; |
229
|
|
|
|
|
|
|
|
230
|
0
|
|
|
|
|
0
|
_finish_test( |
231
|
|
|
|
|
|
|
$pm, |
232
|
|
|
|
|
|
|
{ |
233
|
|
|
|
|
|
|
name => $name, |
234
|
|
|
|
|
|
|
passed => $passed, |
235
|
|
|
|
|
|
|
summary => $summary, |
236
|
|
|
|
|
|
|
output => $output, |
237
|
|
|
|
|
|
|
stderr => $stderr, |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub _finish_test { |
243
|
0
|
|
|
0
|
|
0
|
my $pm = shift; |
244
|
0
|
|
|
|
|
0
|
my $results = shift; |
245
|
|
|
|
|
|
|
|
246
|
0
|
0
|
|
|
|
0
|
if ($pm) { |
247
|
0
|
|
|
|
|
0
|
$pm->finish( 0, $results ); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
else { |
250
|
0
|
|
|
|
|
0
|
local $Test::Builder::Level = $Test::Builder::Level + 2; |
251
|
0
|
|
|
|
|
0
|
_test_report($results); |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
## no critic (Subroutines::ProhibitManyArgs) |
256
|
|
|
|
|
|
|
sub _test_report { |
257
|
0
|
|
|
0
|
|
0
|
my $results = shift; |
258
|
|
|
|
|
|
|
|
259
|
0
|
0
|
|
|
|
0
|
if ( $results->{skipped} ) { |
260
|
0
|
|
|
|
|
0
|
_status_log("UNKNOWN: $results->{name} ($results->{skipped})\n"); |
261
|
0
|
|
|
|
|
0
|
_error_log("UNKNOWN: $results->{name} ($results->{skipped})\n"); |
262
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
0
|
$Test->diag("Skipping $results->{name}: $results->{skipped}"); |
264
|
0
|
|
|
|
|
0
|
$Test->skip( $results->{skipped} ); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
else { |
267
|
0
|
|
|
|
|
0
|
_status_log("$results->{summary}\n"); |
268
|
0
|
|
|
|
|
0
|
_error_log("$results->{summary}\n"); |
269
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
0
|
$Test->ok( $results->{passed}, "$results->{name} passed all tests" ); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
0
|
0
|
0
|
|
|
0
|
if ( $results->{passed} || $results->{skipped} ) { |
274
|
0
|
|
|
|
|
0
|
_error_log("\n"); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
else { |
277
|
0
|
|
|
|
|
0
|
_error_log( q{-} x 50 ); |
278
|
0
|
|
|
|
|
0
|
_error_log("\n"); |
279
|
0
|
0
|
|
|
|
0
|
_error_log("$results->{output}\n") if defined $results->{output}; |
280
|
0
|
0
|
|
|
|
0
|
_error_log("$results->{stderr}\n") if defined $results->{stderr}; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
{ |
285
|
|
|
|
|
|
|
my %logs; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub _make_logs { |
288
|
0
|
0
|
|
0
|
|
0
|
return if %logs; |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
my $file_class = $ENV{PERL_TEST_DM_PROCESSES} |
291
|
0
|
0
|
0
|
|
|
0
|
&& $ENV{PERL_TEST_DM_PROCESSES} > 1 ? 'File::Locked' : 'File'; |
292
|
|
|
|
|
|
|
|
293
|
0
|
|
|
|
|
0
|
for my $type (qw( status error prereq )) { |
294
|
0
|
|
|
|
|
0
|
$logs{$type} = Log::Dispatch->new( |
295
|
|
|
|
|
|
|
outputs => [ |
296
|
|
|
|
|
|
|
[ |
297
|
|
|
|
|
|
|
$file_class, |
298
|
|
|
|
|
|
|
min_level => 'debug', |
299
|
|
|
|
|
|
|
filename => _log_filename($type), |
300
|
|
|
|
|
|
|
mode => 'append', |
301
|
|
|
|
|
|
|
], |
302
|
|
|
|
|
|
|
], |
303
|
|
|
|
|
|
|
); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub _status_log { |
308
|
0
|
|
|
0
|
|
0
|
$logs{status}->info(@_); |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub _error_log { |
312
|
0
|
|
|
0
|
|
0
|
$logs{error}->info(@_); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub _prereq_log { |
316
|
0
|
|
|
0
|
|
0
|
$logs{prereq}->info(@_); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub _log_filename { |
321
|
0
|
|
|
0
|
|
0
|
my $type = shift; |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
return File::Spec->devnull |
324
|
0
|
0
|
|
|
|
0
|
unless $ENV{PERL_TEST_DM_LOG_DIR}; |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
return File::Spec->catfile( |
327
|
|
|
|
|
|
|
$ENV{PERL_TEST_DM_LOG_DIR}, |
328
|
0
|
|
|
|
|
0
|
'test-mydeps-' . $$ . q{-} . $type . '.log' |
329
|
|
|
|
|
|
|
); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub _get_distro { |
333
|
0
|
|
|
0
|
|
0
|
my $name = shift; |
334
|
|
|
|
|
|
|
|
335
|
0
|
|
|
|
|
0
|
my @mods = CPAN::Shell->expand( 'Module', $name ); |
336
|
|
|
|
|
|
|
|
337
|
0
|
0
|
|
|
|
0
|
return unless @mods == 1; |
338
|
|
|
|
|
|
|
|
339
|
0
|
|
|
|
|
0
|
my $dist = $mods[0]->distribution; |
340
|
|
|
|
|
|
|
|
341
|
0
|
0
|
|
|
|
0
|
return unless $dist; |
342
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
0
|
$dist->get; |
344
|
|
|
|
|
|
|
|
345
|
0
|
|
|
|
|
0
|
return $dist; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub _install_prereqs { |
349
|
0
|
|
|
0
|
|
0
|
my $dist = shift; |
350
|
0
|
|
0
|
|
|
0
|
my $root_dist = shift || $dist->base_id; |
351
|
|
|
|
|
|
|
|
352
|
0
|
|
|
|
|
0
|
my $install_dir = _temp_lib_dir(); |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
## no critic (Variables::RequireInitializationForLocalVars, Variables::ProhibitPackageVars) |
355
|
0
|
|
|
|
|
0
|
local $CPAN::Config->{makepl_arg} .= " INSTALL_BASE=$install_dir"; |
356
|
|
|
|
|
|
|
local $CPAN::Config->{mbuild_install_arg} |
357
|
0
|
|
|
|
|
0
|
.= " --install_base $install_dir"; |
358
|
|
|
|
|
|
|
## use critic |
359
|
|
|
|
|
|
|
|
360
|
0
|
|
|
|
|
0
|
my $for_dist = $dist->base_id; |
361
|
|
|
|
|
|
|
|
362
|
0
|
|
|
|
|
0
|
for my $prereq ( $dist->unsat_prereq('configure_requires_later') ) { |
363
|
0
|
|
|
|
|
0
|
_install_prereq( $prereq->[0], $for_dist, $root_dist ); |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
0
|
|
|
|
|
0
|
$dist->undelay; |
367
|
0
|
|
|
|
|
0
|
$dist->make; |
368
|
|
|
|
|
|
|
|
369
|
0
|
|
|
|
|
0
|
for my $prereq ( $dist->unsat_prereq('later') ) { |
370
|
0
|
|
|
|
|
0
|
_install_prereq( $prereq->[0], $for_dist, $root_dist ); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
0
|
$dist->undelay; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub _install_prereq { |
377
|
0
|
|
|
0
|
|
0
|
my $prereq = shift; |
378
|
0
|
|
|
|
|
0
|
my $for_dist = shift; |
379
|
0
|
|
|
|
|
0
|
my $root_dist = shift; |
380
|
|
|
|
|
|
|
|
381
|
0
|
0
|
|
|
|
0
|
return if $prereq eq 'perl'; |
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
0
|
my $for = "for $for_dist"; |
384
|
0
|
0
|
|
|
|
0
|
if ( $for_dist ne $root_dist ) { |
385
|
0
|
|
|
|
|
0
|
$for .= " (started with $root_dist)"; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
0
|
my $dist = _get_distro($prereq); |
389
|
0
|
0
|
|
|
|
0
|
if ( !$dist ) { |
390
|
0
|
|
|
|
|
0
|
_prereq_log("Couldn't find $prereq $for\n"); |
391
|
0
|
|
|
|
|
0
|
next; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
0
|
|
|
|
|
0
|
_install_prereqs( $dist, $root_dist ); |
395
|
|
|
|
|
|
|
|
396
|
0
|
|
|
|
|
0
|
my $installing = $dist->base_id; |
397
|
|
|
|
|
|
|
|
398
|
0
|
|
|
|
|
0
|
_prereq_log("Installing $installing $for\n"); |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
try { |
401
|
0
|
|
|
0
|
|
0
|
$dist->notest; |
402
|
0
|
|
|
|
|
0
|
$dist->install; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
catch { |
405
|
0
|
|
|
0
|
|
0
|
die "Installing $installing for $for_dist failed: $_"; |
406
|
0
|
|
|
|
|
0
|
}; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
{ |
410
|
|
|
|
|
|
|
my $Dir; |
411
|
1
|
|
|
1
|
|
15
|
BEGIN { $Dir = tempdir( CLEANUP => 1 ); } |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
sub _temp_lib_dir { |
414
|
1
|
|
|
1
|
|
23
|
return $Dir; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub _run_tests_for_dir { |
419
|
7
|
|
|
7
|
|
1512730
|
my $dir = shift; |
420
|
|
|
|
|
|
|
|
421
|
7
|
|
|
|
|
397
|
local $CWD = $dir; |
422
|
|
|
|
|
|
|
|
423
|
7
|
100
|
|
|
|
1321
|
if ( -e 'Build.PL' ) { |
424
|
|
|
|
|
|
|
return |
425
|
4
|
50
|
|
|
|
104
|
unless _run_commands( |
426
|
|
|
|
|
|
|
['./Build'], |
427
|
|
|
|
|
|
|
); |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
else { |
430
|
|
|
|
|
|
|
return |
431
|
3
|
50
|
|
|
|
94
|
unless _run_commands( |
432
|
|
|
|
|
|
|
['make'], |
433
|
|
|
|
|
|
|
); |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
|
436
|
7
|
|
|
|
|
214
|
return _run_tests(); |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub _run_commands { |
440
|
7
|
|
|
7
|
|
87
|
for my $cmd (@_) { |
441
|
7
|
|
|
|
|
42
|
my $output; |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
my $success = try { |
444
|
7
|
|
|
7
|
|
1606
|
run3( $cmd, \undef, \$output, \$output ); |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
catch { |
447
|
0
|
|
|
0
|
|
0
|
$output .= "Couldn't run @$cmd: $_"; |
448
|
0
|
|
|
|
|
0
|
return; |
449
|
7
|
|
|
|
|
534
|
}; |
450
|
|
|
|
|
|
|
|
451
|
7
|
50
|
|
|
|
1984094
|
return ( 0, $output ) |
452
|
|
|
|
|
|
|
unless $success; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
7
|
|
|
|
|
190
|
return 1; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub _run_tests { |
459
|
7
|
|
|
7
|
|
61
|
my $output = q{}; |
460
|
7
|
|
|
|
|
28
|
my $error = q{}; |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
my $stderr = sub { |
463
|
6
|
|
|
6
|
|
782546
|
my $line = shift; |
464
|
|
|
|
|
|
|
|
465
|
6
|
|
|
|
|
35
|
$output .= $line; |
466
|
6
|
|
|
|
|
137
|
$error .= $line; |
467
|
7
|
|
|
|
|
135
|
}; |
468
|
|
|
|
|
|
|
|
469
|
7
|
|
|
|
|
71
|
my $cmd; |
470
|
7
|
100
|
|
|
|
370
|
if ( -e 'Build' ) { |
|
|
50
|
|
|
|
|
|
471
|
4
|
|
|
|
|
46
|
$cmd = [qw( ./Build test )]; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
elsif ( -e 'Makefile' ) { |
474
|
3
|
|
|
|
|
51
|
$cmd = [qw( make test )]; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
else { |
477
|
0
|
|
|
|
|
0
|
return ( 0, "Cannot find a Build or Makefile file in $CWD" ); |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
7
|
|
|
|
|
69
|
my $passed; |
481
|
|
|
|
|
|
|
try { |
482
|
7
|
|
|
7
|
|
1196
|
run3( $cmd, undef, \$output, $stderr ); |
483
|
7
|
100
|
|
|
|
2818496
|
if ( $? == 0 ) { |
484
|
6
|
|
33
|
|
|
497
|
$passed = $output eq q{} |
485
|
|
|
|
|
|
|
|| $output =~ /Result: (?:PASS|NOTESTS)|No tests defined/; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
catch { |
489
|
0
|
|
|
0
|
|
0
|
$output .= "Couldn't run @$cmd: $_"; |
490
|
0
|
|
|
|
|
0
|
$error .= "Couldn't run @$cmd: $_"; |
491
|
7
|
|
|
|
|
399
|
}; |
492
|
|
|
|
|
|
|
|
493
|
7
|
|
|
|
|
1799
|
return ( $passed, $output, $error ); |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
{ |
497
|
|
|
|
|
|
|
my $LOADED_CPAN = 0; |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub _load_cpan { |
500
|
|
|
|
|
|
|
## no critic (TestingAndDebugging::ProhibitNoWarnings) |
501
|
1
|
|
|
1
|
|
1310
|
no warnings 'once'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
107
|
|
502
|
0
|
0
|
|
0
|
|
|
return if $LOADED_CPAN; |
503
|
|
|
|
|
|
|
|
504
|
0
|
|
|
|
|
|
require CPAN; |
505
|
0
|
|
|
|
|
|
require CPAN::Shell; |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
## no critic (InputOutput::RequireBriefOpen) |
508
|
0
|
|
|
|
|
|
open my $fh, '>', File::Spec->devnull; |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
{ |
511
|
1
|
|
|
1
|
|
7
|
no warnings 'redefine'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
396
|
|
|
0
|
|
|
|
|
|
|
512
|
0
|
|
|
0
|
|
|
*CPAN::Shell::report_fh = sub {$fh}; |
|
0
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
## no critic (Variables::ProhibitPackageVars) |
516
|
0
|
|
|
|
|
|
$CPAN::Be_Silent = 1; |
517
|
|
|
|
|
|
|
|
518
|
0
|
|
|
|
|
|
CPAN::HandleConfig->load; |
519
|
0
|
|
|
|
|
|
CPAN::Shell::setup_output(); |
520
|
0
|
|
|
|
|
|
CPAN::Index->reload('force'); |
521
|
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
|
$CPAN::Config->{test_report} = 0; |
523
|
0
|
|
|
|
|
|
$CPAN::Config->{mbuildpl_arg} .= ' --quiet'; |
524
|
0
|
|
|
|
|
|
$CPAN::Config->{prerequisites_policy} = 'follow'; |
525
|
0
|
|
|
|
|
|
$CPAN::Config->{make_install_make_command} =~ s/^sudo //; |
526
|
0
|
|
|
|
|
|
$CPAN::Config->{mbuild_install_build_command} =~ s/^sudo //; |
527
|
0
|
|
|
|
|
|
$CPAN::Config->{make_install_arg} =~ s/UNINST=1//; |
528
|
0
|
|
|
|
|
|
$CPAN::Config->{mbuild_install_arg} =~ s/--uninst\s+1//; |
529
|
|
|
|
|
|
|
|
530
|
0
|
0
|
|
|
|
|
if ( $ENV{PERL_TEST_DM_CPAN_VERBOSE} ) { |
531
|
0
|
|
|
0
|
|
|
$fh = io_from_write_cb( sub { $Test->diag( $_[0] ) } ); |
|
0
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
0
|
|
|
|
|
|
$LOADED_CPAN = 1; |
535
|
|
|
|
|
|
|
|
536
|
0
|
|
|
|
|
|
return; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
1; |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
# ABSTRACT: Test all modules which depend on your module |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
__END__ |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=pod |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=encoding UTF-8 |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=head1 NAME |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
Test::DependentModules - Test all modules which depend on your module |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head1 VERSION |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
version 0.27 |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
=head1 SYNOPSIS |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
use Test::DependentModules qw( test_all_dependents ); |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
test_all_dependents('My::Module'); |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# or ... |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
use Test::DependentModules qw( test_modules ); |
567
|
|
|
|
|
|
|
use Test::More tests => 3; |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
test_modules( 'Exception::Class', 'DateTime', 'Log::Dispatch' ); |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head1 DESCRIPTION |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
B<WARNING>: The tests this module does should B<never> be run as part of a |
574
|
|
|
|
|
|
|
normal CPAN install! |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
This module is intended as a tool for module authors who would like to easily |
577
|
|
|
|
|
|
|
test that a module release will not break dependencies. This is particularly |
578
|
|
|
|
|
|
|
useful for module authors (like myself) who have modules which are a |
579
|
|
|
|
|
|
|
dependency of many other modules. |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=head2 How It Works |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
Internally, this module will download dependencies from CPAN and run their |
584
|
|
|
|
|
|
|
tests. If those dependencies in turn have unsatisfied dependencies, they are |
585
|
|
|
|
|
|
|
installed into a temporary directory. These second-level (and third-, etc) |
586
|
|
|
|
|
|
|
dependencies are I<not> tested. |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
In order to avoid prompting, this module sets C<$ENV{PERL_AUTOINSTALL}> to |
589
|
|
|
|
|
|
|
C<--defaultdeps> and sets C<$ENV{PERL_MM_USE_DEFAULT}> to a true value. |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
Nonetheless, some ill-behaved modules will I<still> wait for a |
592
|
|
|
|
|
|
|
prompt. Unfortunately, because of the way this module attempts to keep output |
593
|
|
|
|
|
|
|
to a minimum, you won't see these prompts. Patches are welcome. |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=head2 Running Tests in Parallel |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
If you're testing a lot of modules, you might benefit from running tests in |
598
|
|
|
|
|
|
|
parallel. You'll need to have L<Parallel::ForkManager> installed for this to |
599
|
|
|
|
|
|
|
work. |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
Set the C<$ENV{PERL_TEST_DM_PROCESSES}> env var to a value greater than 1 to |
602
|
|
|
|
|
|
|
enable parallel testing. |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=head1 FUNCTIONS |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
This module optionally exports three functions: |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=head2 test_all_dependents( $module, { filter => sub { ... } } ) |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
Given a module or distro name, this function uses L<MetaCPAN::Client> to find |
611
|
|
|
|
|
|
|
all its dependencies and test them. It will set a test plan for you. |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
If you provide a C<filter> sub, it will be called with a single argument, the |
614
|
|
|
|
|
|
|
I<distribution name>, which will be something like "Test-DependentModules" |
615
|
|
|
|
|
|
|
(note the lack of colons). The filter should return a true or false value to |
616
|
|
|
|
|
|
|
indicate whether or not to test that distribution. |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
If you don't provide a filter, you can provide a regex to use by passing an |
619
|
|
|
|
|
|
|
C<exclude> key in the hashref. Anything that matches the regex is excluded. |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
Additionally, any distribution name starting with "Task" or "Bundle" is always |
622
|
|
|
|
|
|
|
excluded. |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head2 test_modules(@names) |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
Given a list of module names, this function will test them all. You can use |
627
|
|
|
|
|
|
|
this if you'd prefer to hard code a list of modules to test. |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
In this case, you will have to handle your own test planning. |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=head2 test_module($name) |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
B<DEPRECATED>. Use the C<test_modules()> sub instead, so you can optionally |
634
|
|
|
|
|
|
|
run tests in parallel. |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
Given a module name, this function will test it. You can use this if you'd |
637
|
|
|
|
|
|
|
prefer to hard code a list of modules to test. |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
In this case, you will have to handle your own test planning. |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=head1 PERL5LIB FOR DEPENDENCIES |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
If you want to include a module-to-be-released in the path seen by |
644
|
|
|
|
|
|
|
dependencies, you must make sure that the correct path ends up in |
645
|
|
|
|
|
|
|
C<$ENV{PERL5LIB}>. If you use C<prove -l> or C<prove -b> to run tests, then |
646
|
|
|
|
|
|
|
that will happen automatically. |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
=head1 WARNINGS, LOGGING AND VERBOSITY |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
By default, this module attempts to quiet down CPAN and the module building |
651
|
|
|
|
|
|
|
toolchain as much as possible. However, when there are test failures in a |
652
|
|
|
|
|
|
|
dependency it's nice to see the output. |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
In addition, if the tests spit out warnings but still pass, this will just be |
655
|
|
|
|
|
|
|
treated as a pass. |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
If you enable logging, this module log all successes, warnings, and failures, |
658
|
|
|
|
|
|
|
along with the full output of the test suite for each dependency. In addition, |
659
|
|
|
|
|
|
|
it logs what prereqs it installs, since you may want to install some of them |
660
|
|
|
|
|
|
|
permanently to speed up future tests. |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
To enable logging, you must provide a directory to which log files will be |
663
|
|
|
|
|
|
|
written. The log file names are of the form C<test-my-deps-$$-$type.log>, |
664
|
|
|
|
|
|
|
where C<$type> is one of "status", "error", or "prereq". |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
The directory should be provided in C<$ENV{PERL_TEST_DM_LOG_DIR}>. The |
667
|
|
|
|
|
|
|
directory must already exist. |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
You also can enable verbose output from the L<CPAN> package by setting the |
670
|
|
|
|
|
|
|
C<$ENV{PERL_TEST_DM_CPAN_VERBOSE}> variable to a true value. |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=head1 SUPPORT |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
Bugs may be submitted at L<http://rt.cpan.org/Public/Dist/Display.html?Name=Test-DependentModules> or via email to L<bug-test-dependentmodules@rt.cpan.org|mailto:bug-test-dependentmodules@rt.cpan.org>. |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head1 SOURCE |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
The source code repository for Test-DependentModules can be found at L<https://github.com/houseabsolute/Test-DependentModules>. |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=head1 DONATIONS |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
If you'd like to thank me for the work I've done on this module, please |
685
|
|
|
|
|
|
|
consider making a "donation" to me via PayPal. I spend a lot of free time |
686
|
|
|
|
|
|
|
creating free software, and would appreciate any support you'd care to offer. |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
Please note that B<I am not suggesting that you must do this> in order for me |
689
|
|
|
|
|
|
|
to continue working on this particular software. I will continue to do so, |
690
|
|
|
|
|
|
|
inasmuch as I have in the past, for as long as it interests me. |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
Similarly, a donation made in this way will probably not make me work on this |
693
|
|
|
|
|
|
|
software much more, unless I get so many donations that I can consider working |
694
|
|
|
|
|
|
|
on free software full time (let's all have a chuckle at that together). |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
To donate, log into PayPal and send money to autarch@urth.org, or use the |
697
|
|
|
|
|
|
|
button at L<http://www.urth.org/~autarch/fs-donation.html>. |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=head1 AUTHOR |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
Dave Rolsky <autarch@urth.org> |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
=for stopwords Graham Knop Jesse Luehrs mickey Olaf Alders Sawyer X |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
=over 4 |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=item * |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
Graham Knop <haarg@haarg.org> |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
=item * |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
Jesse Luehrs <doy@tozt.net> |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
=item * |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
mickey <mickey75@gmail.com> |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
=item * |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
Olaf Alders <olaf@wundersolutions.com> |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=item * |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
Sawyer X <xsawyerx@cpan.org> |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=back |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
This software is Copyright (c) 2019 by Dave Rolsky. |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
This is free software, licensed under: |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
The full text of the license can be found in the |
740
|
|
|
|
|
|
|
F<LICENSE> file included with this distribution. |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=cut |