File Coverage

blib/lib/Module/ParseDeps.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Module::ParseDeps;
2            
3 1     1   711 use 5.006001;
  1         3  
  1         32  
4 1     1   4 use strict;
  1         2  
  1         26  
5 1     1   17 use warnings;
  1         2  
  1         28  
6            
7 1     1   4 use Carp;
  1         1  
  1         86  
8 1     1   33 use File::Spec;
  1         3  
  1         25  
9 1     1   398 use Module::MakefilePL::Parse 0.03;
  0            
  0            
10             use YAML 'Load';
11            
12             require Exporter;
13            
14             our @ISA = qw(Exporter);
15            
16             our @EXPORT = qw( parsedeps );
17             our %EXPORT_TAGS = ( 'all' => [ @EXPORT ] );
18             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
19            
20             our $VERSION = '0.02';
21            
22             our $DEBUG = 0;
23            
24             sub _parse_meta {
25             my $file = shift;
26            
27             unless (-r $file) {
28             croak "Unable to read file: ", $file;
29             }
30             open my $fh, $file
31             or croak "Unable to open file: ", $file;
32             my $meta_file = join("", <$fh>);
33             close $fh;
34            
35             unless ($meta_file) {
36             croak "No data was read: ", $file;
37             }
38             unless ($meta_file =~ /^--- \#YAML:1\.0/) {
39             $meta_file = "--- #YAML:1.0\n" . $meta_file;
40             }
41            
42             # Some distributions have a "version_from" field which contains an
43             # invalid character (initial dot), and causes YAML 0.35 to complain
44             # (for instance, Test and File-Spec). We fix this by quoting the
45             # string.
46            
47             # TODO: rewrite this to use a proper META.yml parser module, or if
48             # one is not available, to remove the fields that we do not
49             # understand.
50            
51             $meta_file =~
52             s/(version_from): (\.\/\w+)(([\.\/]\w+)+)\n/$1: \'$2$3\'\n/g;
53            
54             my $meta;
55             eval {
56             # print STDERR $meta_file, "\n";
57             ($meta) = Load( $meta_file );
58             };
59             if ($meta) {
60             return { (%{$meta->{requires}||{ }}, %{$meta->{build_requires}||{ }}) };
61             }
62             else {
63             carp "Error parsing META file: ", $!;
64             return;
65             }
66             }
67            
68             sub _parse_makefile {
69             my $file = shift;
70            
71             unless (-r $file) {
72             croak "Unable to read file: ", $file;
73             }
74            
75             open my $fh, $file
76             or croak "Unable to open file: ", $file;
77             my $makefile = join("", <$fh>);
78             close $fh;
79            
80             unless ($makefile && (!ref($makefile))) {
81             croak "No data was read: ", $file;
82             }
83            
84             my $parse;
85             eval {
86            
87             # For some strange reason, we sometimes get the following warning:
88             # "Warning: possible variable references" here, possibly connected
89             # to parsing "Class-Accessor-0.19" Makefile.PL.
90            
91             $parse = Module::MakefilePL::Parse->new( $makefile );
92             };
93            
94             unless ($parse) {
95             return;
96             }
97             return { %{ $parse->required || { } } };
98             }
99            
100             sub _search_directory {
101             my $root_dir = shift;
102             my $recurse = shift;
103            
104             if ($DEBUG) {
105             print STDERR "_search_directory(\"$root_dir\", $recurse)\n";
106             }
107            
108             unless (-d $root_dir) {
109             croak $root_dir, " is not a directory";
110             }
111            
112             opendir my $dh, $root_dir
113             or croak "unable to open directory ", $root_dir;
114            
115             my @directory = map { File::Spec->catfile($root_dir, $_) }
116             grep /^[^.]+/, readdir $dh;
117            
118             closedir $dh;
119            
120             my @file_list = grep /(Makefile\.PL|\.meta|META\.yml)$/, @directory;
121            
122             if ($recurse) {
123             my @subdir_list = grep -d $_, @directory;
124             foreach my $subdir (@subdir_list) {
125             push @file_list, _search_directory($subdir, $recurse);
126             }
127             }
128            
129             return @file_list;
130             }
131            
132            
133             sub parsedeps {
134             my $root_dir = shift;
135             my $recurse = shift || 0;
136            
137             my @file_list = _search_directory($root_dir, $recurse);
138            
139             if (@file_list) {
140             my @reqs = ( );
141             while (my $file = shift @file_list) {
142             if ($file =~ /(META\.yml|\.meta)$/) {
143             push @reqs, %{ _parse_meta($file) || { } };
144             }
145             elsif ($file =~ /Makefile\.PL$/) {
146             push @reqs, %{ _parse_makefile($file) || { } };
147             }
148             else {
149             croak "Don\'t know how to handle file", $file;
150             }
151             }
152             if (@reqs) {
153             return { @reqs };
154             }
155             else {
156             return;
157             }
158             }
159             else {
160             return;
161             }
162             }
163            
164             1;
165             __END__