Upgrade to CPAN-1.88_53.
[p5sagit/p5-mst-13.2.git] / lib / ExtUtils / Installed.pm
CommitLineData
354f3b56 1package ExtUtils::Installed;
17f410f9 2
57b1a898 3use 5.00503;
354f3b56 4use strict;
5use Carp qw();
6use ExtUtils::Packlist;
7use ExtUtils::MakeMaker;
8use Config;
9use File::Find;
10use File::Basename;
5de3f0da 11use File::Spec;
007a26ab 12
dedf98bc 13my $Is_VMS = $^O eq 'VMS';
007a26ab 14my $DOSISH = ($^O =~ /^(MSWin\d\d|os2|dos|mint)$/);
15
dedf98bc 16require VMS::Filespec if $Is_VMS;
17
18use vars qw($VERSION);
f62a57de 19$VERSION = '1.41';
3a465856 20$VERSION = eval $VERSION;
dedf98bc 21
f6d6199c 22sub _is_prefix {
23 my ($self, $path, $prefix) = @_;
24 return unless defined $prefix && defined $path;
25
dedf98bc 26 if( $Is_VMS ) {
f6d6199c 27 $prefix = VMS::Filespec::unixify($prefix);
28 $path = VMS::Filespec::unixify($path);
29 }
2c91f887 30
31 # Sloppy Unix path normalization.
32 $prefix =~ s{/+}{/}g;
33 $path =~ s{/+}{/}g;
30127843 34
f6d6199c 35 return 1 if substr($path, 0, length($prefix)) eq $prefix;
36
37 if ($DOSISH) {
38 $path =~ s|\\|/|g;
39 $prefix =~ s|\\|/|g;
40 return 1 if $path =~ m{^\Q$prefix\E}i;
41 }
42 return(0);
007a26ab 43}
354f3b56 44
3a465856 45sub _is_doc {
f6d6199c 46 my ($self, $path) = @_;
47 my $man1dir = $Config{man1direxp};
48 my $man3dir = $Config{man3direxp};
49 return(($man1dir && $self->_is_prefix($path, $man1dir))
50 ||
51 ($man3dir && $self->_is_prefix($path, $man3dir))
52 ? 1 : 0)
34dcf69d 53}
3a465856 54
f6d6199c 55sub _is_type {
56 my ($self, $path, $type) = @_;
57 return 1 if $type eq "all";
58
59 return($self->_is_doc($path)) if $type eq "doc";
60
61 if ($type eq "prog") {
62 return($self->_is_prefix($path, $Config{prefix} || $Config{prefixexp})
63 &&
64 !($self->_is_doc($path))
65 ? 1 : 0);
66 }
67 return(0);
354f3b56 68}
69
f6d6199c 70sub _is_under {
71 my ($self, $path, @under) = @_;
72 $under[0] = "" if (! @under);
73 foreach my $dir (@under) {
74 return(1) if ($self->_is_prefix($path, $dir));
75 }
354f3b56 76
f6d6199c 77 return(0);
354f3b56 78}
79
f6d6199c 80sub new {
81 my ($class) = @_;
82 $class = ref($class) || $class;
83 my $self = {};
84
85 my $archlib = $Config{archlibexp};
86 my $sitearch = $Config{sitearchexp};
87
88 # File::Find does not know how to deal with VMS filepaths.
dedf98bc 89 if( $Is_VMS ) {
f6d6199c 90 $archlib = VMS::Filespec::unixify($archlib);
91 $sitearch = VMS::Filespec::unixify($sitearch);
92 }
93
94 if ($DOSISH) {
95 $archlib =~ s|\\|/|g;
96 $sitearch =~ s|\\|/|g;
97 }
98
99 # Read the core packlist
100 $self->{Perl}{packlist} =
101 ExtUtils::Packlist->new( File::Spec->catfile($archlib, '.packlist') );
102 $self->{Perl}{version} = $Config{version};
103
104 # Read the module packlists
105 my $sub = sub {
106 # Only process module .packlists
dedf98bc 107 return if $_ ne ".packlist" || $File::Find::dir eq $archlib;
f6d6199c 108
109 # Hack of the leading bits of the paths & convert to a module name
110 my $module = $File::Find::name;
111
112 $module =~ s!\Q$archlib\E/?auto/(.*)/.packlist!$1!s or
113 $module =~ s!\Q$sitearch\E/?auto/(.*)/.packlist!$1!s;
114 my $modfile = "$module.pm";
115 $module =~ s!/!::!g;
116
117 # Find the top-level module file in @INC
118 $self->{$module}{version} = '';
119 foreach my $dir (@INC) {
120 my $p = File::Spec->catfile($dir, $modfile);
dedf98bc 121 if (-r $p) {
122 $module = _module_name($p, $module) if $Is_VMS;
123
f6d6199c 124 require ExtUtils::MM;
125 $self->{$module}{version} = MM->parse_version($p);
126 last;
127 }
128 }
129
130 # Read the .packlist
3a465856 131 $self->{$module}{packlist} =
f6d6199c 132 ExtUtils::Packlist->new($File::Find::name);
133 };
134
135 my(@dirs) = grep { -e } ($archlib, $sitearch);
136 find($sub, @dirs) if @dirs;
137
138 return(bless($self, $class));
354f3b56 139}
140
dedf98bc 141# VMS's non-case preserving file-system means the package name can't
142# be reconstructed from the filename.
143sub _module_name {
144 my($file, $orig_module) = @_;
145
146 my $module = '';
147 if (open PACKFH, $file) {
148 while (<PACKFH>) {
149 if (/package\s+(\S+)\s*;/) {
150 my $pack = $1;
151 # Make a sanity check, that lower case $module
152 # is identical to lowercase $pack before
153 # accepting it
154 if (lc($pack) eq lc($orig_module)) {
155 $module = $pack;
156 last;
157 }
158 }
159 }
160 close PACKFH;
161 }
162
163 print STDERR "Couldn't figure out the package name for $file\n"
164 unless $module;
165
166 return $module;
167}
168
169
170
f6d6199c 171sub modules {
172 my ($self) = @_;
d5d4ec93 173
174 # Bug/feature of sort in scalar context requires this.
175 return wantarray ? sort keys %$self : keys %$self;
354f3b56 176}
177
f6d6199c 178sub files {
179 my ($self, $module, $type, @under) = @_;
180
181 # Validate arguments
182 Carp::croak("$module is not installed") if (! exists($self->{$module}));
183 $type = "all" if (! defined($type));
184 Carp::croak('type must be "all", "prog" or "doc"')
185 if ($type ne "all" && $type ne "prog" && $type ne "doc");
186
187 my (@files);
188 foreach my $file (keys(%{$self->{$module}{packlist}})) {
189 push(@files, $file)
3a465856 190 if ($self->_is_type($file, $type) &&
f6d6199c 191 $self->_is_under($file, @under));
192 }
193 return(@files);
354f3b56 194}
195
f6d6199c 196sub directories {
197 my ($self, $module, $type, @under) = @_;
198 my (%dirs);
199 foreach my $file ($self->files($module, $type, @under)) {
200 $dirs{dirname($file)}++;
201 }
202 return sort keys %dirs;
354f3b56 203}
204
f6d6199c 205sub directory_tree {
206 my ($self, $module, $type, @under) = @_;
207 my (%dirs);
208 foreach my $dir ($self->directories($module, $type, @under)) {
209 $dirs{$dir}++;
210 my ($last) = ("");
211 while ($last ne $dir) {
212 $last = $dir;
213 $dir = dirname($dir);
214 last if !$self->_is_under($dir, @under);
215 $dirs{$dir}++;
216 }
217 }
218 return(sort(keys(%dirs)));
354f3b56 219}
220
f6d6199c 221sub validate {
222 my ($self, $module, $remove) = @_;
223 Carp::croak("$module is not installed") if (! exists($self->{$module}));
224 return($self->{$module}{packlist}->validate($remove));
354f3b56 225}
226
f6d6199c 227sub packlist {
228 my ($self, $module) = @_;
229 Carp::croak("$module is not installed") if (! exists($self->{$module}));
230 return($self->{$module}{packlist});
354f3b56 231}
232
f6d6199c 233sub version {
234 my ($self, $module) = @_;
235 Carp::croak("$module is not installed") if (! exists($self->{$module}));
236 return($self->{$module}{version});
354f3b56 237}
238
f6d6199c 239
354f3b56 2401;
241
242__END__
243
244=head1 NAME
245
246ExtUtils::Installed - Inventory management of installed modules
247
248=head1 SYNOPSIS
249
250 use ExtUtils::Installed;
251 my ($inst) = ExtUtils::Installed->new();
252 my (@modules) = $inst->modules();
253 my (@missing) = $inst->validate("DBI");
254 my $all_files = $inst->files("DBI");
255 my $files_below_usr_local = $inst->files("DBI", "all", "/usr/local");
256 my $all_dirs = $inst->directories("DBI");
257 my $dirs_below_usr_local = $inst->directory_tree("DBI", "prog");
258 my $packlist = $inst->packlist("DBI");
259
260=head1 DESCRIPTION
261
262ExtUtils::Installed provides a standard way to find out what core and module
263files have been installed. It uses the information stored in .packlist files
264created during installation to provide this information. In addition it
265provides facilities to classify the installed files and to extract directory
266information from the .packlist files.
267
268=head1 USAGE
269
270The new() function searches for all the installed .packlists on the system, and
271stores their contents. The .packlists can be queried with the functions
272described below.
273
274=head1 FUNCTIONS
275
bbc7dcd2 276=over 4
354f3b56 277
278=item new()
279
280This takes no parameters, and searches for all the installed .packlists on the
281system. The packlists are read using the ExtUtils::packlist module.
282
283=item modules()
284
285This returns a list of the names of all the installed modules. The perl 'core'
286is given the special name 'Perl'.
287
288=item files()
289
290This takes one mandatory parameter, the name of a module. It returns a list of
291all the filenames from the package. To obtain a list of core perl files, use
292the module name 'Perl'. Additional parameters are allowed. The first is one
34dcf69d 293of the strings "prog", "doc" or "all", to select either just program files,
354f3b56 294just manual files or all files. The remaining parameters are a list of
295directories. The filenames returned will be restricted to those under the
296specified directories.
297
298=item directories()
299
300This takes one mandatory parameter, the name of a module. It returns a list of
301all the directories from the package. Additional parameters are allowed. The
34dcf69d 302first is one of the strings "prog", "doc" or "all", to select either just
354f3b56 303program directories, just manual directories or all directories. The remaining
304parameters are a list of directories. The directories returned will be
305restricted to those under the specified directories. This method returns only
306the leaf directories that contain files from the specified module.
307
308=item directory_tree()
309
34dcf69d 310This is identical in operation to directories(), except that it includes all the
354f3b56 311intermediate directories back up to the specified directories.
312
313=item validate()
314
315This takes one mandatory parameter, the name of a module. It checks that all
316the files listed in the modules .packlist actually exist, and returns a list of
317any missing files. If an optional second argument which evaluates to true is
318given any missing files will be removed from the .packlist
319
320=item packlist()
321
322This returns the ExtUtils::Packlist object for the specified module.
323
324=item version()
325
326This returns the version number for the specified module.
327
328=back
329
ddf41153 330=head1 EXAMPLE
331
332See the example in L<ExtUtils::Packlist>.
333
354f3b56 334=head1 AUTHOR
335
336Alan Burlison <Alan.Burlison@uk.sun.com>
337
338=cut