line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
## no critic: TestingAndDebugging::RequireUseStrict |
2
|
|
|
|
|
|
|
package Module::List::More; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
#IFUNBUILT |
5
|
|
|
|
|
|
|
# # use strict 'subs', 'vars'; |
6
|
|
|
|
|
|
|
# # use warnings; |
7
|
|
|
|
|
|
|
#END IFUNBUILT |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY |
10
|
|
|
|
|
|
|
our $DATE = '2022-08-12'; # DATE |
11
|
|
|
|
|
|
|
our $DIST = 'Module-List-More'; # DIST |
12
|
|
|
|
|
|
|
our $VERSION = '0.004011'; # VERSION |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# do our own exporting to start faster |
15
|
|
|
|
|
|
|
sub import { |
16
|
1
|
|
|
1
|
|
6
|
my $pkg = shift; |
17
|
1
|
|
|
|
|
2
|
my $caller = caller; |
18
|
1
|
|
|
|
|
3
|
for my $sym (@_) { |
19
|
1
|
50
|
|
|
|
3
|
if ($sym eq 'list_modules') { *{"$caller\::$sym"} = \&{$sym} } |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2471
|
|
|
1
|
|
|
|
|
2
|
|
20
|
0
|
|
|
|
|
0
|
else { die "$sym is not exported!" } |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
} |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub list_modules($$) { |
25
|
17
|
|
|
17
|
0
|
112952
|
my($prefix, $options) = @_; |
26
|
17
|
|
|
|
|
28
|
my $trivial_syntax = $options->{trivial_syntax}; |
27
|
17
|
|
|
|
|
38
|
my($root_leaf_rx, $root_notleaf_rx); |
28
|
17
|
|
|
|
|
0
|
my($notroot_leaf_rx, $notroot_notleaf_rx); |
29
|
17
|
50
|
|
|
|
34
|
if($trivial_syntax) { |
30
|
0
|
|
|
|
|
0
|
$root_leaf_rx = $notroot_leaf_rx = qr#:?(?:[^/:]+:)*[^/:]+:?#; |
31
|
0
|
|
|
|
|
0
|
$root_notleaf_rx = $notroot_notleaf_rx = |
32
|
|
|
|
|
|
|
qr#:?(?:[^/:]+:)*[^/:]+#; |
33
|
|
|
|
|
|
|
} else { |
34
|
17
|
|
|
|
|
60
|
$root_leaf_rx = $root_notleaf_rx = qr/[a-zA-Z_][0-9a-zA-Z_]*/; |
35
|
17
|
|
|
|
|
38
|
$notroot_leaf_rx = $notroot_notleaf_rx = qr/[0-9a-zA-Z_]+/; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
17
|
|
|
|
|
23
|
my $recurse = $options->{recurse}; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# filter by wildcard. we cannot do this sooner because wildcard can be put |
41
|
|
|
|
|
|
|
# at the end or at the beginning (e.g. '*::Path') so we still need |
42
|
17
|
|
|
|
|
18
|
my $re_wildcard; |
43
|
17
|
100
|
66
|
|
|
58
|
if ($options->{wildcard} || $options->{ls_mode}) { |
44
|
8
|
|
|
|
|
40
|
require String::Wildcard::Bash; |
45
|
8
|
|
|
|
|
15
|
my $orig_prefix = $prefix; |
46
|
|
|
|
|
|
|
#print "DEBUG: orig_prefix = <$orig_prefix>\n"; |
47
|
8
|
|
|
|
|
21
|
my @prefix_parts = split /::/, $prefix; |
48
|
8
|
0
|
33
|
|
|
32
|
pop @prefix_parts if $options->{ls_mode} && @prefix_parts && $orig_prefix !~ /::\z/ |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
49
|
|
|
|
|
|
|
&& !String::Wildcard::Bash::contains_wildcard($orig_prefix); |
50
|
8
|
|
|
|
|
12
|
$prefix = ""; |
51
|
8
|
|
|
|
|
14
|
my $has_wildcard; |
52
|
8
|
|
|
|
|
19
|
while (defined(my $part = shift @prefix_parts)) { |
53
|
8
|
50
|
|
|
|
23
|
if (String::Wildcard::Bash::contains_wildcard($part)) { |
54
|
8
|
|
|
|
|
245
|
$has_wildcard++; |
55
|
|
|
|
|
|
|
# XXX limit recurse level to scalar(@prefix_parts), or -1 if has_globstar |
56
|
8
|
100
|
|
|
|
17
|
$recurse = 1 if @prefix_parts; |
57
|
8
|
|
|
|
|
16
|
last; |
58
|
|
|
|
|
|
|
} else { |
59
|
0
|
|
|
|
|
0
|
$prefix .= "$part\::"; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
#print "DEBUG: has_wildcard = $has_wildcard\n"; |
63
|
8
|
50
|
33
|
|
|
34
|
if ($options->{wildcard} && $has_wildcard) { |
64
|
8
|
|
|
|
|
32
|
$re_wildcard = String::Wildcard::Bash::convert_wildcard_to_re({path_separator=>':', dotglob=>1, globstar=>1}, $orig_prefix); |
65
|
8
|
|
|
|
|
727
|
$re_wildcard = qr/\A(?:$re_wildcard)\z/; |
66
|
|
|
|
|
|
|
} else { |
67
|
0
|
0
|
|
|
|
0
|
$re_wildcard = $orig_prefix =~ /::\z/ ? qr/\A\Q$orig_prefix\E/ : qr/\A\Q$orig_prefix\E(?:\z|::)/; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
#print "DEBUG: re_wildcard = $re_wildcard\n"; |
70
|
8
|
100
|
|
|
|
26
|
$recurse = 1 if String::Wildcard::Bash::contains_globstar_wildcard($orig_prefix); |
71
|
|
|
|
|
|
|
#print "DEBUG: recurse = $recurse\n"; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
#print "DEBUG: prefix = <$prefix>\n"; |
74
|
|
|
|
|
|
|
|
75
|
17
|
50
|
33
|
|
|
422
|
die "bad module name prefix `$prefix'" |
76
|
|
|
|
|
|
|
unless $prefix =~ /\A(?:${root_notleaf_rx}:: |
77
|
|
|
|
|
|
|
(?:${notroot_notleaf_rx}::)*)?\z/x && |
78
|
|
|
|
|
|
|
$prefix !~ /(?:\A|[^:]::)\.\.?::/; |
79
|
|
|
|
|
|
|
|
80
|
17
|
|
|
|
|
53
|
my $list_modules = $options->{list_modules}; |
81
|
17
|
|
|
|
|
22
|
my $list_prefixes = $options->{list_prefixes}; |
82
|
17
|
|
|
|
|
21
|
my $list_pod = $options->{list_pod}; |
83
|
17
|
|
|
|
|
19
|
my $use_pod_dir = $options->{use_pod_dir}; |
84
|
17
|
50
|
66
|
|
|
42
|
return {} unless $list_modules || $list_prefixes || $list_pod; |
|
|
|
33
|
|
|
|
|
85
|
17
|
|
|
|
|
20
|
my $return_path = $options->{return_path}; |
86
|
17
|
|
|
|
|
19
|
my $return_library_path = $options->{return_library_path}; |
87
|
17
|
|
|
|
|
19
|
my $return_version = $options->{return_version}; |
88
|
17
|
|
|
|
|
20
|
my $all = $options->{all}; |
89
|
17
|
|
|
|
|
33
|
my @prefixes = ($prefix); |
90
|
17
|
|
|
|
|
23
|
my %seen_prefixes; |
91
|
|
|
|
|
|
|
my %results; |
92
|
|
|
|
|
|
|
my $_set_or_add_result = sub { |
93
|
101
|
|
|
101
|
|
176
|
my ($key, $result_field, $val, $always_all) = @_; |
94
|
101
|
100
|
100
|
|
|
241
|
if (!$result_field) { |
|
|
100
|
|
|
|
|
|
95
|
49
|
|
100
|
|
|
158
|
$results{$key} ||= undef; |
96
|
|
|
|
|
|
|
} elsif ($all || $always_all) { |
97
|
25
|
|
100
|
|
|
90
|
$results{$key}{$result_field} ||= []; |
98
|
25
|
|
|
|
|
31
|
push @{ $results{$key}{$result_field} }, $val; |
|
25
|
|
|
|
|
112
|
|
99
|
|
|
|
|
|
|
} else { |
100
|
|
|
|
|
|
|
$results{$key}{$result_field} = $val |
101
|
27
|
100
|
|
|
|
80
|
unless exists $results{$key}{$result_field}; |
102
|
|
|
|
|
|
|
} |
103
|
17
|
|
|
|
|
65
|
}; |
104
|
|
|
|
|
|
|
#use DD; dd \@prefixes; |
105
|
17
|
|
|
|
|
38
|
while(@prefixes) { |
106
|
45
|
|
|
|
|
127
|
my $prefix = pop(@prefixes); |
107
|
45
|
|
|
|
|
117
|
my @dir_suffix = split(/::/, $prefix); |
108
|
45
|
100
|
|
|
|
100
|
my $module_rx = |
109
|
|
|
|
|
|
|
$prefix eq "" ? $root_leaf_rx : $notroot_leaf_rx; |
110
|
45
|
|
|
|
|
480
|
my $pm_rx = qr/\A($module_rx)\.pmc?\z/; |
111
|
45
|
|
|
|
|
310
|
my $pod_rx = qr/\A($module_rx)\.pod\z/; |
112
|
45
|
100
|
|
|
|
102
|
my $dir_rx = |
113
|
|
|
|
|
|
|
$prefix eq "" ? $root_notleaf_rx : $notroot_notleaf_rx; |
114
|
45
|
|
|
|
|
221
|
$dir_rx = qr/\A$dir_rx\z/; |
115
|
45
|
|
|
|
|
91
|
foreach my $incdir (@INC) { |
116
|
90
|
|
|
|
|
224
|
my $dir = join("/", $incdir, @dir_suffix); |
117
|
90
|
100
|
|
|
|
1774
|
opendir(my $dh, $dir) or next; |
118
|
62
|
|
|
|
|
890
|
while(defined(my $entry = readdir($dh))) { |
119
|
261
|
100
|
100
|
|
|
2895
|
if(($list_modules && $entry =~ $pm_rx) || |
|
|
100
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
120
|
|
|
|
|
|
|
($list_pod && |
121
|
|
|
|
|
|
|
$entry =~ $pod_rx)) { |
122
|
60
|
|
|
|
|
158
|
my $key = $prefix.$1; |
123
|
|
|
|
|
|
|
#print "DEBUG: key=<$key>\n"; |
124
|
60
|
100
|
100
|
|
|
337
|
next if $re_wildcard && $key !~ $re_wildcard; |
125
|
33
|
|
|
|
|
71
|
my $path = "$dir/$entry"; |
126
|
33
|
|
|
|
|
87
|
$_set_or_add_result->($key); |
127
|
33
|
100
|
|
|
|
79
|
$_set_or_add_result->($key, 'module_path', $path) if $return_path; |
128
|
33
|
100
|
|
|
|
61
|
$_set_or_add_result->($key, 'library_path', $incdir) if $return_library_path; |
129
|
33
|
100
|
|
|
|
150
|
if ($return_version) { |
130
|
3
|
|
|
|
|
17
|
require ExtUtils::MakeMaker; |
131
|
3
|
|
|
|
|
27
|
my $v = MM->parse_version($path); |
132
|
3
|
100
|
|
|
|
707
|
$v = undef if $v eq 'undef'; |
133
|
3
|
|
|
|
|
11
|
$_set_or_add_result->($key, 'module_version', $v); |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
} elsif(($list_prefixes || $recurse) && |
136
|
|
|
|
|
|
|
($entry ne '.' && $entry ne '..') && |
137
|
|
|
|
|
|
|
$entry =~ $dir_rx && |
138
|
|
|
|
|
|
|
-d join("/", $dir, |
139
|
|
|
|
|
|
|
$entry)) { |
140
|
40
|
|
|
|
|
120
|
my $newmod = $prefix.$entry; |
141
|
40
|
|
|
|
|
63
|
my $newpfx = $newmod."::"; |
142
|
40
|
50
|
|
|
|
73
|
next if exists $seen_prefixes{$newpfx}; |
143
|
40
|
100
|
|
|
|
57
|
if ($list_prefixes) { |
144
|
16
|
|
|
|
|
64
|
$_set_or_add_result->($newpfx); |
145
|
16
|
100
|
|
|
|
62
|
$_set_or_add_result->($newpfx, 'prefix_paths', "$dir/$entry/", 'always_add') if $return_path; |
146
|
16
|
50
|
|
|
|
30
|
$_set_or_add_result->($newpfx, 'library_path', $incdir, 'always_add') if $return_library_path; |
147
|
|
|
|
|
|
|
} |
148
|
40
|
100
|
|
|
|
152
|
push @prefixes, $newpfx if $recurse; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
} |
151
|
62
|
50
|
33
|
|
|
822
|
next unless $list_pod && $use_pod_dir; |
152
|
0
|
|
|
|
|
0
|
$dir = join("/", $dir, "pod"); |
153
|
0
|
0
|
|
|
|
0
|
opendir($dh, $dir) or next; |
154
|
0
|
|
|
|
|
0
|
while(defined(my $entry = readdir($dh))) { |
155
|
0
|
0
|
|
|
|
0
|
if($entry =~ $pod_rx) { |
156
|
0
|
|
|
|
|
0
|
my $key = $prefix.$1; |
157
|
0
|
0
|
0
|
|
|
0
|
next if $re_wildcard && $key !~ $re_wildcard; |
158
|
0
|
|
|
|
|
0
|
$_set_or_add_result->($key); |
159
|
0
|
0
|
|
|
|
0
|
$_set_or_add_result->($key, 'pod_path', "$dir/$entry") if $return_path; |
160
|
0
|
0
|
|
|
|
0
|
$_set_or_add_result->($key, 'library_path', $incdir) if $return_library_path; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# we cannot filter prefixes early with wildcard because we need to dig down |
167
|
|
|
|
|
|
|
# first and that would've been prevented if we had a wildcard like *::Foo. |
168
|
17
|
100
|
100
|
|
|
57
|
if ($list_prefixes && $re_wildcard) { |
169
|
2
|
|
|
|
|
10
|
for my $k (keys %results) { |
170
|
6
|
50
|
|
|
|
21
|
next unless $k =~ /::\z/; |
171
|
6
|
|
|
|
|
19
|
(my $k_nocolon = $k) =~ s/::\z//; |
172
|
6
|
100
|
100
|
|
|
57
|
delete $results{$k} unless $k =~ $re_wildcard || $k_nocolon =~ $re_wildcard; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
17
|
|
|
|
|
156
|
return \%results; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
1; |
180
|
|
|
|
|
|
|
# ABSTRACT: Module::List, with more options |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
__END__ |