File Coverage

blib/lib/CPAN/Packager/DependencyAnalyzer.pm
Criterion Covered Total %
statement 57 144 39.5
branch 1 60 1.6
condition 0 18 0.0
subroutine 19 28 67.8
pod 0 8 0.0
total 77 258 29.8


line stmt bran cond sub pod time code
1             package CPAN::Packager::DependencyAnalyzer;
2 2     2   1845 use Mouse;
  2         33452  
  2         11  
3 2     2   3906 use Module::Depends;
  2         27517  
  2         20  
4 2     2   4453 use Module::Depends::Intrusive;
  2         342273  
  2         48  
5 2     2   19871 use Module::CoreList;
  2         177511  
  2         33  
6 2     2   13048 use List::Compare;
  2         121170  
  2         280  
7 2     2   3636 use FileHandle;
  2         49579  
  2         16  
8 2     2   4045 use Log::Log4perl qw(:easy);
  2         158205  
  2         16  
9 2     2   3836 use Try::Tiny;
  2         4023  
  2         143  
10 2     2   17 use Parse::CPAN::Meta ();
  2         6  
  2         36  
11 2     2   1310 use CPAN::Packager::ModuleNameResolver;
  2         7  
  2         76  
12 2     2   1243 use CPAN::Packager::DependencyFilter::Common;
  2         10  
  2         91  
13 2     2   1306 use CPAN::Packager::FileUtil qw(file dir);
  2         6  
  2         168  
14 2     2   14 use CPAN::Packager::ListUtil qw(uniq any);
  2         3  
  2         106  
15 2     2   1162 use CPAN::Packager::ConflictionChecker;
  2         6  
  2         72  
16 2     2   1395 use CPAN::Packager::Config::Replacer;
  2         9  
  2         61  
17 2     2   1113 use CPAN::Packager::Extractor;
  2         8  
  2         69  
18 2     2   1328 use CPAN::Packager::MetaAnalyzer;
  2         7  
  2         3812  
