File Coverage

blib/lib/Module/License/Report.pm
Criterion Covered Total %
statement 18 88 20.4
branch 0 32 0.0
condition 0 9 0.0
subroutine 6 10 60.0
pod 3 3 100.0
total 27 142 19.0


line stmt bran cond sub pod time code
1             package Module::License::Report;
2              
3 1     1   105109 use warnings;
  1         3  
  1         42  
4 1     1   6 use strict;
  1         2  
  1         38  
5 1     1   5 use File::Spec;
  1         7  
  1         23  
6 1     1   728 use Module::License::Report::CPANPLUS;
  1         4  
  1         263  
7 1     1   16 use Carp;
  1         2  
  1         99  
8 1     1   2038 use English qw(-no_match_vars);
  1         4971  
  1         7  
9              
10             our $VERSION = '0.02';
11              
12             =head1 NAME
13              
14             Module::License::Report - Determine the license of a module
15              
16             =head1 LICENSE
17              
18             Copyright 2005 Clotho Advanced Media, Inc.,
19              
20             This library is free software; you can redistribute it and/or modify it
21             under the same terms as Perl itself.
22              
23             =head1 SYNOPSIS
24              
25             use Module::License::Report;
26            
27             my $reporter = Module::License::Report->new();
28             my $license = $reporter->license('Module::License::Report');
29             print $license; # 'perl'
30             print $license->source_file(); # 'META.yml'
31             print $license->confidence(); # '100'
32             print $license->package_version(); # '0.01'
33            
34             my %lic = $reporter->license_chain('Module::License::Report');
35             # ( Module-License-Report => 'perl', CPANPLUS => 'perl', ... )
36              
37             =head1 DESCRIPTION
38              
39             People who redistribute Perl code must be careful that all of the
40             included libraries are compatible with the final distribution license.
41             A large fraction of CPAN packages are licensed as C,
42             like Perl itself, but not all. If you are going to package your work
43             in, say, a PAR archive with all of its dependencies it's critical
44             that you inspect the licenses of those dependencies. This module can
45             help.
46              
47             This module utilizes CPANPLUS to do much of the hard work of
48             locating the requested CPAN distribution, downloading and extracting
49             it. If you've never used CPANPLUS before, there will be a one-time
50             setup step for that module.
51              
52             =head1 FUNCTIONS
53              
54             =over
55              
56             =item $pkg->new()
57              
58             =item $pkg->new({key =E value, ...})
59              
60             Creates a new instance. Optional parameters can be passed in a hash
61             reference. The recognized options are:
62              
63             =over
64              
65             =item verbose => BOOLEAN
66              
67             Causes some diagnostics to be printed to STDOUT if true.
68              
69             =item cpanhost => URL
70              
71             Changes the default CPANPLUS mirror to be the specified URL.
72              
73             =back
74              
75             =cut
76              
77             sub new
78             {
79 0     0 1   my $pkg = shift;
80 0   0       my $opts_hash = shift || {};
81              
82 0           my $self = bless {
83             opts => $opts_hash,
84             license_cache => {},
85             depends_cache => {},
86             }, $pkg;
87              
88 0           $self->{cp} = Module::License::Report::CPANPLUS->new({
89             verbose => $self->{opts}->{verbose},
90             cb => $self->{opts}->{cb}, # primarily just for testing
91             });
92              
93 0 0         if ($self->{opts}->{cpanhost})
94             {
95 0 0         if (!$self->{cp}->set_host($self->{opts}->{cpanhost}))
96             {
97 0           croak 'Failed to set CPAN host URL';
98             }
99             }
100              
101 0           return $self;
102             }
103              
104             =item $self->license($module_name)
105              
106             Retrieves a license object for the specified module, or undef if no
107             license could be found. The license object stringifies to the name of
108             the license. See also Module::License::Report::Object.
109              
110             The C<$module_name> argument is usually a package name like
111             C. It can also be the distribution name, like C.
112             This is useful for distributions like Text-PDF where there is no
113             actual module named Text::PDF, but which has Text::PDF::File
114             instead.
115              
116             This method uses CPANPLUS to download and inspect the source
117             distribution of the module. If you've never used CPANPLUS before,
118             there will be a one-time setup phase to configure that module.
119              
120             =cut
121              
122             sub license
123             {
124 0     0 1   my $self = shift;
125 0           my $module_name = shift;
126              
127 0 0         if (!defined $self->{license_cache}->{$module_name})
128             {
129 0           my $mod = $self->{cp}->get_module($module_name);
130 0 0         if ($mod)
131             {
132 0           my $dist_name = $mod->package_name();
133 0 0         if (defined $self->{license_cache}->{$dist_name})
134             {
135 0           $self->{license_cache}->{$module_name} = $self->{license_cache}->{$dist_name};
136             }
137             else
138             {
139 0           my $alt_name = $mod->name();
140 0   0       my $license = $mod->license() || 0;
141 0           $self->{license_cache}->{$module_name} = $license;
142 0           $self->{license_cache}->{$alt_name} = $license;
143 0           $self->{license_cache}->{$dist_name} = $license;
144             }
145             }
146             else
147             {
148 0           $self->{license_cache}->{$module_name} = 0;
149             }
150             }
151 0   0       return $self->{license_cache}->{$module_name} || undef;
152             }
153              
154             =item $self->license_chain($module_name)
155              
156             Returns a hash of C license> pairs where the
157             C keys are the distributions of specified module and all of
158             its dependencies, as reported by Module::Depends. The values are
159             Module::License::Report::Object instances. Perl core modules are
160             omitted, as those are all known to be licensed like Perl itself.
161              
162             =cut
163              
164             sub license_chain
165             {
166 0     0 1   my $self = shift;
167 0           my $module_name = shift;
168              
169 0           eval { require Module::Depends::Intrusive; };
  0            
170 0 0         if ($EVAL_ERROR)
171             {
172 0           croak 'Cannot load Module::Depends';
173             }
174              
175 0           eval { require Module::CoreList; };
  0            
176 0 0         if ($EVAL_ERROR)
177             {
178 0           croak 'Cannot load Module::CoreList';
179             }
180              
181 0           my %seen;
182             my %dist_licenses;
183 0           my @stack = ($module_name);
184             MODULE:
185 0           while (@stack > 0)
186             {
187 0           my $mod_name = shift @stack;
188 0 0         next MODULE if ($seen{$mod_name}++);
189              
190 0 0         next MODULE if ($mod_name eq 'perl');
191              
192 0           my $core = Module::CoreList->first_release($mod_name);
193 0 0         next MODULE if ($core);
194            
195 0           my $license = $self->license($mod_name);
196 0 0         if (!$license)
197             {
198 0           warn "Can't find a license for $mod_name\n";
199             }
200             else
201             {
202 0 0         if ($license->module_name() ne $mod_name)
203             {
204 0           $mod_name = $license->module_name();
205 0           $seen{$mod_name}++;
206 0           my $core = Module::CoreList->first_release($mod_name);
207 0 0         next MODULE if ($core);
208             }
209            
210 0           $dist_licenses{$license->package_name()} = $license;
211            
212 0           push @stack, $self->_deps($mod_name, $license->package_dir());
213             }
214             }
215              
216 0           return %dist_licenses;
217             }
218              
219             sub _deps
220             {
221 0     0     my $self = shift;
222 0           my $module_name = shift;
223 0           my $dir = shift;
224            
225 0 0         if (!$self->{depends_cache}->{$module_name})
226             {
227 0           my $deps = Module::Depends->new();
228 0           eval { $deps->dist_dir($dir)->find_modules(); };
  0            
229 0 0         if ($deps->error())
230             {
231 0           $deps = Module::Depends::Intrusive->new();
232 0           eval { $deps->dist_dir($dir)->find_modules(); };
  0            
233             }
234 0           $self->{depends_cache}->{$module_name} = [];
235 0 0 0       if ($deps && $deps->requires())
236             {
237 0           push @{$self->{depends_cache}->{$module_name}},
  0            
238 0           sort keys %{$deps->requires()}
239             }
240             }
241 0           return @{$self->{depends_cache}->{$module_name}};
  0            
242             }
243              
244             1;
245             __END__