File Coverage

blib/lib/Test/CheckManifest.pm
Criterion Covered Total %
statement 159 173 91.9
branch 58 86 67.4
condition 33 63 52.3
subroutine 16 16 100.0
pod 1 1 100.0
total 267 339 78.7


line stmt bran cond sub pod time code
1             package Test::CheckManifest;
2              
3             # ABSTRACT: Check if your Manifest matches your distro
4              
5 4     4   1879 use strict;
  4         5  
  4         97  
6 4     4   13 use warnings;
  4         4  
  4         95  
7              
8 4     4   19 use Cwd;
  4         4  
  4         215  
9 4     4   15 use Carp;
  4         5  
  4         182  
10 4     4   15 use File::Spec;
  4         4  
  4         74  
11 4     4   14 use File::Basename;
  4         4  
  4         233  
12 4     4   697 use Test::Builder;
  4         8594  
  4         88  
13 4     4   17 use File::Find;
  4         5  
  4         482  
14              
15             our $VERSION = '1.31';
16             our $VERBOSE = 1;
17              
18             my $test = Test::Builder->new();
19             my $test_bool = 1;
20             my $plan = 0;
21             my $counter = 0;
22              
23             sub import {
24 4     4   25 my $self = shift;
25 4         5 my $caller = caller;
26 4         8 my %plan = @_;
27              
28 4         10 for my $func ( qw( ok_manifest ) ) {
29 4     4   15 no strict 'refs';
  4         4  
  4         5515  
30 4         6 *{$caller."::".$func} = \&$func;
  4         19  
31             }
32              
33 4         17 $test->exported_to($caller);
34 4         42 $test->plan(%plan);
35            
36 4 100       825 $plan = 1 if(exists $plan{tests});
37             }
38              
39             sub ok_manifest{
40 11     11 1 202 my ($hashref,$msg) = @_;
41            
42 11 100       35 $test->plan(tests => 1) unless $plan;
43            
44 11         446 my $is_hashref = 1;
45 11 100       37 $is_hashref = 0 unless ref($hashref);
46            
47 11 100       26 unless ( $is_hashref ) {
48 1         1 $msg = $hashref;
49 1         3 $hashref = {};
50             }
51              
52 11         921 my $tmp_path = dirname( File::Spec->rel2abs( $0 ) );
53              
54 11 50       58 if ( $hashref->{file} ) {
    100          
55 0         0 $tmp_path = dirname $hashref->{file};
56             }
57             elsif ( $hashref->{dir} ) {
58 1         1 $tmp_path = $hashref->{dir};
59             }
60            
61 11         18 my $bool = 1;
62 11         397 my $home = Cwd::realpath( $tmp_path );
63 11         17 my $manifest;
64              
65 11         14 my $counter = 0;
66 11         28 while ( 1 ) {
67 22         132 my $manifest_path = File::Spec->catfile( $home . '/MANIFEST' );
68 22 100       271 last if -f $manifest_path;
69              
70 11         334 my $tmp_home = Cwd::realpath( File::Spec->catdir( $home, '..' ) );
71              
72 11 50 33     129 last if !$tmp_home || $tmp_home eq $home || $counter++ == 20;
      33        
73 11         27 $home = $tmp_home;
74             }
75              
76 11         34 eval { $manifest = Cwd::realpath( $home . '/MANIFEST' ); 1; };
  11         289  
  11         20  
77 11 50       28 if ( !$manifest ) {
78 0         0 $test->BAILOUT( 'Cannot find a MANIFEST. Please check!' );
79             }
80            
81 11         12 my $skip;
82 11         93 my $skip_path = File::Spec->catfile( $home, 'MANIFEST.SKIP' );
83 11 50       23 eval { $skip = Cwd::realpath( $skip_path ) if -f $skip_path; 1; };
  11         105  
  11         15  
84              
85 11         21 my @dup_files = ();
86 11         14 my @missing_files = ();
87 11         13 my @files_plus = ();
88 11         21 my $arref = ['/blib' , '/_build'];
89             my $filter = $is_hashref &&
90 11 100 66     44 $hashref->{filter} ? $hashref->{filter} : [];
91             my $comb = $is_hashref &&
92             $hashref->{bool} &&
93 11 100 66     59 $hashref->{bool} =~ m/^and$/i ?
94             'and' :
95             'or';
96            
97 5         11 push @$arref, @{$hashref->{exclude}}
98             if $is_hashref and exists $hashref->{exclude} and
99 11 100 66     57 ref($hashref->{exclude}) eq 'ARRAY';
      66        
100            
101 11         20 for(@$arref){
102 27 50       87 croak 'path in excluded array must be "absolute"' unless m!^/!;
103 27         57 my $path = $home . $_;
104 27 100       276 next unless -e $path;
105 13         339 $_ = Cwd::realpath($path);
106             }
107            
108 11         22 @$arref = grep { defined }@$arref;
  27         59  
109            
110 11 50       331 unless( open my $fh, '<', $manifest ){
111 0         0 $bool = 0;
112 0         0 $msg = "can't open $manifest";
113             }
114             else{
115             { # extra block to use "last"
116            
117 11         15 my $files_in_skip = _read_skip( $skip, \$msg, \$bool );
  11         36  
118 11 50       30 last unless $files_in_skip;
119              
120 11         27 my @files = _read_file( $fh );
121 11         77 close $fh;
122            
123 11         18 chomp @files;
124            
125             {
126 11         13 local $/ = "\r";
  11         38  
127 11         23 chomp @files;
128             }
129            
130 11         19 for my $tfile(@files){
131 143         319 $tfile = (split(/\s{2,}/,$tfile,2))[0];
132 143 50       1531 next unless -e $home . '/' . $tfile;
133 143         4279 $tfile = Cwd::realpath($home . '/' . $tfile);
134             }
135            
136 11         12 my (@dir_files,%files_hash,%excluded);
137 11         105 @files_hash{@files} = ();
138            
139             find({no_chdir => 1,
140             wanted => sub{
141 627     627   837 my $file = $File::Find::name;
142 627         927 my $is_excluded = _is_excluded(
143             $file,
144             $arref,
145             $filter,
146             $comb,
147             $files_in_skip,
148             $home,
149             );
150            
151 627 100 100     14525 push(@dir_files,Cwd::realpath($file)) if -f $file and !$is_excluded;
152            
153 627 100 100     26037 $excluded{$file} = 1 if -f $file and $is_excluded
154             }
155 11         987 },$home);
156              
157             #use Data::Dumper;
158             #print STDERR ">>",++$counter,":",Dumper(\@files,\@dir_files);
159             SFILE:
160 11         86 for my $file(@dir_files){
161 173         148 for my $check(@files){
162 1560 100       2562 if($file eq $check){
163 119         177 delete $files_hash{$check};
164 119         151 next SFILE;
165             }
166             }
167 54         76 push(@missing_files,$file);
168 54         61 $bool = 0;
169             }
170            
171 11         93 delete $files_hash{$_} for keys %excluded;
172 11         41 @files_plus = sort keys %files_hash;
173 11 50       35 $bool = 0 if scalar @files_plus > 0;
174              
175 11         21 my %seen_files = ();
176 11 50       19 @dup_files = map { 1==$seen_files{$_}++ ? $_ : () } @files;
  143         288  
177 11 50       193 $bool = 0 if scalar @dup_files > 0;
178            
179             } # close extra block
180             }
181            
182 11         81 my $diag = 'The following files are not named in the MANIFEST file: '.
183             join(', ',@missing_files);
184 11         28 my $plus = 'The following files are not part of distro but named in the MANIFEST file: '.
185             join(', ',@files_plus);
186 11         17 my $dup = 'The following files appeared more than once in the MANIFEST file: '.
187             join(', ',@dup_files);
188            
189 11         79 $test->is_num($bool,$test_bool,$msg);
190 11 50 100     9566 $test->diag($diag) if scalar @missing_files >= 1 and $test_bool == 1 and $VERBOSE;
      66        
191 11 0 33     455 $test->diag($plus) if scalar @files_plus >= 1 and $test_bool == 1 and $VERBOSE;
      33        
192 11 0 33     176 $test->diag($dup) if scalar @dup_files >= 1 and $test_bool == 1 and $VERBOSE;
      33        
193             }
194              
195             sub _read_file {
196 11     11   12 my ($fh) = @_;
197            
198 11         13 my @files;
199 11         11 my $selftest = 0;
200              
201 11         162 while( my $fh_line = <$fh> ){
202 154         173 chomp $fh_line;
203            
204 154 50       228 $selftest++ if $fh_line =~ m{# MANIFEST for Test-CheckManifest};
205              
206 154 100       286 next if $fh_line =~ m{ \A \s* \# }x;
207 143 50 33     216 next if $selftest && $fh_line =~ m{# selftest};
208            
209 143         90 my ($file);
210            
211 143 100       243 if ( ($file) = $fh_line =~ /^'(\\[\\']|.+)+'\s*(.*)/) {
212 11         20 $file =~ s/\\([\\'])/$1/g;
213             }
214             else {
215 132         238 ($file) = $fh_line =~ /^(\S+)\s*(.*)/;
216             }
217              
218 143 50       199 next unless $file;
219              
220 143         416 push @files, $file;
221             }
222            
223 11         50 return @files;
224             }
225              
226             sub _not_ok_manifest{
227 6     6   560 $test_bool = 0;
228 6         15 ok_manifest(@_);
229 6         16 $test_bool = 1;
230             }
231              
232             sub _is_excluded{
233 627     627   1115 my ($file,$dirref,$filter,$bool,$files_in_skip,$home) = @_;
234 627         1313 my @excluded_files = qw(
235             pm_to_blib Makefile META.yml Build pod2htmd.tmp
236             pod2htmi.tmp Build.bat .cvsignore MYMETA.json MYMETA.yml
237             );
238              
239 627 50 33     2279 if ( $files_in_skip and 'ARRAY' eq ref $files_in_skip ) {
240 627         3390 (my $local_file = $file) =~ s{\Q$home\E/?}{};
241 627         631 for my $rx ( @{$files_in_skip} ) {
  627         1032  
242 0         0 my $regex = qr/$rx/;
243 0 0       0 return 1 if $local_file =~ $regex;
244             }
245             }
246            
247 627         663 my @matches = grep{ $file =~ /$_$/ }@excluded_files;
  6270         34749  
248            
249 627 100       863 if($bool eq 'or'){
250 569 50 33     675 push @matches, $file if grep{ref($_) and ref($_) eq 'Regexp' and $file =~ /$_/}@$filter;
  570 100       4190  
251 569 100       596 push @matches, $file if grep{$file =~ /^\Q$_\E/}@$dirref;
  1368         10775  
252             }
253             else{
254 58 100 66     59 if(grep{$file =~ /$_/ and ref($_) and ref($_) eq 'Regexp'}@$filter and
  58 50 66     269  
255 6 50       63 grep{$file =~ /^\Q$_\E/ and not ref($_)}@$dirref){
256 0         0 push @matches, $file;
257             }
258             }
259            
260 627         1335 return scalar @matches;
261             }
262              
263             sub _read_skip {
264 11     11   21 my ($skip, $msg, $bool) = @_;
265              
266 11 50 33     63 return [] unless $skip and -e $skip;
267            
268 0           my @files;
269 0 0 0       if( -e $skip and not open my $skip_fh, '<', $skip ) {
270 0           $$bool = 0;
271 0           $$msg = "can't open $skip";
272 0           return;
273             }
274             else {
275 0           @files = _read_file( $skip_fh );
276             }
277              
278 0           return \@files;
279             }
280              
281             1;
282              
283             __END__