File Coverage

blib/lib/Module/CPANTS/Kwalitee/License.pm
Criterion Covered Total %
statement 61 114 53.5
branch 23 56 41.0
condition 10 22 45.4
subroutine 12 17 70.5
pod 3 3 100.0
total 109 212 51.4


line stmt bran cond sub pod time code
1             package Module::CPANTS::Kwalitee::License;
2 7     7   4219 use warnings;
  7         21  
  7         299  
3 7     7   57 use strict;
  7         27  
  7         166  
4 7     7   54 use File::Spec::Functions qw(catfile);
  7         12  
  7         321  
5 7     7   3525 use Software::LicenseUtils;
  7         468656  
  7         10610  
6              
7             our $VERSION = '1.02';
8             $VERSION =~ s/_//; ## no critic
9              
10 35     35 1 123 sub order { 100 }
11              
12             ##################################################################
13             # Analyse
14             ##################################################################
15              
16             sub analyse {
17 12     12 1 46 my $class = shift;
18 12         27 my $me = shift;
19 12         345 my $distdir = $me->distdir;
20              
21             # check META.yml
22 12         298 my $yaml = $me->d->{meta_yml};
23 12         304 $me->d->{license} = '';
24 12 100       175 if ($yaml) {
25 3 50 33     58 if ($yaml->{license} and $yaml->{license} ne 'unknown') {
26 3         19 my $license = $yaml->{license};
27 3 50       17 $license = join ',', @$license if ref $license eq 'ARRAY';
28 3         65 $me->d->{license_from_yaml} = $license;
29 3         97 $me->d->{license} = $license.' defined in META.yml';
30             }
31             }
32             # use "files_array" to exclude files listed in "no_index".
33 12   50     261 my $files = $me->d->{files_array} || [];
34              
35             # check if there's a LICEN[CS]E file
36             # (also accept LICENSE.txt etc; RT #114247)
37 12 50       133 if (my ($file) = grep {$_ =~ /^(?:LICEN[CS]E|COPYING)\b/} @$files) {
  20         203  
38 0         0 $me->d->{license} .= " defined in $file";
39 0         0 $me->d->{external_license_file} = $file;
40             }
41              
42             # check pod
43 12         35 my %licenses;
44 12         47 foreach my $file (grep { m!^(?:bin|scripts?)/|\.(?:pm|pod|pl|PL)$! } sort @$files ) {
  20         262  
45 10 50       50 next if $file =~ /(?:Makefile|Build)\.PL$/;
46 10         82 my $path = catfile($distdir, $file);
47 10 50       190 next unless -r $path; # skip if not readable
48 10 50       570 open my $fh, '<', $path or next;
49 10         44 my $in_pod = 0;
50 10         71 my $pod = '';
51 10         75 my $pod_head = '';
52 10         72 my @possible_licenses;
53             my @unknown_license_texts;
54 10         0 my $uc_head;
55 10         260 while(<$fh>) {
56 44         150 my $first_four = substr($_, 0, 4);
57 44 50 66     435 if ($first_four eq '=hea' && (($uc_head = uc $_) =~ /(?:LICEN[CS]E|LICEN[CS]ING|COPYRIGHT|LEGAL)/)) {
    100 100        
    50          
58 0         0 $me->d->{license_in_pod} = 1;
59 0   0     0 $me->d->{license} ||= "defined in POD ($file)";
60 0 0       0 if ($in_pod) {
61 0         0 my @guessed = Software::LicenseUtils->guess_license_from_pod("=head1 LICENSE\n$pod\n\n=cut\n");
62 0 0       0 if (@guessed) {
63 0         0 push @possible_licenses, @guessed;
64             } else {
65 0         0 push @unknown_license_texts, "$pod_head$pod";
66             }
67             }
68              
69 0         0 $in_pod = 1;
70 0         0 $pod_head = $_;
71 0         0 $pod = '';
72             }
73             elsif ($first_four eq '=hea' or $first_four eq '=cut') {
74 4 50       10 if ($in_pod) {
75 0         0 my @guessed = Software::LicenseUtils->guess_license_from_pod("=head1 LICENSE\n$pod\n\n=cut\n");
76 0 0       0 if (@guessed) {
77 0         0 push @possible_licenses, @guessed;
78             } else {
79 0         0 push @unknown_license_texts, "$pod_head$pod";
80             }
81             }
82 4         7 $in_pod = 0;
83 4         14 $pod = '';
84             }
85             elsif ($in_pod) {
86 0         0 $pod .= $_;
87             }
88             }
89 10 50       67 if ($pod) {
90 0         0 my @guessed = Software::LicenseUtils->guess_license_from_pod("=head1 LICENSE\n$pod\n\n=cut\n");
91 0 0       0 if (@guessed) {
92 0         0 push @possible_licenses, @guessed;
93             } else {
94 0         0 push @unknown_license_texts, "$pod_head$pod";
95             }
96             }
97 10 50       49 if (@possible_licenses) {
98 0         0 my %seen;
99 0         0 @possible_licenses = grep {!$seen{$_}++} map { s/^Software::License:://; $_ } @possible_licenses;
  0         0  
  0         0  
  0         0  
100 0   0     0 push @{$licenses{$_} ||= []}, $file for @possible_licenses;
  0         0  
101 0         0 $me->d->{files_hash}{$file}{license} = join ',', @possible_licenses;
102             } else {
103 10 50       182 $me->d->{unknown_license_texts}{$file} = join "\n", @unknown_license_texts if @unknown_license_texts;
104             }
105             }
106 12 50       55 if (%licenses) {
107 0         0 $me->d->{licenses} = \%licenses;
108 0         0 my @possible_licenses = keys %licenses;
109 0 0       0 if (@possible_licenses == 1) {
110 0         0 my ($type) = @possible_licenses;
111 0         0 $me->d->{license_type} = $type;
112 0         0 $me->d->{license_file} = join ',', @{$licenses{$type}};
  0         0  
113             }
114             }
115              
116 12         56 return;
117             }
118              
119             ##################################################################
120             # Kwalitee Indicators
121             ##################################################################
122              
123             sub kwalitee_indicators{
124             return [
125             {
126             name => 'meta_yml_has_license',
127             error => q{This distribution does not have a license defined in META.yml.},
128             remedy => q{Define the license if you are using in Build.PL. If you are using MakeMaker (Makefile.PL) you should upgrade to ExtUtils::MakeMaker version 6.31.},
129             is_extra => 1,
130             code => sub {
131 12     12   122 my $d = shift;
132 12         34 my $yaml = $d->{meta_yml};
133 12 100 66     79 ($yaml->{license} and $yaml->{license} ne 'unknown') ? 1 : 0 },
134             details => sub {
135 0     0   0 my $d = shift;
136 0         0 my $yaml = $d->{meta_yml};
137 0 0       0 return "No META.yml." unless $yaml;
138 0 0       0 return "No license was found in META.yml." unless $yaml->{license};
139 0         0 return "Unknown license was found in META.yml.";
140             },
141             },
142             {
143             name => 'has_human_readable_license',
144             error => q{This distribution does not have a license defined in the documentation or in a file called LICENSE},
145             remedy => q{Add a section called "LICENSE" to the documentation, or add a file named LICENSE to the distribution.},
146             code => sub {
147 12     12   90 my $d = shift;
148 12 50 33     128 return $d->{external_license_file} || $d->{license_in_pod} ? 1 : 0;
149             },
150             details => sub {
151 0     0   0 my $d = shift;
152 0         0 return "Neither LICENSE file nor LICENSE section in pod was found.";
153             },
154             },
155             {
156             name => 'has_separate_license_file',
157             error => q{This distribution does not have a LICENSE or LICENCE file in its root directory.},
158             remedy => q{This is not a critical issue. Currently mainly informative for the CPANTS authors. It might be removed later.},
159             is_experimental => 1,
160 12 50   12   124 code => sub { shift->{external_license_file} ? 1 : 0 },
161             details => sub {
162 0     0   0 my $d = shift;
163 0         0 return "LICENSE file was found.";
164             },
165             },
166             {
167             name => 'has_license_in_source_file',
168             error => q{Does not have license information in any of its source files},
169             remedy => q{Add =head1 LICENSE and the text of the license to the main module in your code.},
170             code => sub {
171 12     12   81 my $d = shift;
172 12 50       70 return $d->{license_in_pod} ? 1 : 0;
173             },
174             details => sub {
175 0     0   0 my $d = shift;
176 0         0 return "LICENSE section was not found in the pod.";
177             },
178             },
179             {
180             name => 'has_known_license_in_source_file',
181             error => q{Does not have license information in any of its source files, or the information is not recognized by Software::License},
182             remedy => q{Add =head1 LICENSE and/or the proper text of the well-known license to the main module in your code.},
183             is_extra => 1,
184             code => sub {
185 12     12   92 my $d = shift;
186 12 50       56 return 0 unless $d->{license_in_pod};
187 0         0 my @files_with_licenses = grep {$d->{files_hash}{$_}{license}} keys %{$d->{files_hash}};
  0         0  
  0         0  
188 0 0       0 return @files_with_licenses ? 1 : 0;
189             },
190             details => sub {
191 0     0   0 my $d = shift;
192 0         0 return "LICENSE section was not found in the pod, or the license information was not recognized by Software::License.";
193             },
194             },
195 8     8 1 387 ];
196             }
197              
198              
199             q{Favourite record of the moment:
200             Lili Allen - Allright, still};
201              
202             __END__