File Coverage

blib/lib/Dist/Zilla/Role/PrereqScanner.pm
Criterion Covered Total %
statement 57 58 98.2
branch 18 18 100.0
condition 3 3 100.0
subroutine 5 6 83.3
pod 0 1 0.0
total 83 86 96.5


line stmt bran cond sub pod time code
1             package Dist::Zilla::Role::PrereqScanner 6.029;
2             # ABSTRACT: automatically extract prereqs from your modules
3              
4 6     6   3571 use Moose::Role;
  6         20  
  6         87  
5             with(
6             'Dist::Zilla::Role::FileFinderUser' => {
7             default_finders => [ ':InstallModules', ':ExecFiles' ],
8             },
9             'Dist::Zilla::Role::FileFinderUser' => {
10             method => 'found_test_files',
11             finder_arg_names => [ 'test_finder' ],
12             default_finders => [ ':TestFiles' ],
13             },
14             'Dist::Zilla::Role::FileFinderUser' => {
15             method => 'found_configure_files',
16             finder_arg_names => [ 'configure_finder' ],
17             default_finders => [],
18             },
19             'Dist::Zilla::Role::FileFinderUser' => {
20             method => 'found_develop_files',
21             finder_arg_names => [ 'develop_finder' ],
22             default_finders => [ ':ExtraTestFiles' ],
23             },
24             );
25              
26 6     6   32757 use Dist::Zilla::Pragmas;
  6         16  
  6         43  
27              
28 6     6   48 use namespace::autoclean;
  6         16  
  6         39  
29              
30 6     6   450 use MooseX::Types;
  6         13  
  6         88  
