Fixes for ext/compress
[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);
060fb22c 19$VERSION = '1.43';
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) = @_;
060fb22c 47
48 my $man1dir = $self->{':private:'}{Config}{man1direxp};
49 my $man3dir = $self->{':private:'}{Config}{man3direxp};
f6d6199c 50 return(($man1dir && $self->_is_prefix($path, $man1dir))
51 ||
52 ($man3dir && $self->_is_prefix($path, $man3dir))
53 ? 1 : 0)
34dcf69d 54}
3a465856 55
f6d6199c 56sub _is_type {
57 my ($self, $path, $type) = @_;
58 return 1 if $type eq "all";
59
60 return($self->_is_doc($path)) if $type eq "doc";
61
62 if ($type eq "prog") {
060fb22c 63 return($self->_is_prefix($path, $self->{':private:'}{Config}{prefix} || $self->{':private:'}{Config}{prefixexp})
f6d6199c 64 &&
65 !($self->_is_doc($path))
66 ? 1 : 0);
67 }
68 return(0);
354f3b56 69}
70
f6d6199c 71sub _is_under {
72 my ($self, $path, @under) = @_;
73 $under[0] = "" if (! @under);
74 foreach my $dir (@under) {
75 return(1) if ($self->_is_prefix($path, $dir));
76 }
354f3b56 77
f6d6199c 78 return(0);
354f3b56 79}
80
f6d6199c 81sub new {
060fb22c 82 my ($class) = shift(@_);
f6d6199c 83 $class = ref($class) || $class;
f6d6199c 84
060fb22c 85 my %args = @_;
f6d6199c 86
060fb22c 87 my $self = {};
88
89 if ($args{config_override}) {
90 eval {
91 $self->{':private:'}{Config} = { %{$args{config_override}} };
92 } or Carp::croak(
93 "The 'config_override' parameter must be a hash reference."
94 );
95 }
96 else {
97 $self->{':private:'}{Config} = \%Config;
98 }
99
100 for my $tuple ([inc_override => INC => [ @INC ] ],
101 [ extra_libs => EXTRA => [] ])
102 {
103 my ($arg,$key,$val)=@$tuple;
104 if ( $args{$arg} ) {
105 eval {
106 $self->{':private:'}{$key} = [ @{$args{$arg}} ];
107 } or Carp::croak(
108 "The '$arg' parameter must be an array reference."
109 );
110 }
111 elsif ($val) {
112 $self->{':private:'}{$key} = $val;
113 }
114 }
115 {
116 my %dupe;
117 @{$self->{':private:'}{INC}} = grep { -e $_ && !$dupe{$_}++ }
118 @{$self->{':private:'}{INC}}, @{$self->{':private:'}{EXTRA}};
119 }
120 my $perl5lib = defined $ENV{PERL5LIB} ? $ENV{PERL5LIB} : "";
121
122 my @dirs = ( $self->{':private:'}{Config}{archlibexp},
123 $self->{':private:'}{Config}{sitearchexp},
124 split(/\Q$Config{path_sep}\E/, $perl5lib),
125 @{$self->{':private:'}{EXTRA}},
126 );
127
f6d6199c 128 # File::Find does not know how to deal with VMS filepaths.
dedf98bc 129 if( $Is_VMS ) {
060fb22c 130 $_ = VMS::Filespec::unixify($_)
131 for @dirs;
f6d6199c 132 }
133
134 if ($DOSISH) {
060fb22c 135 s|\\|/|g for @dirs;
f6d6199c 136 }
060fb22c 137 my $archlib = $dirs[0];
138
f6d6199c 139 # Read the core packlist
140 $self->{Perl}{packlist} =
141 ExtUtils::Packlist->new( File::Spec->catfile($archlib, '.packlist') );
060fb22c 142 $self->{Perl}{version} = $self->{':private:'}{Config}{version};
f6d6199c 143
144 # Read the module packlists
145 my $sub = sub {
146 # Only process module .packlists
dedf98bc 147 return if $_ ne ".packlist" || $File::Find::dir eq $archlib;
f6d6199c 148
149 # Hack of the leading bits of the paths & convert to a module name
150 my $module = $File::Find::name;
060fb22c 151 my $found;
152 for (@dirs) {
153 $found = $module =~ s!\Q$_\E/?auto/(.*)/.packlist!$1!s
154 and last;
155 }
156 unless ($found) {
157 # warn "Woah! \$_=$_\n\$module=$module\n\$File::Find::dir=$File::Find::dir\n",
158 # join ("\n",@dirs);
159 return;
160 }
f6d6199c 161 my $modfile = "$module.pm";
162 $module =~ s!/!::!g;
163
164 # Find the top-level module file in @INC
165 $self->{$module}{version} = '';
060fb22c 166 foreach my $dir (@{$self->{':private:'}{INC}}) {
f6d6199c 167 my $p = File::Spec->catfile($dir, $modfile);
dedf98bc 168 if (-r $p) {
169 $module = _module_name($p, $module) if $Is_VMS;
170
f6d6199c 171 $self->{$module}{version} = MM->parse_version($p);
172 last;
173 }
174 }
175
176 # Read the .packlist
3a465856 177 $self->{$module}{packlist} =
f6d6199c 178 ExtUtils::Packlist->new($File::Find::name);
179 };
060fb22c 180 my %dupe;
181 @dirs= grep { -e $_ && !$dupe{$_}++ } @dirs;
182 $self->{':private:'}{LIBDIRS} = \@dirs;
f6d6199c 183 find($sub, @dirs) if @dirs;
184
185 return(bless($self, $class));
354f3b56 186}
187
dedf98bc 188# VMS's non-case preserving file-system means the package name can't
189# be reconstructed from the filename.
190sub _module_name {
191 my($file, $orig_module) = @_;
192
193 my $module = '';
194 if (open PACKFH, $file) {
195 while (<PACKFH>) {
196 if (/package\s+(\S+)\s*;/) {
197 my $pack = $1;
198 # Make a sanity check, that lower case $module
199 # is identical to lowercase $pack before
200 # accepting it
201 if (lc($pack) eq lc($orig_module)) {
202 $module = $pack;
203 last;
204 }
205 }
206 }
207 close PACKFH;
208 }
209
210 print STDERR "Couldn't figure out the package name for $file\n"
211 unless $module;
212
213 return $module;
214}
215
216
217
f6d6199c 218sub modules {
219 my ($self) = @_;
d5d4ec93 220
221 # Bug/feature of sort in scalar context requires this.
060fb22c 222 return wantarray
223 ? sort grep { not /^:private:$/ } keys %$self
224 : grep { not /^:private:$/ } keys %$self;
354f3b56 225}
226
f6d6199c 227sub files {
228 my ($self, $module, $type, @under) = @_;
229
230 # Validate arguments
231 Carp::croak("$module is not installed") if (! exists($self->{$module}));
232 $type = "all" if (! defined($type));
233 Carp::croak('type must be "all", "prog" or "doc"')
234 if ($type ne "all" && $type ne "prog" && $type ne "doc");
235
236 my (@files);
237 foreach my $file (keys(%{$self->{$module}{packlist}})) {
238 push(@files, $file)
3a465856 239 if ($self->_is_type($file, $type) &&
f6d6199c 240 $self->_is_under($file, @under));
241 }
242 return(@files);
354f3b56 243}
244
f6d6199c 245sub directories {
246 my ($self, $module, $type, @under) = @_;
247 my (%dirs);
248 foreach my $file ($self->files($module, $type, @under)) {
249 $dirs{dirname($file)}++;
250 }
251 return sort keys %dirs;
354f3b56 252}
253
f6d6199c 254sub directory_tree {
255 my ($self, $module, $type, @under) = @_;
256 my (%dirs);
257 foreach my $dir ($self->directories($module, $type, @under)) {
258 $dirs{$dir}++;
259 my ($last) = ("");
260 while ($last ne $dir) {
261 $last = $dir;
262 $dir = dirname($dir);
263 last if !$self->_is_under($dir, @under);
264 $dirs{$dir}++;
265 }
266 }
267 return(sort(keys(%dirs)));
354f3b56 268}
269
f6d6199c 270sub validate {
271 my ($self, $module, $remove) = @_;
272 Carp::croak("$module is not installed") if (! exists($self->{$module}));
273 return($self->{$module}{packlist}->validate($remove));
354f3b56 274}
275
f6d6199c 276sub packlist {
277 my ($self, $module) = @_;
278 Carp::croak("$module is not installed") if (! exists($self->{$module}));
279 return($self->{$module}{packlist});
354f3b56 280}
281
f6d6199c 282sub version {
283 my ($self, $module) = @_;
284 Carp::croak("$module is not installed") if (! exists($self->{$module}));
285 return($self->{$module}{version});
354f3b56 286}
287
f6d6199c 288
354f3b56 2891;
290
291__END__
292
293=head1 NAME
294
295ExtUtils::Installed - Inventory management of installed modules
296
297=head1 SYNOPSIS
298
299 use ExtUtils::Installed;
300 my ($inst) = ExtUtils::Installed->new();
301 my (@modules) = $inst->modules();
302 my (@missing) = $inst->validate("DBI");
303 my $all_files = $inst->files("DBI");
304 my $files_below_usr_local = $inst->files("DBI", "all", "/usr/local");
305 my $all_dirs = $inst->directories("DBI");
306 my $dirs_below_usr_local = $inst->directory_tree("DBI", "prog");
307 my $packlist = $inst->packlist("DBI");
308
309=head1 DESCRIPTION
310
311ExtUtils::Installed provides a standard way to find out what core and module
312files have been installed. It uses the information stored in .packlist files
313created during installation to provide this information. In addition it
314provides facilities to classify the installed files and to extract directory
315information from the .packlist files.
316
317=head1 USAGE
318
319The new() function searches for all the installed .packlists on the system, and
320stores their contents. The .packlists can be queried with the functions
060fb22c 321described below. Where it searches by default is determined by the settings found
322in C<%Config::Config>, and what the value is of the PERL5LIB environment variable.
354f3b56 323
324=head1 FUNCTIONS
325
bbc7dcd2 326=over 4
354f3b56 327
328=item new()
329
060fb22c 330This takes optional named parameters. Without parameters, this
331searches for all the installed .packlists on the system using
332information from C<%Config::Config> and the default module search
333paths C<@INC>. The packlists are read using the
334L<ExtUtils::Packlist> module.
335
336If the named parameter C<config_override> is specified,
337it should be a reference to a hash which contains all information
338usually found in C<%Config::Config>. For example, you can obtain
339the configuration information for a separate perl installation and
340pass that in.
341
342 my $yoda_cfg = get_fake_config('yoda');
343 my $yoda_inst = ExtUtils::Installed->new(config_override=>$yoda_cfg);
344
345Similarly, the parameter C<inc_override> may be a reference to an
346array which is used in place of the default module search paths
347from C<@INC>.
348
349 use Config;
350 my @dirs = split(/\Q$Config{path_sep}\E/, $ENV{PERL5LIB});
351 my $p5libs = ExtUtils::Installed->new(inc_override=>\@dirs);
352
353The parameter c<extra_libs> can be used to specify B<additional> paths to
354search for installed modules. For instance
355
356 my $installed = ExtUtils::Installed->new(extra_libs=>["/my/lib/path"]);
357
358This should only be necessary if C</my/lib/path> is not in PERL5LIB.
354f3b56 359
360=item modules()
361
362This returns a list of the names of all the installed modules. The perl 'core'
363is given the special name 'Perl'.
364
365=item files()
366
367This takes one mandatory parameter, the name of a module. It returns a list of
368all the filenames from the package. To obtain a list of core perl files, use
369the module name 'Perl'. Additional parameters are allowed. The first is one
34dcf69d 370of the strings "prog", "doc" or "all", to select either just program files,
354f3b56 371just manual files or all files. The remaining parameters are a list of
372directories. The filenames returned will be restricted to those under the
373specified directories.
374
375=item directories()
376
377This takes one mandatory parameter, the name of a module. It returns a list of
378all the directories from the package. Additional parameters are allowed. The
34dcf69d 379first is one of the strings "prog", "doc" or "all", to select either just
354f3b56 380program directories, just manual directories or all directories. The remaining
381parameters are a list of directories. The directories returned will be
382restricted to those under the specified directories. This method returns only
383the leaf directories that contain files from the specified module.
384
385=item directory_tree()
386
34dcf69d 387This is identical in operation to directories(), except that it includes all the
354f3b56 388intermediate directories back up to the specified directories.
389
390=item validate()
391
392This takes one mandatory parameter, the name of a module. It checks that all
393the files listed in the modules .packlist actually exist, and returns a list of
394any missing files. If an optional second argument which evaluates to true is
395given any missing files will be removed from the .packlist
396
397=item packlist()
398
399This returns the ExtUtils::Packlist object for the specified module.
400
401=item version()
402
403This returns the version number for the specified module.
404
405=back
406
ddf41153 407=head1 EXAMPLE
408
409See the example in L<ExtUtils::Packlist>.
410
354f3b56 411=head1 AUTHOR
412
413Alan Burlison <Alan.Burlison@uk.sun.com>
414
415=cut