19              
20             has 'downloader' => ( is => 'rw', );
21              
22             has 'extractor' => (
23             is => 'rw',
24             default => sub {
25             CPAN::Packager::Extractor->new;
26             }
27             );
28              
29             has 'module_name_resolver' => (
30             is => 'rw',
31             default => sub {
32             CPAN::Packager::ModuleNameResolver->new;
33             }
34             );
35              
36             has 'meta_analyzer' => (
37             is => 'rw',
38             default => sub {
39             CPAN::Packager::MetaAnalyzer->new;
40             }
41             );
42              
43             has 'modules' => (
44             is => 'rw',
45             isa => 'HashRef',
46             default => sub {
47             +{},;
48             }
49             );
50              
51             has 'resolved' => (
52             is => 'rw',
53             default => sub {
54             +{};
55             }
56             );
57              
58             has 'dependency_filter' => (
59             is => 'rw',
60             default => sub {
61             CPAN::Packager::DependencyFilter::Common->new;
62             }
63             );
64              
65             has 'confliction_checker' => (
66             is => 'rw',
67             default => sub {
68             CPAN::Packager::ConflictionChecker->new;
69             }
70             );
71              
72             sub analyze_dependencies {
73 0     0 0 0 my ( $self, $module, $config ) = @_;
74 0 0 0     0 return $module
75             if $config->{modules}->{$module}
76             && $config->{modules}->{$module}->{build_status};
77              
78 0 0       0 return $module if $self->is_non_dualife_core_module($module);
79              
80             # try to download unresolved name because resolver sometimes return wrong name.
81 0         0 my $module_info = $self->download_module( $module, $config );
82              
83 0         0 my $resolved_module = $module_info->{dist_name};
84 0         0 $resolved_module = $self->fix_module_name( $module, $config );
85 0 0       0 unless ( $module_info->{dist_name} ) {
86              
87             # try to download unresolved name because resolver sometimes return wrong name.
88 0         0 $module_info = $self->download_module( $resolved_module, $config );
89 0         0 $resolved_module = $module_info->{dist_name};
90             }
91              
92 0         0 $resolved_module = $module_info->{dist_name};
93 0 0       0 unless ( $module_info->{dist_name} ) {
94 0         0 $resolved_module = $self->resolve_module_name( $module, $config );
95             }
96              
97 0 0       0 return $resolved_module
98             unless $self->_is_needed_to_analyze_dependencies( $resolved_module,
99             $config );
100              
101 0 0       0 unless ( $module_info->{dist_name} ) {
102 0         0 $module_info = $self->download_module( $resolved_module, $config );
103 0 0       0 $resolved_module
104             = $module_info->{dist_name}
105             ? $module_info->{dist_name}
106             : $resolved_module;
107             }
108              
109             my @depends
110 0         0 = $self->get_dependencies( $resolved_module, $module_info->{src_dir},
111             $config );
112 0   0     0 $self->modules->{$resolved_module} = {
      0        
113             module => $resolved_module,
114             original_module_name => $module,
115             skip_name_resolve =>
116             $self->_does_skip_resolve_module_name( $module, $config ),
117             version => $module_info->{version},
118             tgz => ( $module_info->{tgz_path} || undef ),
119             src => ( $module_info->{src_dir} || undef ),
120             depends => \@depends,
121             };
122              
123 0         0 my @new_depends;
124 0         0 for my $depend_module (@depends) {
125 0         0 my $new_name = $self->analyze_dependencies( $depend_module, $config );
126 0         0 push @new_depends, $new_name;
127             }
128              
129             @new_depends
130 0         0 = $self->dependency_filter->filter_dependencies( $resolved_module,
131             \@new_depends, $config );
132              
133             # fix depends to resolved module name.
134 0         0 $self->modules->{$resolved_module}->{depends} = \@new_depends;
135              
136 0         0 return $resolved_module;
137             }
138              
139             sub download_module {
140 0     0 0 0 my ( $self, $module, $config ) = @_;
141              
142             # REFACTOR
143             # move to this to BUILD method after implementing config as singleton
144             # class
145 0 0 0     0 if ( defined $config->{global}->{cpan_mirrors}
146             && $config->{global}->{cpan_mirrors} )
147             {
148 0         0 $self->downloader->set_cpan_mirrors(
149             $config->{global}->{cpan_mirrors} );
150             }
151              
152 0   0     0 $self->{__downloaded} ||= {};
153              
154 0 0       0 unless ( $self->{__downloaded}->{$module} ) {
155 0         0 my $custom_src = $config->{modules}->{$module}->{custom};
156 0 0       0 if ($custom_src) {
157 0 0       0 if ( $custom_src->{tgz_path} ) {
158 0         0 $custom_src->{tgz_path}
159             = CPAN::Packager::Config::Replacer->replace_variable(
160             $custom_src->{tgz_path} );
161             }
162 0 0       0 $custom_src->{src_dir}
163             = $custom_src->{src_dir}
164             ? CPAN::Packager::Config::Replacer->replace_variable(
165             $custom_src->{src_dir} )
166             : $self->extractor->extract( $custom_src->{tgz_path} );
167 0         0 $self->{__downloaded}->{$module} = $custom_src;
168              
169 0 0       0 if ( defined $custom_src->{patches} ) {
170 0         0 my @expanded_patches = ();
171 0         0 foreach my $patch ( @{ $custom_src->{patches} } ) {
  0         0  
172 0         0 push @expanded_patches,
173             CPAN::Packager::Config::Replacer->replace_variable(
174             $patch);
175             }
176 0         0 $custom_src->{patches} = \@expanded_patches;
177             }
178             }
179             else {
180 0 0       0 if ( my $version = $config->{modules}->{$module}->{version} ) {
181 0         0 my $dist_with_version = "$module-$version";
182 0         0 $dist_with_version =~ s/::/-/g;
183 0         0 $self->{__downloaded}->{$module}
184             = $self->downloader->download($dist_with_version);
185             }
186             else {
187 0         0 $self->{__downloaded}->{$module}
188             = $self->downloader->download($module);
189             }
190             }
191             }
192              
193 0 0       0 return $self->{__downloaded}->{$module}
194             if $self->{__downloaded}->{$module};
195              
196             }
197              
198             sub _is_needed_to_analyze_dependencies {
199 0     0   0 my ( $self, $resolved_module, $config ) = @_;
200 0 0       0 return 0 if $self->is_added($resolved_module);
201 0 0       0 return 0 if $self->is_non_dualife_core_module($resolved_module);
202 0 0       0 return 0 if $resolved_module eq 'perl';
203 0 0       0 return 0 if $resolved_module eq 'PerlInterp';
204 0 0       0 return 0 if $config->{modules}->{$resolved_module}->{skip_build};
205 0         0 return 1;
206             }
207              
208             sub _does_skip_resolve_module_name {
209 2     2   23 my ( $self, $module, $config ) = @_;
210             my @skip_name_resolve_modules
211 2 50       4 = @{ $config->{global}->{skip_name_resolve_modules} || () };
  2         10  
212             my $skip_name_resolve
213 2     2   15 = any { $_->{module} eq $module } @skip_name_resolve_modules;
  2         14  
214 2         17 return $skip_name_resolve;
215             }
216              
217             sub is_added {
218 0     0 0   my ( $self, $module ) = @_;
219              
220 0           exists $self->modules->{$module};
221             }
222              
223             sub is_non_dualife_core_module {
224 0     0 0   my ( $self, $module ) = @_;
225 0 0         return 1 if $module eq 'perl';
226              
227             # We should process dual life core modules by default.
228             # The entire point of dual life modules to exist in the first
229             # place is for users to be able to update these modules independent of
230             # upgrading Perl. The vast majority of our users will want dual life
231             # modules to be updated, particularly considering that a lot of recent
232             # CPAN distributions directly depend on updated dual life core modules.
233 0 0         return 0 if $self->is_dual_lived_module($module);
234              
235 0           my $corelist = $Module::CoreList::version{$]};
236 0 0         return 1 if exists $corelist->{$module};
237              
238 0           return 0;
239             }
240              
241             sub is_dual_lived_module {
242 0     0 0   my ( $self, $module ) = @_;
243 0 0         if ( $self->confliction_checker->is_dual_lived_module($module) ) {
244 0           return 1;
245             }
246             else {
247 0           return 0;
248             }
249             }
250              
251             sub get_dependencies {
252 0     0 0   my ( $self, $module, $src, $config ) = @_;
253 0           INFO("Analyzing dependencies for $module");
254 0 0 0       if ( $config->{modules}
      0        
255             && $config->{modules}->{$module}
256             && $config->{modules}->{$module}->{depends} )
257             {
258             return
259 0           map { $_->{module} }
  0            
260 0           @{ $config->{modules}->{$module}->{depends} };
261             }
262              
263 0           my $deps = $self->meta_analyzer->get_dependencies_from_meta($src);
264              
265 0           return grep { !$self->is_added($_) }
  0            
266 0           grep { !$self->is_non_dualife_core_module($_) } @$deps;
267             }
268              
269             sub resolve_module_name {
270 0     0 0   my ( $self, $module, $config ) = @_;
271              
272 0 0         return $self->resolved->{$module} if $self->resolved->{$module};
273 0 0         return $module
274             if $self->_does_skip_resolve_module_name( $module, $config );
275              
276 0           my $resolved_module_name = $self->module_name_resolver->resolve($module);
277 0 0         return $module unless $resolved_module_name;
278 0           $self->resolved->{$module} = $resolved_module_name;
279             }
280              
281             sub fix_module_name {
282 0     0 0   my ( $self, $module, $config ) = @_;
283 0           my $new_module_name = $module;
284 0 0         $new_module_name = $config->{global}->{fix_module_name}->{$module}
285             if $config->{global}->{fix_module_name}->{$module};
286 0           $new_module_name;
287             }
288              
289             __PACKAGE__->meta->make_immutable;
290             1;
291              
292             __END__