line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Module::Install::Admin; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
124403
|
use strict 'vars'; |
|
3
|
|
|
|
|
27
|
|
|
3
|
|
|
|
|
85
|
|
4
|
3
|
|
|
3
|
|
15
|
use File::Path (); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
59
|
|
5
|
3
|
|
|
3
|
|
1240
|
use inc::Module::Install (); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
81
|
|
6
|
|
|
|
|
|
|
|
7
|
3
|
|
|
3
|
|
21
|
use vars qw{$VERSION @ISA}; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
153
|
|
8
|
|
|
|
|
|
|
BEGIN { |
9
|
3
|
|
|
3
|
|
10
|
$VERSION = '1.19'; |
10
|
3
|
|
|
|
|
252
|
@ISA = 'Module::Install'; |
11
|
|
|
|
|
|
|
} |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=pod |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Module::Install::Admin - Author-side manager for Module::Install |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
In a B extension module: |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub extension_method { |
24
|
|
|
|
|
|
|
my $self = shift; |
25
|
|
|
|
|
|
|
$self->admin->some_method(@args); |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
As an one-liner: |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
% perl "-MModule::Install::Admin" -e'&some_method(@args);' |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
The two snippets above are really shorthands for |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
$some_obj->some_method(@args) |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
where C<$some_obj> is the singleton object of a class under the |
37
|
|
|
|
|
|
|
C namespace that provides the method |
38
|
|
|
|
|
|
|
C. See L for a list of built-in methods. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 DESCRIPTION |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
This module implements the internal mechanism for initializing, |
43
|
|
|
|
|
|
|
including and managing extensions, and should only be of interest to |
44
|
|
|
|
|
|
|
extension developers; it is I included under a distribution's |
45
|
|
|
|
|
|
|
F directory, nor are any of the B |
46
|
|
|
|
|
|
|
extensions. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
For normal usage of B, please see L |
49
|
|
|
|
|
|
|
and L instead. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head2 Bootstrapping |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
When someone runs a F that has C |
54
|
|
|
|
|
|
|
and there is no F in the current directory, B |
55
|
|
|
|
|
|
|
will load this module bootstrap itself, through the steps below: |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=over 4 |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item * |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
First, F is POD-stripped and copied from C<@INC> to |
62
|
|
|
|
|
|
|
F. This should only happen on the author's side, never on the |
63
|
|
|
|
|
|
|
end-user side. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=item * |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Reload F if the current file is somewhere else. |
68
|
|
|
|
|
|
|
This ensures that the included version of F is |
69
|
|
|
|
|
|
|
always preferred over the installed version. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item * |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Look at F and load all of them. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item * |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Set up a C function to delegate missing function calls |
78
|
|
|
|
|
|
|
to C -- again, this should only happen |
79
|
|
|
|
|
|
|
at the author's side. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item * |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Provide a C function for removing included |
84
|
|
|
|
|
|
|
files under F. |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=back |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=head1 METHODS |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=cut |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub import { |
93
|
2
|
|
|
2
|
|
26
|
my $class = shift; |
94
|
2
|
|
|
|
|
11
|
my $self = $class->new( _top => Module::Install->new, @_ ); |
95
|
2
|
|
|
|
|
9
|
local $^W; |
96
|
2
|
|
|
|
|
66
|
*{caller(0) . "::AUTOLOAD"} = sub { |
97
|
3
|
|
|
3
|
|
21
|
no strict 'vars'; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
17080
|
|
98
|
0
|
0
|
|
0
|
|
0
|
$AUTOLOAD =~ /([^:]+)$/ or die "Cannot load"; |
99
|
0
|
0
|
|
|
|
0
|
return if uc($1) eq $1; |
100
|
0
|
0
|
|
|
|
0
|
my $obj = $self->load($1) or return; |
101
|
0
|
|
|
|
|
0
|
unshift @_, $obj; |
102
|
0
|
|
|
|
|
0
|
goto &{$obj->can($1)}; |
|
0
|
|
|
|
|
0
|
|
103
|
2
|
|
|
|
|
10
|
}; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub new { |
107
|
2
|
|
|
2
|
0
|
6
|
my ($class, %args) = @_; |
108
|
|
|
|
|
|
|
return $class->SUPER::new( |
109
|
2
|
|
|
|
|
3
|
%{$args{_top}}, %args, |
|
2
|
|
|
|
|
22
|
|
110
|
|
|
|
|
|
|
extensions => undef, |
111
|
|
|
|
|
|
|
pathnames => undef, |
112
|
|
|
|
|
|
|
); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub init { |
116
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
117
|
0
|
|
|
|
|
0
|
$self->copy($INC{"$self->{path}.pm"} => $self->{file}); |
118
|
|
|
|
|
|
|
|
119
|
0
|
0
|
|
|
|
0
|
unless ( grep { $_ eq $self->{prefix} } @INC ) { |
|
0
|
|
|
|
|
0
|
|
120
|
0
|
|
|
|
|
0
|
unshift @INC, $self->{prefix}; |
121
|
|
|
|
|
|
|
} |
122
|
0
|
|
|
|
|
0
|
delete $INC{"$self->{path}.pm"}; |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
0
|
local $^W; |
125
|
0
|
|
|
|
|
0
|
do "$self->{path}.pm"; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub copy { |
129
|
1
|
|
|
1
|
0
|
5536
|
my ($self, $from, $to) = @_; |
130
|
|
|
|
|
|
|
|
131
|
1
|
|
|
|
|
5
|
my @parts = split('/', $to); |
132
|
1
|
50
|
|
|
|
5
|
File::Path::mkpath([ join('/', @parts[ 0 .. $#parts-1 ])]) |
133
|
|
|
|
|
|
|
if @parts > 1; |
134
|
|
|
|
|
|
|
|
135
|
1
|
|
|
|
|
3
|
chomp $to; |
136
|
|
|
|
|
|
|
|
137
|
1
|
|
|
|
|
2
|
local ($_); |
138
|
1
|
50
|
|
|
|
65
|
open my $FROM, "<", $from or die "Can't open $from for input:\n$!"; |
139
|
1
|
50
|
|
|
|
54
|
open my $TO, ">", $to or die "Can't open $to for output:\n$!"; |
140
|
1
|
|
|
|
|
5
|
binmode $FROM; |
141
|
1
|
|
|
|
|
2
|
binmode $TO; |
142
|
1
|
|
|
|
|
5
|
print $TO "#line 1\n"; |
143
|
|
|
|
|
|
|
|
144
|
1
|
|
|
|
|
3
|
my $content; |
145
|
|
|
|
|
|
|
my $in_pod; |
146
|
|
|
|
|
|
|
|
147
|
1
|
|
|
|
|
21
|
while ( <$FROM> ) { |
148
|
3
|
50
|
33
|
|
|
14
|
if ( /^=(?:b(?:egin|ack)|head\d|(?:po|en)d|item|(?:ove|fo)r)/ ) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
149
|
0
|
|
|
|
|
0
|
$in_pod = 1; |
150
|
|
|
|
|
|
|
} elsif ( /^=cut\s*\z/ and $in_pod ) { |
151
|
0
|
|
|
|
|
0
|
$in_pod = 0; |
152
|
0
|
|
|
|
|
0
|
print $TO "#line $.\n"; |
153
|
|
|
|
|
|
|
} elsif ( ! $in_pod ) { |
154
|
3
|
|
|
|
|
12
|
print $TO $_; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
1
|
50
|
|
|
|
9
|
close $FROM or die "Can't close $from for input:\n$!"; |
159
|
1
|
50
|
|
|
|
25
|
close $TO or die "Can't close $to for output:\n$!"; |
160
|
|
|
|
|
|
|
|
161
|
1
|
|
|
|
|
40
|
print "include $to\n"; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# scan through our target to find |
165
|
|
|
|
|
|
|
sub load_all_extensions { |
166
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
167
|
0
|
0
|
|
|
|
|
unless ($self->{extensions}) { |
168
|
0
|
|
|
|
|
|
$self->{extensions} = []; |
169
|
0
|
|
|
|
|
|
foreach my $inc (@INC) { |
170
|
0
|
0
|
0
|
|
|
|
next if ref($inc) or $inc eq $self->{prefix}; |
171
|
0
|
|
|
|
|
|
$self->load_extensions("$inc/$self->{path}", $self->{_top}); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
} |
174
|
0
|
|
|
|
|
|
return @{$self->{extensions}}; |
|
0
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub load { |
178
|
0
|
|
|
0
|
0
|
|
my ($self, $method, $copy) = @_; |
179
|
|
|
|
|
|
|
|
180
|
0
|
|
|
|
|
|
my @extobj; |
181
|
0
|
|
|
|
|
|
foreach my $obj ($self->load_all_extensions) { |
182
|
0
|
0
|
|
|
|
|
next unless defined &{ref($obj)."::$method"}; |
|
0
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
my $is_admin = (ref($obj) =~ /^\Q$self->{name}::$self->{dispatch}::/); |
184
|
|
|
|
|
|
|
# Don't ever include admin modules, and vice versa. |
185
|
|
|
|
|
|
|
# $copy = 0 if $XXX and $is_admin; |
186
|
0
|
0
|
0
|
|
|
|
push @extobj, $obj if $copy xor $is_admin; |
187
|
|
|
|
|
|
|
} |
188
|
0
|
0
|
|
|
|
|
unless ( @extobj ) { |
189
|
0
|
|
|
|
|
|
die "Cannot find an extension with method '$method'"; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# XXX - do we need to reload $obj from the new location? |
193
|
0
|
|
|
|
|
|
my $obj = $self->pick($method, \@extobj); |
194
|
0
|
0
|
|
|
|
|
$self->copy_package(ref($obj)) if $copy; |
195
|
|
|
|
|
|
|
|
196
|
0
|
|
|
|
|
|
return $obj; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# Copy a package to inc/, with its @ISA tree. $pathname is optional. |
200
|
|
|
|
|
|
|
sub copy_package { |
201
|
0
|
|
|
0
|
0
|
|
my ($self, $pkg, $pathname) = @_; |
202
|
0
|
0
|
0
|
|
|
|
return unless ($pathname ||= $self->{pathnames}{$pkg}); |
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
|
my $file = $pkg; $file =~ s!::!/!g; |
|
0
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
|
$file = "$self->{prefix}/$file.pm"; |
206
|
0
|
0
|
|
|
|
|
return if -f $file; # prevents infinite recursion |
207
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
$self->copy($pathname => $file); |
209
|
0
|
|
|
|
|
|
foreach my $pkg (@{"$pkg\::ISA"}) { |
|
0
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
|
$self->copy_package($pkg); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub pick { |
215
|
|
|
|
|
|
|
# determine which name to load |
216
|
0
|
|
|
0
|
0
|
|
my ($self, $method, $objects) = @_; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# XXX this whole thing needs to be discussed |
219
|
0
|
0
|
0
|
|
|
|
return $objects->[0] unless $#{$objects} > 0 and -t STDIN; |
|
0
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# sort by last modified time |
222
|
0
|
|
|
|
|
|
@$objects = map { $_->[0] } |
223
|
0
|
|
|
|
|
|
sort { $a->[1] <=> $b->[1] } |
224
|
0
|
|
|
|
|
|
map { [ $_ => -M $self->{pathnames}{ref($_)} ] } @$objects; |
|
0
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
|
226
|
0
|
|
|
|
|
|
print "Multiple extensions found for method '$method':\n"; |
227
|
0
|
|
|
|
|
|
foreach my $i ( 1 .. @$objects ) { |
228
|
0
|
|
|
|
|
|
print "\t$i. ", ref($objects->[$i-1]), "\n"; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
while ( 1 ) { |
232
|
0
|
|
|
|
|
|
print "Please select one [1]: "; |
233
|
0
|
|
|
|
|
|
chomp(my $choice = ); |
234
|
0
|
|
0
|
|
|
|
$choice ||= 1; |
235
|
0
|
0
|
0
|
|
|
|
return $objects->[$choice-1] if $choice > 0 and $choice <= @$objects; |
236
|
0
|
|
|
|
|
|
print "Invalid choice. "; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub delete_package { |
241
|
0
|
|
|
0
|
0
|
|
my ($self, $pkg) = @_; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# expand to full symbol table name if needed |
244
|
0
|
0
|
|
|
|
|
unless ( $pkg =~ /^main::.*::$/ ) { |
245
|
0
|
0
|
|
|
|
|
$pkg = "main$pkg" if $pkg =~ /^::/; |
246
|
0
|
0
|
|
|
|
|
$pkg = "main::$pkg" unless $pkg =~ /^main::/; |
247
|
0
|
0
|
|
|
|
|
$pkg .= '::' unless $pkg =~ /::$/; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
0
|
|
|
|
|
|
my($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/; |
251
|
0
|
|
|
|
|
|
my $stem_symtab = *{$stem}{HASH}; |
|
0
|
|
|
|
|
|
|
252
|
0
|
0
|
0
|
|
|
|
return unless defined $stem_symtab and exists $stem_symtab->{$leaf}; |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# free all the symbols in the package |
255
|
0
|
|
|
|
|
|
my $leaf_symtab = *{$stem_symtab->{$leaf}}{HASH}; |
|
0
|
|
|
|
|
|
|
256
|
0
|
|
|
|
|
|
foreach my $name (keys %$leaf_symtab) { |
257
|
0
|
0
|
|
|
|
|
next if $name eq "$self->{dispatch}::"; |
258
|
0
|
|
|
|
|
|
undef *{$pkg . $name}; |
|
0
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# delete the symbol table |
262
|
0
|
|
|
|
|
|
foreach my $name (keys %$leaf_symtab) { |
263
|
0
|
0
|
|
|
|
|
next if $name eq "$self->{dispatch}::"; |
264
|
0
|
|
|
|
|
|
delete $leaf_symtab->{$name}; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub AUTOLOAD { |
269
|
0
|
|
|
0
|
|
|
goto &{shift->autoload}; |
|
0
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
0
|
|
|
sub DESTROY { } |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
1; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
__END__ |