File Coverage

blib/lib/Module/ScanDeps/Static.pm
Criterion Covered Total %
statement 140 279 50.1
branch 34 142 23.9
condition 27 88 30.6
subroutine 23 29 79.3
pod 3 12 25.0
total 227 550 41.2


line stmt bran cond sub pod time code
1             package Module::ScanDeps::Static;
2              
3 2     2   3288 use strict;
  2         5  
  2         63  
4 2     2   9 use warnings;
  2         4  
  2         73  
5              
6             our $VERSION = '1.001';
7              
8 2     2   41 use 5.010;
  2         6  
9              
10 2     2   13 use Carp;
  2         3  
  2         135  
11 2     2   707 use Data::Dumper;
  2         7068  
  2         124  
12 2     2   1032 use English qw{ -no_match_vars };
  2         3477  
  2         10  
13 2     2   1651 use ExtUtils::MM;
  2         225424  
  2         203  
14 2     2   1697 use Getopt::Long;
  2         22321  
  2         10  
15 2     2   2024 use JSON::PP;
  2         33763  
  2         133  
16 2     2   6586 use Module::CoreList;
  2         226406  
  2         30  
17 2     2   3107 use Pod::Usage;
  2         80126  
  2         292  
18 2     2   19 use Pod::Find qw{ pod_where };
  2         6  
  2         109  
19 2     2   1197 use Readonly;
  2         8204  
  2         128  
20 2     2   1040 use IO::Scalar;
  2         22203  
  2         97  
21 2     2   22 use List::Util qw{ max };
  2         5  
  2         205  
22 2     2   13 use version;
  2         17  
  2         21  
23              
24 2     2   1131 use parent qw{ Class::Accessor::Fast };
  2         584  
  2         11  
