+ # modules can be loaded implicitly with use base qw(Module) or use parent
+ # 'Module'. catch these:
+ my ($module, $args) = $useline =~ /
+ (?:
+ (?:base|parent)
+ \s
+ (?:'|"|qw.)
+ )? # optional parent block
+ ([\w:]+) # the module
+ (.*) # args
+ /ix;
+
+ # some comments looks very much like use lines
+ # try to get rid of them
+ next if $useline =~ /^it like a normal Perl node/; # YAML::Dump comment
+ next if $useline =~ /^most and offer that in a small/; # YAML
+
+ my $version = Module::CoreList->first_release($module);
+ $modules{$module} = { status => $supplied{$module} ? 'included'
+ : $version ? sprintf '%2.6f', $version
+ : is_required($module) ? 'required'
+ : is_optional($module) ? 'optional'
+ : is_developer($module) ? 'developer'
+ : '!missing',
+ files => $uselines{$useline},
+ };
+
+ # build requirement tree
+ for my $file (@{ $uselines{$useline} }) {
+ next if $file =~ /\.pl$/;
+ my $orig_module = modulize($file);
+ $requires{$orig_module} ||= {};
+ $requires{$orig_module}{$module}++;
+ }
+}
+
+# have all documented modules mentioned here
+$modules{$_->{name}} ||= { status => 'required' } for @SL::InstallationCheck::required_modules;
+$modules{$_->{name}} ||= { status => 'optional' } for @SL::InstallationCheck::optional_modules;
+$modules{$_->{name}} ||= { status => 'developer' } for @SL::InstallationCheck::developer_modules;
+
+# build transitive closure for documented dependencies
+my $changed = 1;
+while ($changed) {
+ $changed = 0;
+ for my $src_module (keys %requires) {
+ for my $dst_module (keys %{ $requires{$src_module} }) {
+ if ( $modules{$src_module}
+ && $modules{$dst_module}
+ && $modules{$src_module}->{status} =~ /^(required|devel|optional)/
+ && $modules{$dst_module}->{status} eq '!missing') {
+ $modules{$dst_module}->{status} = "required"; # . ", via $src_module";
+ $changed = 1;
+ }
+ }
+ }