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