| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Module::Install::Admin; |
|
2
|
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
213050
|
use strict 'vars'; |
|
|
3
|
|
|
|
|
32
|
|
|
|
3
|
|
|
|
|
99
|
|
|
4
|
3
|
|
|
3
|
|
17
|
use File::Path (); |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
40
|
|
|
5
|
3
|
|
|
3
|
|
1391
|
use inc::Module::Install (); |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
97
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
3
|
|
|
3
|
|
19
|
use vars qw{$VERSION @ISA}; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
185
|
|
|
8
|
|
|
|
|
|
|
BEGIN { |
|
9
|
3
|
|
|
3
|
|
11
|
$VERSION = '1.21'; |
|
10
|
3
|
|
|
|
|
284
|
@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<Module::Install> 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<Module::Install::Admin::*> namespace that provides the method |
|
38
|
|
|
|
|
|
|
C<some_method>. See L</METHODS> 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<never> included under a distribution's |
|
45
|
|
|
|
|
|
|
F<inc/> directory, nor are any of the B<Module::Install::Admin::*> |
|
46
|
|
|
|
|
|
|
extensions. |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
For normal usage of B<Module::Install>, please see L<Module::Install> |
|
49
|
|
|
|
|
|
|
and L<Module::Install/"COOKBOOK / EXAMPLES"> instead. |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head2 Bootstrapping |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
When someone runs a F<Makefile.PL> that has C<use inc::Module::Install>, |
|
54
|
|
|
|
|
|
|
and there is no F<inc/> in the current directory, B<Module::Install> |
|
55
|
|
|
|
|
|
|
will load this module bootstrap itself, through the steps below: |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=over 4 |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item * |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
First, F<Module/Install.pm> is POD-stripped and copied from C<@INC> to |
|
62
|
|
|
|
|
|
|
F<inc/>. This should only happen on the author's side, never on the |
|
63
|
|
|
|
|
|
|
end-user side. |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=item * |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Reload F<inc/Module/Install.pm> if the current file is somewhere else. |
|
68
|
|
|
|
|
|
|
This ensures that the included version of F<inc/Module/Install.pm> is |
|
69
|
|
|
|
|
|
|
always preferred over the installed version. |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item * |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Look at F<inc/Module/Install/*.pm> and load all of them. |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item * |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Set up a C<main::AUTOLOAD> function to delegate missing function calls |
|
78
|
|
|
|
|
|
|
to C<Module::Install::Admin::load> -- again, this should only happen |
|
79
|
|
|
|
|
|
|
at the author's side. |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item * |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Provide a C<Module::Install::purge_self> function for removing included |
|
84
|
|
|
|
|
|
|
files under F<inc/>. |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=back |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=head1 METHODS |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=cut |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub import { |
|
93
|
2
|
|
|
2
|
|
20
|
my $class = shift; |
|
94
|
2
|
|
|
|
|
8
|
my $self = $class->new( _top => Module::Install->new, @_ ); |
|
95
|
2
|
|
|
|
|
11
|
local $^W; |
|
96
|
2
|
|
|
|
|
81
|
*{caller(0) . "::AUTOLOAD"} = sub { |
|
97
|
3
|
|
|
3
|
|
23
|
no strict 'vars'; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
4812
|
|
|
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
|
|
|
|
|
11
|
}; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub new { |
|
107
|
2
|
|
|
2
|
0
|
9
|
my ($class, %args) = @_; |
|
108
|
|
|
|
|
|
|
return $class->SUPER::new( |
|
109
|
2
|
|
|
|
|
4
|
%{$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
|
6807
|
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
|
|
|
|
|
6
|
chomp $to; |
|
136
|
|
|
|
|
|
|
|
|
137
|
1
|
|
|
|
|
2
|
local ($_); |
|
138
|
1
|
50
|
|
|
|
42
|
open my $FROM, "<", $from or die "Can't open $from for input:\n$!"; |
|
139
|
1
|
50
|
|
|
|
68
|
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
|
|
|
|
|
26
|
while ( <$FROM> ) { |
|
148
|
3
|
50
|
33
|
|
|
16
|
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
|
|
|
|
|
19
|
print $TO $_; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
1
|
50
|
|
|
|
15
|
close $FROM or die "Can't close $from for input:\n$!"; |
|
159
|
1
|
50
|
|
|
|
35
|
close $TO or die "Can't close $to for output:\n$!"; |
|
160
|
|
|
|
|
|
|
|
|
161
|
1
|
|
|
|
|
67
|
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 = <STDIN>); |
|
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__ |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=pod |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
L<Module::Install> |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head1 AUTHORS |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Audrey Tang E<lt>autrijus@autrijus.orgE<gt> |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Copyright 2003, 2004 by Audrey Tang E<lt>autrijus@autrijus.orgE<gt>. |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
293
|
|
|
|
|
|
|
under the same terms as Perl itself. |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
See L<http://www.perl.com/perl/misc/Artistic.html> |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=cut |