25              
26             __PACKAGE__->follow_best_practice;
27             __PACKAGE__->mk_accessors(
28             qw{
29             json raw text handle include_require core
30             add_version perlreq require path separator min_core_version
31             }
32             );
33              
34             # booleans
35             Readonly my $TRUE => 1;
36             Readonly my $FALSE => 0;
37              
38             # shell success/failure
39             Readonly my $SUCCESS => 0;
40             Readonly my $FAILURE => 1;
41              
42             # chars
43             Readonly my $COMMA => q{,};
44             Readonly my $DOUBLE_COLON => q{::};
45             Readonly my $EMPTY => q{};
46             Readonly my $NEWLINE => qq{\n};
47             Readonly my $SLASH => q{/};
48             Readonly my $SPACE => q{ };
49              
50             Readonly my $DEFAULT_MIN_CORE_VERSION => '5.8.9';
51              
52             our $HAVE_VERSION = eval {
53             require version;
54             return $TRUE;
55             };
56              
57             caller or __PACKAGE__->main();
58              
59             ########################################################################
60             sub new {
61             ########################################################################
62 2     2 1 7586 my ( $class, $args ) = @_;
63              
64 2   50     7 $args = $args || {};
65              
66 2         2 my %options = %{$args};
  2         16  
67              
68 2         17 foreach my $k ( keys %options ) {
69 3         8 my $v = $options{$k};
70              
71 3         5 delete $options{$k};
72              
73 3         6 $k =~ s/-/_/gxsm;
74              
75 3         8 $options{$k} = $v;
76             }
77              
78             # defaults
79 2   33     14 $options{'core'} //= $TRUE;
80 2   33     20 $options{'include_require'} //= $FALSE;
81 2   66     15 $options{'add_version'} //= $TRUE;
82 2   33     14 $options{'min_core_version'} //= $DEFAULT_MIN_CORE_VERSION;
83              
84 2         17 my $self = $class->SUPER::new( \%options );
85              
86 2         79 $self->set_perlreq( {} );
87 2         52 $self->set_require( {} );
88              
89 2         17 return $self;
90             }
91              
92             ########################################################################
93             sub make_path_from_module {
94             ########################################################################
95 4     4 0 8 my ( $self, $module ) = @_;
96              
97 4         12 my $file = join $SLASH, split /$DOUBLE_COLON/xsm, $module;
98              
99 4         64 return "$file.pm";
100             }
101              
102             ########################################################################
103             sub get_module_version {
104             ########################################################################
105 4     4 0 8 my ( $self, $module_w_version, @include_path ) = @_;
106              
107 4 50       10 if ( !@include_path ) {
108 4         13 @include_path = @INC;
109             }
110              
111 4         12 my ( $module, $version ) = split /\s+/xsm, $module_w_version;
112              
113 4         13 my %module_version = (
114             module => $module,
115             version => $version,
116             path => undef,
117             );
118              
119 4 50       9 return \%module_version
120             if $version;
121              
122 4         8 $module_version{'file'} = $self->make_path_from_module($module);
123              
124 4         7 foreach my $prefix (@include_path) {
125              
126 40         143 my $path = $prefix . $SLASH . $module_version{'file'};
127 40 100       679 next if !-e $path;
128              
129 2         7 $module_version{'path'} = $path;
130              
131             $module_version{'version'}
132 2   50     4 = eval { return ExtUtils::MM->parse_version($path) // 0; };
  2         37  
133              
134 2         1837 last;
135             }
136              
137 4         20 return \%module_version;
138             }
139              
140             ########################################################################
141             sub is_core {
142             ########################################################################
143 0     0 0 0 my ( $self, $module_w_version ) = @_;
144              
145 0         0 my ( $module, $version ) = split /\s/xsm, $module_w_version;
146              
147 0         0 my $core = $FALSE;
148              
149 0         0 my @ms = Module::CoreList->find_modules(qr/\A$module\z/xsm);
150              
151 0 0       0 if (@ms) {
152 0         0 my $first_release = Module::CoreList->first_release($module);
153              
154 0         0 my $first_release_version = version->parse($first_release);
155 0         0 my $min_core_version = $self->get_min_core_version;
156              
157             # consider a module core if its first release was less than some
158             # version of Perl. This is done because CPAN testers don't seem to
159             # test modules against Perls that are older than 5.8.9 - however,
160             # some modules like JSON::PP did not appear until > 5.10
161              
162             # print {*STDERR} "$module: $first_release_version $min_core_version\n";
163              
164 0 0       0 $core = version->parse($first_release_version)
165             <= version->parse($min_core_version) ? 1 : 0;
166              
167             }
168              
169             # print {*STDERR} "$module: [$core]\n";
170              
171 0         0 return $core;
172             }
173              
174             ########################################################################
175             sub parse_line { ## no critic (Subroutines::ProhibitExcessComplexity)
176             ########################################################################
177 8     8 0 16 my ( $self, $line ) = @_;
178              
179 8         172 my $fh = $self->get_handle;
180              
181             # skip the "= <<" block
182 8 50 33     68 if ( $line =~ /\A\s*(?:my\s*)?\$(?:.*)\s*=\s*<<\s*(["'`])(.+?)\1/xsm
183             || $line =~ /\A\s*(?:my\s*)?\$(.*)\s*=\s*<<(\w+)\s*;/xsm ) {
184 0         0 my $tag = $2;
185              
186 0         0 while ( $line = <$fh> ) {
187 0         0 chomp $line;
188              
189 0 0       0 last if $line eq $tag;
190             }
191              
192 0         0 $line = <$fh>;
193              
194 0 0       0 return if !$line;
195              
196             }
197              
198             # skip q{} quoted sections - just hope we don't have curly brackets
199             # within the quote, nor an escaped hash mark that isn't a comment
200             # marker, such as occurs right here. Draw the line somewhere.
201 8 50 33     23 if ( $line =~ /\A.*\Wq[qxwr]?\s*([{([#|\/])[^})\]#|\/]*$/xsm
202             && $line !~ /\A\s*require|use\s/xsm ) {
203 0         0 my $tag = $1;
204              
205 0         0 $tag =~ tr/{\(\[\#|\//})]#|\//;
206 0         0 $tag = quotemeta $tag;
207              
208 0         0 while ( $line = <$fh> ) {
209 0 0       0 last if $line =~ /$tag/xsm;
210             }
211              
212 0 0       0 return if !$line;
213             }
214              
215             # skip the documentation
216              
217             # we should not need to have item in this if statement (it
218             # properly belongs in the over/back section) but people do not
219             # read the perldoc.
220              
221 8 50       17 if ( $line =~ /\A=(head[\d]|pod|for|item)/xsm ) {
222              
223 0         0 while ( $line = <$fh> ) {
224 0 0       0 last if $line =~ /\A^=cut/xsm;
225             }
226              
227 0 0       0 return if !$line;
228             }
229              
230 8 50       13 if ( $line =~ /\A=over/xsm ) {
231 0         0 while ( $line = <$fh> ) {
232 0 0       0 last if /\A=back/xsm;
233             }
234              
235 0 0       0 return if !$line;
236             }
237              
238             # skip the data section
239 8 50       13 return if $line =~ /\A__(DATA|END)__/xsm;
240              
241 8         32 my $modver_re = qr/[.\d]+/xsm;
242              
243             #
244             # The (require|use) match further down in this subroutine will match lines
245             # within a multi-line print or return statements. So, let's skip over such
246             # statements whose content should not be loading modules anyway. -BEF-
247             #
248 8 50 33     41 if ( $line =~ /print(?:\s+|\s+\S+\s+)\<\<\s*(["'`])(.+?)\1/xsm
      33        
249             || $line =~ /print(\s+|\s+\S+\s+)\<\<(\w+)/xsm
250             || $line =~ /return(\s+)\<\<(\w+)/xsm ) {
251              
252 0         0 my $tag = $2;
253 0         0 while ( $line = <$fh> ) {
254 0         0 chomp $line;
255 0 0       0 last if $line eq $tag;
256             }
257              
258 0         0 $line = <$fh>;
259              
260 0 0       0 return if !$line;
261             }
262              
263             # Skip multiline print and assign statements
264 8 50 33     61 if ( $line =~ /\$\S+\s*=\s*(")([^"\\]|(\\.))*\z/xsm
      33        
      33        
265             || $line =~ /\$\S+\s*=\s*(')([^'\\]|(\\.))*\z/xsm
266             || $line =~ /print\s+(")([^"\\]|(\\.))*\z/xsm
267             || $line =~ /print\s+(')([^'\\]|(\\.))*\z/xsm ) {
268              
269 0         0 my $quote = $1;
270              
271 0         0 while ( $line = <$fh> ) {
272 0 0       0 last if $line =~ /\A([^\\$quote]|(\\.))*$quote/xsm;
273             }
274              
275 0         0 $line = <$fh>;
276              
277 0 0       0 return if !$line;
278             }
279              
280             # ouch could be in a eval, perhaps we do not want these since we catch
281             # an exception they must not be required
282              
283             # eval { require Term::ReadLine } or die $@;
284             # eval "require Term::Rendezvous;" or die $@;
285             # eval { require Carp } if defined $^S; # If error/warning during compilation,
286              
287             ## no critic (ProhibitComplexRegexes, RequireBracesForMultiline)
288 8 100       210 if (
289             ( $line =~ /\A(\s*) # we hope the inclusion starts the line
290             (require|use)\s+(?![{]) # do not want 'do {' loops
291             # quotes around name are always legal
292             ['"]?([\w:.\/]+?)['"]?[\t; ]
293             # the syntax for 'use' allows version requirements
294             # the latter part is for "use base qw(Foo)" and friends special case
295             \s*($modver_re|(qw\s*[{(\/'"]\s*|['"])[^})\/"'\$]*?\s*[})\/"'])?/xsm
296             )
297             ) {
298              
299             # \s*($modver_re|(qw\s*[(\/'"]\s*|['"])[^)\/"'\$]*?\s*[)\/"'])?
300              
301 6         30 my ( $whitespace, $statement, $module, $version ) = ( $1, $2, $3, $4 );
302              
303 6   66     19 $version //= $EMPTY;
304              
305             #print {*STDERR} "$whitespace, $statement, $module, $version\n";
306              
307             # fix misidentification of version when use parent qw{ Foo };
308             #
309             # Pragmatism dictates that I just identify the misidentification
310             # instead of trying to make the regexp above even more
311             # complicated...
312              
313 6 50 66     56 if ( $statement eq 'use' && $module =~ /(parent|base)/xsm ) {
314 0 0       0 if ( $version =~ /\A\s*qw?\s*['"{(\/]\s*([^'")}\/]+)\s*['")}\/]/xsm ) {
    0          
315 0         0 $module = $1;
316 0         0 $version = $EMPTY;
317             }
318             elsif ( $version =~ /\A\s*['"]([^"']+)['"]\s*\z/xsm ) {
319 0         0 $module = $1;
320 0         0 $version = $EMPTY;
321             }
322             }
323              
324             #print {*STDERR} "$whitespace, $statement, $module, $version\n";
325              
326             #
327              
328             # we only consider require statements that are flushed against
329             # the left edge. any other require statements give too many
330             # false positives, as they are usually inside of an if statement
331             # as a fallback module or a rarely used option
332              
333 6 50       120 if ( !$self->get_include_require ) {
    0          
334 6 50 33     40 return $line if $whitespace ne $EMPTY && $statement eq 'require';
335             }
336             elsif ( $statement eq 'require' ) {
337 0 0       0 return $line if $line =~ /\$/xsm; # eval?
338             }
339              
340             # if there is some interpolation of variables just skip this
341             # dependency, we do not want
342             # do "$ENV{LOGDIR}/$rcfile";
343              
344 6 50       40 return $line if $module =~ /\$/xsm;
345              
346             # skip if the phrase was "use of" -- shows up in gimp-perl, et al.
347 6 50       13 return $line if $module eq 'of';
348              
349             # if the module ends in a comma we probably caught some
350             # documentation of the form 'check stuff,\n do stuff, clean
351             # stuff.' there are several of these in the perl distribution
352              
353 6 50       14 return $line if $module =~ /[,>]\z/xsm;
354              
355             # if the module name starts in a dot it is not a module name.
356             # Is this necessary? Please give me an example if you turn this
357             # back on.
358              
359             # ($module =~ m/^\./) && next;
360              
361             # if the module starts with /, it is an absolute path to a file
362 6 50       8 if ( $module =~ /\A\//xsm ) {
363 0         0 $self->add_require($module);
364 0         0 return $line;
365             }
366              
367             # sometimes people do use POSIX qw(foo), or use POSIX(qw(foo)) etc.
368             # we can strip qw.*$, as well as (.*$:
369 6         11 $module =~ s/qw.*\z//xsm;
370 6         8 $module =~ s/[(].*\z//xsm;
371              
372             # if the module ends with .pm, strip it to leave only basename.
373 6         6 $module =~ s/[.]pm\z//xsm;
374              
375             # some perl programmers write 'require URI/URL;' when
376             # they mean 'require URI::URL;'
377              
378 6         7 $module =~ s/\//::/xsm;
379              
380             # trim off trailing parentheses if any. Sometimes people pass
381             # the module an empty list.
382              
383 6         7 $module =~ s/[(]\s*[)]$//xsm;
384              
385 6 50       18 if ( $module =~ /\Av?([\d._]+)\z/xsm ) {
386             # if module is a number then both require and use interpret that
387             # to mean that a particular version of perl is specified
388              
389 0         0 my $ver = $1;
390              
391 0         0 $self->get_perlreq->{'perl'} = $ver;
392              
393 0         0 return $line;
394              
395             }
396              
397             # ph files do not use the package name inside the file.
398             # perlmodlib documentation says:
399              
400             # the .ph files made by h2ph will probably end up as
401             # extension modules made by h2xs.
402              
403             # so do not expend much effort on these.
404              
405             # there is no easy way to find out if a file named systeminfo.ph
406             # will be included with the name sys/systeminfo.ph so only use the
407             # basename of *.ph files
408              
409 6 50       13 return $line if $module =~ /[.]ph\z/xsm;
410              
411             # use base|parent qw(Foo) dependencies
412 6 50 33     25 if ( $statement eq 'use'
      66        
413             && ( $module eq 'base' || $module eq 'parent' ) ) {
414 0         0 $self->add_require( $module, $version );
415             #print {*STDERR}
416             # "statement: $statement module: $module, version: $version\n";
417              
418 0 0       0 if ( $version =~ /\Aqw\s*[{(\/'"]\s*([^)}\/"']+?)\s*[})\/"']/xsm ) {
    0          
419 0         0 foreach ( split $SPACE, $1 ) {
420 0         0 $self->add_require( $line, undef );
421             }
422             }
423             elsif ( $version =~ /(["'])([^"']+)\1/xsm ) {
424 0         0 $self->add_require( $2, undef );
425             }
426              
427 0         0 return $line;
428             }
429              
430 6 50 66     47 if ( $version && $version !~ /\A$modver_re\z/oxsm ) {
431 0         0 $version = undef;
432             }
433             #print {*STDERR}
434             # "statement: $statement module: $module, version: $version\n";
435              
436 6         17 my @module_list = split /\s+/xsm, $module;
437              
438 6 50       14 if ( @module_list > 1 ) {
439 0         0 for (@module_list) {
440 0         0 $self->add_require( $_, $EMPTY );
441             }
442             }
443             else {
444 6         18 $self->add_require( $module, $version );
445             }
446             }
447              
448 8         73 return $line;
449             }
450              
451             ########################################################################
452             sub parse {
453             ########################################################################
454 2     2 1 11 my ( $self, $script ) = @_;
455              
456 2 50       45 if ( my $file = $self->get_path ) {
457 0         0 chomp $file;
458              
459 0 0       0 open my $fh, '<', $file ## no critic (InputOutput::RequireBriefOpen)
460             or croak "could not open file '$file' for reading: $OS_ERROR";
461              
462 0         0 $self->set_handle($fh);
463             }
464              
465 2 50 33     47 if ( !$self->get_handle && $script ) {
    50          
466 0         0 $self->set_handle( IO::Scalar->new($script) );
467             }
468             elsif ( !$self->get_handle ) {
469 0 0       0 open my $fh, '<&STDIN' ## no critic (InputOutput::RequireBriefOpen)
470             or croak 'could not open STDIN';
471              
472 0         0 $self->set_handle($fh);
473             }
474              
475 2         83 my $fh = $self->get_handle;
476              
477 2         35 while ( my $line = <$fh> ) {
478 8 50       19 last if !$self->parse_line($line);
479             }
480              
481             # only close the file if we opened...
482 2 50       59 if ( $self->get_path ) {
483 0 0       0 close $fh
484             or croak 'could not close file ' . $self->get_path . "$OS_ERROR\n";
485             }
486              
487 2         16 my @sorted_dependencies = sort keys %{ $self->get_require };
  2         37  
488              
489 2         31 return @sorted_dependencies;
490             }
491              
492             ########################################################################
493             #
494             # To be honest, I'm really not sure what the code below should do
495             # other than simply put the version number in the hash. I can only
496             # surmise that if the original script was running in the context of a
497             # list of perl scripts in a project AND one script specified an older
498             # version of a module, then that version is replace with the newer
499             # version.
500             #
501             # In our implementation here, the typical use case (I think) will be
502             # for an instance of Module::ScanDeps::Static to parse one
503             # script. However, it is possible for the instance to scan multiple
504             # files by calling "parse()" iteratively, accumulating the
505             # dependencies along the way. In that case this method's actions
506             # appear to be relevant.
507             #
508             # Thinking through the above use case and the way it is being
509             # implemented might indicate a "bug", or at least a design flaw. Take
510             # the case where two Perl scripts (presumably in the same project
511             # considering that this utility was written for packaging RPMs)
512             # require different versions of the same module. Rare, and odd, but
513             # possible - although one might wonder why the author of these scripts
514             # didn't resolve any conflicts between the modules so that he could
515             # use one version of said module.
516             #
517             # In any event this method enforces a single version of the module
518             # (the highest) as the answer to the question what version of
519             # __fill_in_the_blank__ module do I require?
520             #
521             # The original method did not attempt to find the version of the
522             # module on the system where this script was being executed. This
523             # implementation does try to do that if you've sent the "add_version"
524             # option to a true value.
525             ########################################################################
526              
527             ########################################################################
528             sub add_require {
529             ########################################################################
530 6     6 0 12 my ( $self, $module, $newver ) = @_;
531              
532 6         19 $module =~ s/\A\s*//xsm;
533 6         23 $module =~ s/\s*\z//xsm;
534              
535 6         118 my $require = $self->get_require;
536              
537 6         63 my $oldver = $require->{$module};
538              
539 6 50       18 if ($oldver) {
    100          
540 0 0 0     0 if ( $HAVE_VERSION && $newver && version->new($oldver) < $newver ) {
      0        
541 0         0 $require->{$module} = $newver;
542             }
543             }
544             elsif ( !$newver ) {
545 4         8 my $m = {};
546              
547 4 50       68 if ( $self->get_add_version ) {
548 4         25 $m = $self->get_module_version($module);
549             }
550              
551 4   66     21 $require->{$module} = $m->{'version'} // $EMPTY;
552             }
553             else {
554 2         5 $require->{$module} = $newver;
555             }
556              
557 6         50 return $self;
558             }
559              
560             ########################################################################
561             sub format_json {
562             ########################################################################
563 0     0 0   my ( $self, @requirements ) = @_;
564              
565 0           my %perlreq = %{ $self->get_perlreq };
  0            
566              
567 0           my %requires = %{ $self->get_require };
  0            
568              
569 0 0         if ( exists $perlreq{'perl'} ) {
570 0           my $perl_version = $perlreq{'perl'};
571              
572 0 0 0       if ( !$perl_version && $self->get_add_version ) {
573 0           $perl_version = $PERL_VERSION;
574             }
575              
576 0   0       push @requirements,
577             {
578             name => 'perl',
579             version => $perl_version // $EMPTY
580             };
581             }
582              
583 0           foreach my $m ( sort keys %requires ) {
584              
585 0 0 0       next if !$self->get_core && $self->is_core($m);
586              
587             push @requirements,
588             {
589             name => $m,
590 0           version => $requires{$m}
591             };
592             }
593              
594 0           my $json = JSON::PP->new->pretty;
595              
596 0 0         return wantarray ? @requirements : $json->encode( \@requirements );
597             }
598              
599             ########################################################################
600             sub get_dependencies {
601             ########################################################################
602 0     0 1   my ( $self, %options ) = @_;
603              
604 0 0 0       if ( $self->get_json ) {
    0          
605 0           return scalar $self->format_json;
606             }
607             elsif ( $self->get_text || $self->get_raw ) {
608 0           return $self->format_text;
609             }
610             else {
611 0           return $self->format_json;
612             }
613             }
614              
615             ########################################################################
616             sub format_text {
617             ########################################################################
618 0     0 0   my ($self) = @_;
619              
620 0           my @requirements = $self->format_json;
621 0 0         return if !@requirements;
622              
623 0           my $str = $EMPTY;
624              
625 0           my $max_len = 2 + max map { length $_->{'name'} } @requirements;
  0            
626              
627 0           my @output;
628              
629 0           foreach my $module (@requirements) {
630 0           my ( $name, $version ) = @{$module}{qw{ name version }};
  0            
631              
632 0           my $separator = $self->get_separator;
633 0           my $format = "%-${max_len}s%s'%s',";
634              
635 0 0         if ( $self->get_raw ) {
636 0           $separator = $SPACE;
637 0           $format = "%-${max_len}s%s%s";
638             }
639             else {
640 0           $name = "'$name'";
641             }
642              
643 0   0       push @output, sprintf $format, $name, $separator, $version // $EMPTY;
644             }
645              
646 0           return join $NEWLINE, @output, $EMPTY;
647             }
648              
649             ########################################################################
650             sub to_rpm {
651             ########################################################################
652 0     0 0   my ($self) = @_;
653              
654 0           my @rpm_deps = ();
655              
656 0           foreach my $perlver ( sort keys %{ $self->get_perlreq } ) {
  0            
657 0           push @rpm_deps, "perl >= $perlver";
658             }
659              
660 0           my %require = %{ $self->get_require };
  0            
661              
662 0           foreach my $module ( sort keys %require ) {
663 0 0 0       next if !$self->get_core && $self->is_core($module);
664              
665 0 0         if ( !$require{$module} ) {
666 0           my $m;
667              
668 0 0         if ( $self->get_add_version ) {
669 0           $m = $self->get_module_version($module);
670 0 0         if ( $m->{'version'} ) {
671 0           $require{$module} = $m->{'version'};
672              
673 0           push @rpm_deps, "perl($module) >= %s", $m->{'version'};
674             }
675             }
676              
677 0 0 0       if ( !$m || !$m->{'version'} ) {
678 0           push @rpm_deps, "perl($module)";
679             }
680             }
681             else {
682 0           push @rpm_deps, "perl($module) >= $require{$module}";
683             }
684             }
685              
686 0           return join $EMPTY, @rpm_deps;
687             }
688              
689             ########################################################################
690             sub main {
691             ########################################################################
692              
693 0     0 0   my %options = (
694             core => $TRUE,
695             'add-version' => $TRUE,
696             'include-require' => $TRUE,
697             'json' => $FALSE,
698             'text' => $TRUE,
699             'separator' => q{ => },
700             'min-core-version' => '5.8.9',
701             );
702              
703 0           GetOptions(
704             \%options, 'json|j',
705             'text|t', 'core!',
706             'min-core-version|m=s', 'add-version|a!',
707             'include-require|i!', 'help|h',
708             'separator|s=s', 'version|v',
709             'raw|r',
710             );
711              
712             # print {*STDERR} Dumper( \%options );
713              
714 0 0         if ( $options{'version'} ) {
715 0           pod2usage(
716             -exitval => 1,
717             -input => pod_where( { -inc => 1 }, __PACKAGE__ ),
718             -sections => 'VERSION|NAME|AUTHOR',
719             -verbose => 99,
720             );
721             }
722              
723 0 0         if ( $options{'help'} ) {
724 0           pod2usage(
725             -exitval => 1,
726             -input => pod_where( { -inc => 1 }, __PACKAGE__ ),
727             -sections => 'USAGE|VERSION',
728             -verbose => 99,
729             );
730             }
731              
732 0           $options{'path'} = shift @ARGV;
733              
734 0           my $scanner = Module::ScanDeps::Static->new( {%options} );
735 0           $scanner->parse;
736              
737 0 0         if ( $options{'json'} ) {
738 0           print $scanner->get_dependencies( format => 'json' );
739             }
740             else {
741 0           print $scanner->get_dependencies( format => 'text' );
742             }
743              
744 0           exit $SUCCESS;
745             }
746              
747             1;
748              
749             __END__