File Coverage

blib/lib/PPM/Make/Meta.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package PPM::Make::Meta;
2 1     1   1575 use strict;
  1         1  
  1         26  
3 1     1   4 use warnings;
  1         1  
  1         22  
4 1     1   26 use PPM::Make::Util qw(:all);
  0            
  0            
5             use File::Find;
6             use Safe;
7             use CPAN::Meta::YAML qw(LoadFile);
8              
9             our $VERSION = '0.9904';
10              
11             sub new {
12             my ($class, %opts) = @_;
13             my $cwd = $opts{dir};
14             die qq{Please supply the name of the directory} unless $cwd;
15             die qq{The supplied directory "$cwd" doesn't exist} unless -d $cwd;
16             my $search = $opts{search};
17             die qq{Please supply a PPM::Make::Search object}
18             unless (defined $search and (ref($search) eq 'PPM::Make::Search'));
19             my $self = {info => {}, cwd => $cwd, search => $search};
20             bless $self, $class;
21             }
22              
23             sub meta {
24             my $self = shift;
25             chdir $self->{cwd} or die qq{Cannot chdir to "$self->{cwd}": $!};
26             my $mb = -e 'Build.PL';
27             $self->{mb} = $mb;
28             $self->parse_yaml if (-e 'META.yml');
29             if ($mb and -d '_build') {
30             $self->parse_build();
31             }
32             elsif (!$mb) { # ignore Module::Build::Tiny
33             $self->parse_make();
34             }
35             $self->abstract();
36             $self->author();
37             $self->{info}->{VERSION} = (defined $self->{info}->{VERSION_FROM}) ?
38             parse_version($self->{info}->{VERSION_FROM}) :
39             $self->{info}->{VERSION};
40             $self->bundle() if ($self->{info}->{NAME} =~ /^(Bundle|Task)/i);
41             return 1;
42             }
43              
44              
45             sub parse_build {
46             my $self = shift;
47             my $bp = '_build/build_params';
48             # open(my $fh, '<', $bp) or die "Couldn't open $bp: $!";
49             # my @lines = <$fh>;
50             # close $fh;
51             # my $content = join "\n", @lines;
52             # my $c = new Safe();
53             # my $r = $c->reval($content);
54             # if ($@) {
55             # warn "Eval of $bp failed: $@";
56             # return;
57             # }
58             my $file = $self->{cwd} . '/_build/build_params';
59             my $r;
60             unless ($r = do $file) {
61             die "Can't parse $file: $@" if $@;
62             die "Can't do $file: $!" unless defined $r;
63             die "Can't run $file" unless $r;
64             }
65              
66             my $props = $r->[2];
67             my %r = ( NAME => $props->{module_name},
68             DISTNAME => $props->{dist_name},
69             VERSION => $props->{dist_version},
70             VERSION_FROM => $props->{dist_version_from},
71             PREREQ_PM => $props->{requires},
72             AUTHOR => $props->{dist_author},
73             ABSTRACT => $props->{dist_abstract},
74             );
75             foreach (keys %r) {
76             next unless $r{$_};
77             $self->{info}->{$_} ||= $r{$_};
78             }
79             return 1;
80             }
81              
82             sub parse_yaml {
83             my $self = shift;
84             my $props;
85             eval {$props = LoadFile('META.yml')};
86             return if $@;
87             my $author = ($props->{author} and ref($props->{author}) eq 'ARRAY') ?
88             $props->{author}->[0] : $props->{author};
89             my %r = ( NAME => $props->{name},
90             DISTNAME => $props->{distname},
91             VERSION => $props->{version},
92             VERSION_FROM => $props->{version_from},
93             PREREQ_PM => $props->{requires},
94             AUTHOR => $author,
95             ABSTRACT => $props->{abstract},
96             );
97             foreach (keys %r) {
98             next unless $r{$_};
99             $self->{info}->{$_} ||= $r{$_};
100             }
101             return 1;
102             }
103              
104             sub parse_make {
105             my $self = shift;
106             my $flag = 0;
107             my @wanted = qw(NAME DISTNAME ABSTRACT ABSTRACT_FROM AUTHOR
108             VERSION VERSION_FROM PREREQ_PM);
109             my $re = join '|', @wanted;
110             my @lines;
111             open(my $fh, '<', 'Makefile') or die "Couldn't open Makefile: $!";
112             while (<$fh>) {
113             if (not $flag and /MakeMaker Parameters/) {
114             $flag = 1;
115             next;
116             }
117             next unless $flag;
118             last if /MakeMaker post_initialize/;
119             next unless /$re/;
120             # Skip MAN3PODS that can appear here if some words from @wanted found
121             next if /^#\s+MAN3PODS => /;
122             chomp;
123             s/^#*\s+// or next;
124             next unless /^(?:$re)\s*\=\>/o;
125             push @lines, $_;
126             }
127             close($fh);
128             my $make = join ',', @lines;
129             $make = '(' . $make . ')';
130             my $c = new Safe();
131             my %r = $c->reval($make);
132             die "Eval of Makefile failed: $@" if ($@);
133             unless ($r{NAME}) {
134             if ($r{NAME} = $r{DISTNAME}) {
135             $r{NAME} =~ s/-/::/gx;
136             warn 'Cannot determine NAME, using DISTNAME instead';
137             }
138             else {
139             die 'Cannot determine NAME and DISTNAME in Makefile';
140             }
141             }
142             for (@wanted) {
143             next unless $r{$_};
144             $self->{info}->{$_} ||= $r{$_};
145             }
146             return 1;
147             }
148              
149             sub abstract {
150             my $self = shift;
151             my $info = $self->{info};
152             unless ($info->{ABSTRACT}) {
153             if (my $abstract = $self->guess_abstract()) {
154             warn "Setting ABSTRACT to '$abstract'\n";
155             $self->{info}->{ABSTRACT} = $abstract;
156             }
157             else {
158             warn "Please check ABSTRACT in the ppd file\n";
159             }
160             }
161             }
162              
163             sub guess_abstract {
164             my $self = shift;
165             my $info = $self->{info};
166             my $cwd = $self->{cwd};
167             my $search = $self->{search};
168             my $result;
169             for my $guess(qw(ABSTRACT_FROM VERSION_FROM)) {
170             if (my $file = $info->{$guess}) {
171             print "Trying to get ABSTRACT from $file ...\n";
172             $result = parse_abstract($info->{NAME}, $file);
173             return $result if $result;
174             }
175             }
176             my ($hit, $guess);
177             for my $ext (qw(pm pod)) {
178             if ($info->{NAME} =~ /-|:/) {
179             ($guess = $info->{NAME}) =~ s!.*[-:](.*)!$1.$ext!;
180             }
181             else {
182             $guess = $info->{NAME} . ".$ext";
183             }
184             finddepth(sub{$_ eq $guess && ($hit = $File::Find::name)
185             && ($hit !~ m!blib/!)}, $cwd);
186             next unless ($hit and -f $hit);
187             print "Trying to get ABSTRACT from $hit ...\n";
188             $result = parse_abstract($info->{NAME}, $hit);
189             return $result if $result;
190             }
191             if (my $try = $info->{NAME} || $info->{DISTNAME}) {
192             $try =~ s{-}{::}g;
193             my $mod_results = $search->{mod_results};
194             if (defined $mod_results and defined $mod_results->{$try}) {
195             return $mod_results->{$try}->{mod_abs}
196             if defined $mod_results->{$try}->{mod_abs};
197             }
198             if ($search->search($try, mode => 'mod')) {
199             $mod_results = $search->{mod_results};
200             if (defined $mod_results and defined $mod_results->{$try}) {
201             return $mod_results->{$try}->{mod_abs}
202             if defined $mod_results->{$try}->{mod_abs};
203             }
204             }
205             else {
206             $search->search_error();
207             }
208             }
209             if (my $try = $info->{NAME} || $info->{DISTNAME}) {
210             $try =~ s{::}{-}g;
211             my $dist_results = $search->{dist_results};
212             if (defined $dist_results and defined $dist_results->{$try}) {
213             return $dist_results->{$try}->{dist_abs}
214             if defined $dist_results->{$try}->{dist_abs};
215             }
216             if ($search->search($try, mode => 'dist')) {
217             $dist_results = $search->{dist_results};
218             if (defined $dist_results and defined $dist_results->{$try}) {
219             return $dist_results->{$try}->{dist_abs}
220             if defined $dist_results->{$try}->{dist_abs};
221             }
222             }
223             else {
224             $search->search_error();
225             }
226             }
227             return;
228             }
229              
230             sub bundle {
231             my $self = shift;
232             my $info = $self->{info};
233             my $result = $self->guess_bundle();
234             if ($result and ref($result) eq 'ARRAY') {
235             warn "Extracting Bundle/Task info ...\n";
236             foreach my $mod(@$result) {
237             $info->{PREREQ_PM}->{$mod} = 0;
238             }
239             }
240             else {
241             warn "Please check prerequisites in the ppd file\n";
242             }
243             }
244              
245             sub guess_bundle {
246             my $self = shift;
247             my $info = $self->{info};
248             my $cwd = $self->{cwd};
249             my $result;
250             for my $guess(qw(ABSTRACT_FROM VERSION_FROM)) {
251             if (my $file = $info->{$guess}) {
252             print "Trying to get Bundle/Task info from $file ...\n";
253             $result = parse_bundle($file);
254             return $result if $result;
255             }
256             }
257             my ($hit, $guess);
258             for my $ext (qw(pm pod)) {
259             if ($info->{NAME} =~ /-|:/) {
260             ($guess = $info->{NAME}) =~ s!.*[-:](.*)!$1.$ext!;
261             }
262             else {
263             $guess = $info->{NAME} . ".$ext";
264             }
265             finddepth(sub{$_ eq $guess && ($hit !~ m!blib/!)
266             && ($hit = $File::Find::name) }, $cwd);
267             next unless (-f $hit);
268             print "Trying to get Bundle/Task info from $hit ...\n";
269             $result = parse_bundle($hit);
270             return $result if $result;
271             }
272             return;
273             }
274              
275             sub parse_bundle {
276             my ($file) = @_;
277             my @result;
278             local $/ = "\n";
279             my $in_cont = 0;
280             open(my $fh, '<', $file) or die "Couldn't open $file: $!";
281             while (<$fh>) {
282             $in_cont = m/^=(?!head1\s+CONTENTS)/ ? 0 :
283             m/^=head1\s+CONTENTS/ ? 1 : $in_cont;
284             next unless $in_cont;
285             next if /^=/;
286             s/\#.*//;
287             next if /^\s+$/;
288             chomp;
289             my $result = (split " ", $_, 2)[0];
290             $result =~ s/^L<(.*?)>/$1/;
291             push @result, $result;
292             }
293             close $fh;
294             return (scalar(@result) > 0) ? \@result : undef;
295             }
296              
297             sub author {
298             my $self = shift;
299             my $info = $self->{info};
300             unless ($info->{AUTHOR}) {
301             if (my $author = $self->guess_author()) {
302             $self->{info}->{AUTHOR} = $author;
303             warn qq{Setting AUTHOR to "$author"\n};
304             }
305             else {
306             warn "Please check AUTHOR in the ppd file\n";
307             }
308             }
309             }
310              
311             sub guess_author {
312             my $self = shift;
313             my $info = $self->{info};
314             my $search = $self->{search};
315             my $results;
316             if (my $try = $info->{NAME} || $info->{DISTNAME}) {
317             $try =~ s{-}{::}g;
318             my $mod_results = $search->{mod_results};
319             if (defined $mod_results and defined $mod_results->{$try}) {
320             return $mod_results->{$try}->{author}
321             if defined $mod_results->{$try}->{author};
322             }
323             if ($search->search($try, mode => 'mod')) {
324             $mod_results = $search->{mod_results};
325             if (defined $mod_results and defined $mod_results->{$try}) {
326             return $mod_results->{$try}->{author}
327             if defined $mod_results->{$try}->{author};
328             }
329             }
330             else {
331             $search->search_error();
332             }
333             }
334             if (my $try = $info->{DISTNAME} || $info->{NAME}) {
335             $try =~ s{::}{-}g;
336             my $dist_results = $search->{dist_results};
337             if (defined $dist_results and defined $dist_results->{$try}) {
338             return $dist_results->{$try}->{author}
339             if defined $dist_results->{$try}->{author};
340             }
341             if ($search->search($try, mode => 'dist')) {
342             $dist_results = $search->{dist_results};
343             if (defined $dist_results and defined $dist_results->{$try}) {
344             return $dist_results->{$try}->{author}
345             if defined $dist_results->{$try}->{author};
346             }
347             }
348             else {
349             $search->search_error();
350             }
351             }
352             return;
353             }
354              
355             1;
356              
357             __END__