31              
32             #pod =attr finder
33             #pod
34             #pod This is the name of a L<FileFinder|Dist::Zilla::Role::FileFinder>
35             #pod whose files will be scanned to determine runtime prerequisites. It
36             #pod may be specified multiple times. The default value is
37             #pod C<:InstallModules> and C<:ExecFiles>.
38             #pod
39             #pod =attr test_finder
40             #pod
41             #pod Just like C<finder>, but for test-phase prerequisites. The default
42             #pod value is C<:TestFiles>.
43             #pod
44             #pod =attr configure_finder
45             #pod
46             #pod Just like C<finder>, but for configure-phase prerequisites. There is
47             #pod no default value; AutoPrereqs will not determine configure-phase
48             #pod prerequisites unless you set configure_finder.
49             #pod
50             #pod =attr develop_finder
51             #pod
52             #pod Just like <finder>, but for develop-phase prerequisites. The default value
53             #pod is C<:ExtraTestFiles>.
54             #pod
55             #pod =attr skips
56             #pod
57             #pod This is an arrayref of regular expressions, derived from all the 'skip' lines
58             #pod in the configuration. Any module names matching any of these regexes will not
59             #pod be registered as prerequisites.
60             #pod
61             #pod =cut
62              
63             has skips => (
64             is => 'ro',
65             isa => 'ArrayRef[Str]',
66             );
67              
68             around mvp_multivalue_args => sub {
69             my ($orig, $self) = @_;
70             ($self->$orig, 'skips')
71             };
72             around mvp_aliases => sub {
73             my ($orig, $self) = @_;
74             my $aliases = $self->$orig;
75             $aliases->{skip} = 'skips';
76             return $aliases
77             };
78              
79              
80             requires 'scan_file_reqs';
81              
82             sub scan_prereqs {
83 29     29 0 71 my $self = shift;
84              
85 29         182 require CPAN::Meta::Requirements;
86 29         155 require List::Util;
87 29         870 List::Util->VERSION(1.45); # uniq
88              
89             # not a hash, because order is important
90 29         274 my @sets = (
91             # phase => file finder method
92             [ configure => 'found_configure_files' ], # must come before runtime
93             [ runtime => 'found_files' ],
94             [ test => 'found_test_files' ],
95             [ develop => 'found_develop_files' ],
96             );
97              
98 29         110 my %reqs_by_phase;
99             my %runtime_final;
100 29         0 my @modules;
101              
102 29         99 for my $fileset (@sets) {
103 116         362 my ($phase, $method) = @$fileset;
104              
105 116         617 my $req = CPAN::Meta::Requirements->new;
106 116         2545 my $files = $self->$method;
107              
108 116         386 foreach my $file (@$files) {
109             # skip binary files
110 117 100       20701 next if $file->is_bytes;
111             # parse only perl files
112 98 100 100     406 next unless $file->name =~ /\.(?:pm|pl|t|psgi)$/i
113             || $file->content =~ /^#!(?:.*)perl(?:$|\s)/;
114             # RT#76305 skip extra tests produced by ExtraTests plugin
115 93 100       380 next if $file->name =~ m{^t/(?:author|release)-[^/]*\.t$};
116              
117             # store module name, to trim it from require list later on
118 91         304 my @this_thing = $file->name;
119              
120             # t/lib/Foo.pm is treated as providing t::lib::Foo, lib::Foo, and Foo
121 91 100       410 if ($this_thing[0] =~ /^t/) {
122 5         27 push @this_thing, ($this_thing[0]) x 2;
123 5         23 $this_thing[1] =~ s{^t/}{};
124 5         18 $this_thing[2] =~ s{^t/lib/}{};
125             } else {
126 86         327 $this_thing[0] =~ s{^lib/}{};
127             }
128 91         457 s{\.pm$}{} for @this_thing;
129 91         418 s{/}{::}g for @this_thing;
130              
131             # this is a bunk heuristic and can still capture strings from pod - the
132             # proper thing to do is grab all packages from Module::Metadata
133 91         358 push @this_thing, $file->content =~ /^[^#]*?(?:^|\s)package\s+([^\s;#]+)/mg;
134 91         282 push @modules, @this_thing;
135              
136             # parse a file, and merge with existing prereqs
137 91         361 $self->log_debug([ 'scanning %s for %s prereqs', $file->name, $phase ]);
138 91         3169 my $file_req = $self->scan_file_reqs($file);
139              
140 91         1153277 $req->add_requirements($file_req);
141              
142             }
143              
144             # remove prereqs from skiplist
145 116 100       58950 for my $skip (@{ $self->skips || [] }) {
  116         4008  
146 92         489 my $re = qr/$skip/;
147              
148 92         369 foreach my $k ($req->required_modules) {
149 634 100       3099 $req->clear_requirement($k) if $k =~ $re;
150             }
151             }
152              
153             # remove prereqs shipped with current dist
154 116 100       846 if (@modules) {
155             $self->log_debug([
156             'excluding local packages: %s',
157 90     0   684 sub { join(', ', List::Util::uniq(@modules)) } ]
  0         0  
158             )
159             }
160 116         3207 $req->clear_requirement($_) for @modules;
161              
162 116         3925 $req->clear_requirement($_) for qw(Config DB Errno NEXT Pod::Functions); # never indexed
163              
164             # we're done, return what we've found
165 116         3160 my %got = %{ $req->as_string_hash };
  116         483  
166 116 100       20126 if ($phase eq 'runtime') {
167 29         395 %runtime_final = %got;
168             } else {
169             # do not test-require things required for runtime
170 87         478 delete $got{$_} for
171 1078 100       2347 grep { exists $got{$_} and $runtime_final{$_} ge $got{$_} }
172             keys %runtime_final;
173             }
174              
175 116         1139 $reqs_by_phase{$phase} = \%got;
176             }
177              
178 29         369 return \%reqs_by_phase
179             }
180              
181             1;
182              
183             =pod
184              
185             =encoding UTF-8
186              
187             =head1 NAME
188              
189             Dist::Zilla::Role::PrereqScanner - automatically extract prereqs from your modules
190              
191             =head1 VERSION
192              
193             version 6.029
194              
195             =head1 PERL VERSION
196              
197             This module should work on any version of perl still receiving updates from
198             the Perl 5 Porters. This means it should work on any version of perl released
199             in the last two to three years. (That is, if the most recently released
200             version is v5.40, then this module should work on both v5.40 and v5.38.)
201              
202             Although it may work on older versions of perl, no guarantee is made that the
203             minimum required version will not be increased. The version may be increased
204             for any reason, and there is no promise that patches will be accepted to lower
205             the minimum required perl.
206              
207             =head1 ATTRIBUTES
208              
209             =head2 finder
210              
211             This is the name of a L<FileFinder|Dist::Zilla::Role::FileFinder>
212             whose files will be scanned to determine runtime prerequisites. It
213             may be specified multiple times. The default value is
214             C<:InstallModules> and C<:ExecFiles>.
215              
216             =head2 test_finder
217              
218             Just like C<finder>, but for test-phase prerequisites. The default
219             value is C<:TestFiles>.
220              
221             =head2 configure_finder
222              
223             Just like C<finder>, but for configure-phase prerequisites. There is
224             no default value; AutoPrereqs will not determine configure-phase
225             prerequisites unless you set configure_finder.
226              
227             =head2 develop_finder
228              
229             Just like <finder>, but for develop-phase prerequisites. The default value
230             is C<:ExtraTestFiles>.
231              
232             =head2 skips
233              
234             This is an arrayref of regular expressions, derived from all the 'skip' lines
235             in the configuration. Any module names matching any of these regexes will not
236             be registered as prerequisites.
237              
238             =head1 SEE ALSO
239              
240             L<Dist::Zilla::Plugin::AutoPrereqs>.
241              
242             =head1 CREDITS
243              
244             The role was provided by Olivier Mengué (DOLMEN) and Philippe Bruhat (BOOK) at Perl QA Hackathon 2016
245             (but it is just a refactor of the AutoPrereqs plugin).
246              
247             =head1 AUTHOR
248              
249             Ricardo SIGNES 😏 <cpan@semiotic.systems>
250              
251             =head1 COPYRIGHT AND LICENSE
252              
253             This software is copyright (c) 2022 by Ricardo SIGNES.
254              
255             This is free software; you can redistribute it and/or modify it under
256             the same terms as the Perl 5 programming language system itself.
257              
258             =cut
259              
260             __END__
261              
262             #pod =head1 SEE ALSO
263             #pod
264             #pod L<Dist::Zilla::Plugin::AutoPrereqs>.
265             #pod
266             #pod =head1 CREDITS
267             #pod
268             #pod The role was provided by Olivier Mengué (DOLMEN) and Philippe Bruhat (BOOK) at Perl QA Hackathon 2016
269             #pod (but it is just a refactor of the AutoPrereqs plugin).
270             #pod
271             #pod =cut
272