1eac174f2Safresh1use strict; 2b8851fccSafresh1package ExtUtils::Installed; 3b8851fccSafresh1 4b8851fccSafresh1#use warnings; # XXX requires 5.6 5b8851fccSafresh1use Carp qw(); 6b8851fccSafresh1use ExtUtils::Packlist; 7b8851fccSafresh1use ExtUtils::MakeMaker; 8b8851fccSafresh1use Config; 9b8851fccSafresh1use File::Find; 10b8851fccSafresh1use File::Basename; 11b8851fccSafresh1use File::Spec; 12b8851fccSafresh1 13b8851fccSafresh1my $Is_VMS = $^O eq 'VMS'; 14b8851fccSafresh1my $DOSISH = ($^O =~ /^(MSWin\d\d|os2|dos|mint)$/); 15b8851fccSafresh1 16b8851fccSafresh1require VMS::Filespec if $Is_VMS; 17b8851fccSafresh1 18*e0680481Safresh1our $VERSION = '2.22'; 19b8851fccSafresh1$VERSION = eval $VERSION; 20b8851fccSafresh1 21b8851fccSafresh1sub _is_prefix { 22b8851fccSafresh1 my ($self, $path, $prefix) = @_; 23b8851fccSafresh1 return unless defined $prefix && defined $path; 24b8851fccSafresh1 25b8851fccSafresh1 if( $Is_VMS ) { 26b8851fccSafresh1 $prefix = VMS::Filespec::unixify($prefix); 27b8851fccSafresh1 $path = VMS::Filespec::unixify($path); 28b8851fccSafresh1 } 29b8851fccSafresh1 30b8851fccSafresh1 # Unix path normalization. 31b8851fccSafresh1 $prefix = File::Spec->canonpath($prefix); 32b8851fccSafresh1 33b8851fccSafresh1 return 1 if substr($path, 0, length($prefix)) eq $prefix; 34b8851fccSafresh1 35b8851fccSafresh1 if ($DOSISH) { 36b8851fccSafresh1 $path =~ s|\\|/|g; 37b8851fccSafresh1 $prefix =~ s|\\|/|g; 38b8851fccSafresh1 return 1 if $path =~ m{^\Q$prefix\E}i; 39b8851fccSafresh1 } 40b8851fccSafresh1 return(0); 41b8851fccSafresh1} 42b8851fccSafresh1 43b8851fccSafresh1sub _is_doc { 44b8851fccSafresh1 my ($self, $path) = @_; 45b8851fccSafresh1 46b8851fccSafresh1 my $man1dir = $self->{':private:'}{Config}{man1direxp}; 47b8851fccSafresh1 my $man3dir = $self->{':private:'}{Config}{man3direxp}; 48b8851fccSafresh1 return(($man1dir && $self->_is_prefix($path, $man1dir)) 49b8851fccSafresh1 || 50b8851fccSafresh1 ($man3dir && $self->_is_prefix($path, $man3dir)) 51b8851fccSafresh1 ? 1 : 0) 52b8851fccSafresh1} 53b8851fccSafresh1 54b8851fccSafresh1sub _is_type { 55b8851fccSafresh1 my ($self, $path, $type) = @_; 56b8851fccSafresh1 return 1 if $type eq "all"; 57b8851fccSafresh1 58b8851fccSafresh1 return($self->_is_doc($path)) if $type eq "doc"; 59b8851fccSafresh1 my $conf= $self->{':private:'}{Config}; 60b8851fccSafresh1 if ($type eq "prog") { 61b8851fccSafresh1 return($self->_is_prefix($path, $conf->{prefix} || $conf->{prefixexp}) 62b8851fccSafresh1 && !($self->_is_doc($path)) ? 1 : 0); 63b8851fccSafresh1 } 64b8851fccSafresh1 return(0); 65b8851fccSafresh1} 66b8851fccSafresh1 67b8851fccSafresh1sub _is_under { 68b8851fccSafresh1 my ($self, $path, @under) = @_; 69b8851fccSafresh1 $under[0] = "" if (! @under); 70b8851fccSafresh1 foreach my $dir (@under) { 71b8851fccSafresh1 return(1) if ($self->_is_prefix($path, $dir)); 72b8851fccSafresh1 } 73b8851fccSafresh1 74b8851fccSafresh1 return(0); 75b8851fccSafresh1} 76b8851fccSafresh1 77b8851fccSafresh1sub _fix_dirs { 78b8851fccSafresh1 my ($self, @dirs)= @_; 79b8851fccSafresh1 # File::Find does not know how to deal with VMS filepaths. 80b8851fccSafresh1 if( $Is_VMS ) { 81b8851fccSafresh1 $_ = VMS::Filespec::unixify($_) 82b8851fccSafresh1 for @dirs; 83b8851fccSafresh1 } 84b8851fccSafresh1 85b8851fccSafresh1 if ($DOSISH) { 86b8851fccSafresh1 s|\\|/|g for @dirs; 87b8851fccSafresh1 } 88b8851fccSafresh1 return wantarray ? @dirs : $dirs[0]; 89b8851fccSafresh1} 90b8851fccSafresh1 91b8851fccSafresh1sub _make_entry { 92b8851fccSafresh1 my ($self, $module, $packlist_file, $modfile)= @_; 93b8851fccSafresh1 94b8851fccSafresh1 my $data= { 95b8851fccSafresh1 module => $module, 96b8851fccSafresh1 packlist => scalar(ExtUtils::Packlist->new($packlist_file)), 97b8851fccSafresh1 packlist_file => $packlist_file, 98b8851fccSafresh1 }; 99b8851fccSafresh1 100b8851fccSafresh1 if (!$modfile) { 101b8851fccSafresh1 $data->{version} = $self->{':private:'}{Config}{version}; 102b8851fccSafresh1 } else { 103b8851fccSafresh1 $data->{modfile} = $modfile; 104b8851fccSafresh1 # Find the top-level module file in @INC 105b8851fccSafresh1 $data->{version} = ''; 106b8851fccSafresh1 foreach my $dir (@{$self->{':private:'}{INC}}) { 107b8851fccSafresh1 my $p = File::Spec->catfile($dir, $modfile); 108b8851fccSafresh1 if (-r $p) { 109b8851fccSafresh1 $module = _module_name($p, $module) if $Is_VMS; 110b8851fccSafresh1 111b8851fccSafresh1 $data->{version} = MM->parse_version($p); 112b8851fccSafresh1 $data->{version_from} = $p; 113b8851fccSafresh1 $data->{packlist_valid} = exists $data->{packlist}{$p}; 114b8851fccSafresh1 last; 115b8851fccSafresh1 } 116b8851fccSafresh1 } 117b8851fccSafresh1 } 118b8851fccSafresh1 $self->{$module}= $data; 119b8851fccSafresh1} 120b8851fccSafresh1 121b8851fccSafresh1our $INSTALLED; 122b8851fccSafresh1sub new { 123b8851fccSafresh1 my ($class) = shift(@_); 124b8851fccSafresh1 $class = ref($class) || $class; 125b8851fccSafresh1 126b8851fccSafresh1 my %args = @_; 127b8851fccSafresh1 128b8851fccSafresh1 return $INSTALLED if $INSTALLED and ($args{default_get} || $args{default}); 129b8851fccSafresh1 130b8851fccSafresh1 my $self = bless {}, $class; 131b8851fccSafresh1 132b8851fccSafresh1 $INSTALLED= $self if $args{default_set} || $args{default}; 133b8851fccSafresh1 134b8851fccSafresh1 135b8851fccSafresh1 if ($args{config_override}) { 136b8851fccSafresh1 eval { 137b8851fccSafresh1 $self->{':private:'}{Config} = { %{$args{config_override}} }; 138b8851fccSafresh1 } or Carp::croak( 139b8851fccSafresh1 "The 'config_override' parameter must be a hash reference." 140b8851fccSafresh1 ); 141b8851fccSafresh1 } 142b8851fccSafresh1 else { 143b8851fccSafresh1 $self->{':private:'}{Config} = \%Config; 144b8851fccSafresh1 } 145b8851fccSafresh1 146b8851fccSafresh1 for my $tuple ([inc_override => INC => [ @INC ] ], 147b8851fccSafresh1 [ extra_libs => EXTRA => [] ]) 148b8851fccSafresh1 { 149b8851fccSafresh1 my ($arg,$key,$val)=@$tuple; 150b8851fccSafresh1 if ( $args{$arg} ) { 151b8851fccSafresh1 eval { 152b8851fccSafresh1 $self->{':private:'}{$key} = [ @{$args{$arg}} ]; 153b8851fccSafresh1 } or Carp::croak( 154b8851fccSafresh1 "The '$arg' parameter must be an array reference." 155b8851fccSafresh1 ); 156b8851fccSafresh1 } 157b8851fccSafresh1 elsif ($val) { 158b8851fccSafresh1 $self->{':private:'}{$key} = $val; 159b8851fccSafresh1 } 160b8851fccSafresh1 } 161b8851fccSafresh1 { 162b8851fccSafresh1 my %dupe; 163b8851fccSafresh1 @{$self->{':private:'}{LIBDIRS}} = 164b8851fccSafresh1 grep { $_ ne '.' || ! $args{skip_cwd} } 165b8851fccSafresh1 grep { -e $_ && !$dupe{$_}++ } 166b8851fccSafresh1 @{$self->{':private:'}{EXTRA}}, @{$self->{':private:'}{INC}}; 167b8851fccSafresh1 } 168b8851fccSafresh1 169b8851fccSafresh1 my @dirs= $self->_fix_dirs(@{$self->{':private:'}{LIBDIRS}}); 170b8851fccSafresh1 171b8851fccSafresh1 # Read the core packlist 172b8851fccSafresh1 my $archlib = $self->_fix_dirs($self->{':private:'}{Config}{archlibexp}); 173b8851fccSafresh1 $self->_make_entry("Perl",File::Spec->catfile($archlib, '.packlist')); 174b8851fccSafresh1 175b8851fccSafresh1 my $root; 176b8851fccSafresh1 # Read the module packlists 177b8851fccSafresh1 my $sub = sub { 178b8851fccSafresh1 # Only process module .packlists 179b8851fccSafresh1 return if $_ ne ".packlist" || $File::Find::dir eq $archlib; 180b8851fccSafresh1 181b8851fccSafresh1 # Hack of the leading bits of the paths & convert to a module name 182b8851fccSafresh1 my $module = $File::Find::name; 183b8851fccSafresh1 my $found = $module =~ s!^.*?/auto/(.*)/.packlist!$1!s 184b8851fccSafresh1 or do { 185b8851fccSafresh1 # warn "Woah! \$_=$_\n\$module=$module\n\$File::Find::dir=$File::Find::dir\n", 186b8851fccSafresh1 # join ("\n",@dirs); 187b8851fccSafresh1 return; 188b8851fccSafresh1 }; 189b8851fccSafresh1 190b8851fccSafresh1 my $modfile = "$module.pm"; 191b8851fccSafresh1 $module =~ s!/!::!g; 192b8851fccSafresh1 193b8851fccSafresh1 return if $self->{$module}; #shadowing? 194b8851fccSafresh1 $self->_make_entry($module,$File::Find::name,$modfile); 195b8851fccSafresh1 }; 196b8851fccSafresh1 while (@dirs) { 197b8851fccSafresh1 $root= shift @dirs; 198b8851fccSafresh1 next if !-d $root; 199b8851fccSafresh1 find($sub,$root); 200b8851fccSafresh1 } 201b8851fccSafresh1 202b8851fccSafresh1 return $self; 203b8851fccSafresh1} 204b8851fccSafresh1 205b8851fccSafresh1# VMS's non-case preserving file-system means the package name can't 206b8851fccSafresh1# be reconstructed from the filename. 207b8851fccSafresh1sub _module_name { 208b8851fccSafresh1 my($file, $orig_module) = @_; 209b8851fccSafresh1 210b8851fccSafresh1 my $module = ''; 211b8851fccSafresh1 if (open PACKFH, $file) { 212b8851fccSafresh1 while (<PACKFH>) { 213b8851fccSafresh1 if (/package\s+(\S+)\s*;/) { 214b8851fccSafresh1 my $pack = $1; 215b8851fccSafresh1 # Make a sanity check, that lower case $module 216b8851fccSafresh1 # is identical to lowercase $pack before 217b8851fccSafresh1 # accepting it 218b8851fccSafresh1 if (lc($pack) eq lc($orig_module)) { 219b8851fccSafresh1 $module = $pack; 220b8851fccSafresh1 last; 221b8851fccSafresh1 } 222b8851fccSafresh1 } 223b8851fccSafresh1 } 224b8851fccSafresh1 close PACKFH; 225b8851fccSafresh1 } 226b8851fccSafresh1 227b8851fccSafresh1 print STDERR "Couldn't figure out the package name for $file\n" 228b8851fccSafresh1 unless $module; 229b8851fccSafresh1 230b8851fccSafresh1 return $module; 231b8851fccSafresh1} 232b8851fccSafresh1 233b8851fccSafresh1sub modules { 234b8851fccSafresh1 my ($self) = @_; 235b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 236b8851fccSafresh1 237b8851fccSafresh1 # Bug/feature of sort in scalar context requires this. 238b8851fccSafresh1 return wantarray 239b8851fccSafresh1 ? sort grep { not /^:private:$/ } keys %$self 240b8851fccSafresh1 : grep { not /^:private:$/ } keys %$self; 241b8851fccSafresh1} 242b8851fccSafresh1 243b8851fccSafresh1sub files { 244b8851fccSafresh1 my ($self, $module, $type, @under) = @_; 245b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 246b8851fccSafresh1 247b8851fccSafresh1 # Validate arguments 248b8851fccSafresh1 Carp::croak("$module is not installed") if (! exists($self->{$module})); 249b8851fccSafresh1 $type = "all" if (! defined($type)); 250b8851fccSafresh1 Carp::croak('type must be "all", "prog" or "doc"') 251b8851fccSafresh1 if ($type ne "all" && $type ne "prog" && $type ne "doc"); 252b8851fccSafresh1 253b8851fccSafresh1 my (@files); 254b8851fccSafresh1 foreach my $file (keys(%{$self->{$module}{packlist}})) { 255b8851fccSafresh1 push(@files, $file) 256b8851fccSafresh1 if ($self->_is_type($file, $type) && 257b8851fccSafresh1 $self->_is_under($file, @under)); 258b8851fccSafresh1 } 259b8851fccSafresh1 return(@files); 260b8851fccSafresh1} 261b8851fccSafresh1 262b8851fccSafresh1sub directories { 263b8851fccSafresh1 my ($self, $module, $type, @under) = @_; 264b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 265b8851fccSafresh1 my (%dirs); 266b8851fccSafresh1 foreach my $file ($self->files($module, $type, @under)) { 267b8851fccSafresh1 $dirs{dirname($file)}++; 268b8851fccSafresh1 } 269b8851fccSafresh1 return sort keys %dirs; 270b8851fccSafresh1} 271b8851fccSafresh1 272b8851fccSafresh1sub directory_tree { 273b8851fccSafresh1 my ($self, $module, $type, @under) = @_; 274b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 275b8851fccSafresh1 my (%dirs); 276b8851fccSafresh1 foreach my $dir ($self->directories($module, $type, @under)) { 277b8851fccSafresh1 $dirs{$dir}++; 278b8851fccSafresh1 my ($last) = (""); 279b8851fccSafresh1 while ($last ne $dir) { 280b8851fccSafresh1 $last = $dir; 281b8851fccSafresh1 $dir = dirname($dir); 282b8851fccSafresh1 last if !$self->_is_under($dir, @under); 283b8851fccSafresh1 $dirs{$dir}++; 284b8851fccSafresh1 } 285b8851fccSafresh1 } 286b8851fccSafresh1 return(sort(keys(%dirs))); 287b8851fccSafresh1} 288b8851fccSafresh1 289b8851fccSafresh1sub validate { 290b8851fccSafresh1 my ($self, $module, $remove) = @_; 291b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 292b8851fccSafresh1 Carp::croak("$module is not installed") if (! exists($self->{$module})); 293b8851fccSafresh1 return($self->{$module}{packlist}->validate($remove)); 294b8851fccSafresh1} 295b8851fccSafresh1 296b8851fccSafresh1sub packlist { 297b8851fccSafresh1 my ($self, $module) = @_; 298b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 299b8851fccSafresh1 Carp::croak("$module is not installed") if (! exists($self->{$module})); 300b8851fccSafresh1 return($self->{$module}{packlist}); 301b8851fccSafresh1} 302b8851fccSafresh1 303b8851fccSafresh1sub version { 304b8851fccSafresh1 my ($self, $module) = @_; 305b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 306b8851fccSafresh1 Carp::croak("$module is not installed") if (! exists($self->{$module})); 307b8851fccSafresh1 return($self->{$module}{version}); 308b8851fccSafresh1} 309b8851fccSafresh1 310eac174f2Safresh1sub _debug_dump { 311b8851fccSafresh1 my ($self, $module) = @_; 312b8851fccSafresh1 $self= $self->new(default=>1) if !ref $self; 313b8851fccSafresh1 local $self->{":private:"}{Config}; 314b8851fccSafresh1 require Data::Dumper; 315b8851fccSafresh1 print Data::Dumper->new([$self])->Sortkeys(1)->Indent(1)->Dump(); 316b8851fccSafresh1} 317b8851fccSafresh1 318b8851fccSafresh1 319b8851fccSafresh11; 320b8851fccSafresh1 321b8851fccSafresh1__END__ 322b8851fccSafresh1 323b8851fccSafresh1=head1 NAME 324b8851fccSafresh1 325b8851fccSafresh1ExtUtils::Installed - Inventory management of installed modules 326b8851fccSafresh1 327b8851fccSafresh1=head1 SYNOPSIS 328b8851fccSafresh1 329b8851fccSafresh1 use ExtUtils::Installed; 330b8851fccSafresh1 my ($inst) = ExtUtils::Installed->new( skip_cwd => 1 ); 331b8851fccSafresh1 my (@modules) = $inst->modules(); 332b8851fccSafresh1 my (@missing) = $inst->validate("DBI"); 333b8851fccSafresh1 my $all_files = $inst->files("DBI"); 334b8851fccSafresh1 my $files_below_usr_local = $inst->files("DBI", "all", "/usr/local"); 335b8851fccSafresh1 my $all_dirs = $inst->directories("DBI"); 336b8851fccSafresh1 my $dirs_below_usr_local = $inst->directory_tree("DBI", "prog"); 337b8851fccSafresh1 my $packlist = $inst->packlist("DBI"); 338b8851fccSafresh1 339b8851fccSafresh1=head1 DESCRIPTION 340b8851fccSafresh1 341b8851fccSafresh1ExtUtils::Installed provides a standard way to find out what core and module 342b8851fccSafresh1files have been installed. It uses the information stored in .packlist files 343b8851fccSafresh1created during installation to provide this information. In addition it 344b8851fccSafresh1provides facilities to classify the installed files and to extract directory 345b8851fccSafresh1information from the .packlist files. 346b8851fccSafresh1 347b8851fccSafresh1=head1 USAGE 348b8851fccSafresh1 349b8851fccSafresh1The new() function searches for all the installed .packlists on the system, and 350b8851fccSafresh1stores their contents. The .packlists can be queried with the functions 351b8851fccSafresh1described below. Where it searches by default is determined by the settings found 352b8851fccSafresh1in C<%Config::Config>, and what the value is of the PERL5LIB environment variable. 353b8851fccSafresh1 354b8851fccSafresh1=head1 METHODS 355b8851fccSafresh1 356b8851fccSafresh1Unless specified otherwise all method can be called as class methods, or as object 357b8851fccSafresh1methods. If called as class methods then the "default" object will be used, and if 358b8851fccSafresh1necessary created using the current processes %Config and @INC. See the 359b8851fccSafresh1'default' option to new() for details. 360b8851fccSafresh1 361b8851fccSafresh1 362b8851fccSafresh1=over 4 363b8851fccSafresh1 364b8851fccSafresh1=item new() 365b8851fccSafresh1 366b8851fccSafresh1This takes optional named parameters. Without parameters, this 367b8851fccSafresh1searches for all the installed .packlists on the system using 368b8851fccSafresh1information from C<%Config::Config> and the default module search 369b8851fccSafresh1paths C<@INC>. The packlists are read using the 370b8851fccSafresh1L<ExtUtils::Packlist> module. 371b8851fccSafresh1 372b8851fccSafresh1If the named parameter C<skip_cwd> is true, the current directory C<.> will 373b8851fccSafresh1be stripped from C<@INC> before searching for .packlists. This keeps 374b8851fccSafresh1ExtUtils::Installed from finding modules installed in other perls that 375b8851fccSafresh1happen to be located below the current directory. 376b8851fccSafresh1 377b8851fccSafresh1If the named parameter C<config_override> is specified, 378b8851fccSafresh1it should be a reference to a hash which contains all information 379b8851fccSafresh1usually found in C<%Config::Config>. For example, you can obtain 380b8851fccSafresh1the configuration information for a separate perl installation and 381b8851fccSafresh1pass that in. 382b8851fccSafresh1 383b8851fccSafresh1 my $yoda_cfg = get_fake_config('yoda'); 384b8851fccSafresh1 my $yoda_inst = 385b8851fccSafresh1 ExtUtils::Installed->new(config_override=>$yoda_cfg); 386b8851fccSafresh1 387b8851fccSafresh1Similarly, the parameter C<inc_override> may be a reference to an 388b8851fccSafresh1array which is used in place of the default module search paths 389b8851fccSafresh1from C<@INC>. 390b8851fccSafresh1 391b8851fccSafresh1 use Config; 392b8851fccSafresh1 my @dirs = split(/\Q$Config{path_sep}\E/, $ENV{PERL5LIB}); 393b8851fccSafresh1 my $p5libs = ExtUtils::Installed->new(inc_override=>\@dirs); 394b8851fccSafresh1 395b8851fccSafresh1B<Note>: You probably do not want to use these options alone, almost always 396b8851fccSafresh1you will want to set both together. 397b8851fccSafresh1 398b8851fccSafresh1The parameter C<extra_libs> can be used to specify B<additional> paths to 399b8851fccSafresh1search for installed modules. For instance 400b8851fccSafresh1 401b8851fccSafresh1 my $installed = 402b8851fccSafresh1 ExtUtils::Installed->new(extra_libs=>["/my/lib/path"]); 403b8851fccSafresh1 404b8851fccSafresh1This should only be necessary if F</my/lib/path> is not in PERL5LIB. 405b8851fccSafresh1 406b8851fccSafresh1Finally there is the 'default', and the related 'default_get' and 'default_set' 407b8851fccSafresh1options. These options control the "default" object which is provided by the 408b8851fccSafresh1class interface to the methods. Setting C<default_get> to true tells the constructor 409b8851fccSafresh1to return the default object if it is defined. Setting C<default_set> to true tells 410b8851fccSafresh1the constructor to make the default object the constructed object. Setting the 411b8851fccSafresh1C<default> option is like setting both to true. This is used primarily internally 412b8851fccSafresh1and probably isn't interesting to any real user. 413b8851fccSafresh1 414b8851fccSafresh1=item modules() 415b8851fccSafresh1 416b8851fccSafresh1This returns a list of the names of all the installed modules. The perl 'core' 417b8851fccSafresh1is given the special name 'Perl'. 418b8851fccSafresh1 419b8851fccSafresh1=item files() 420b8851fccSafresh1 421b8851fccSafresh1This takes one mandatory parameter, the name of a module. It returns a list of 422b8851fccSafresh1all the filenames from the package. To obtain a list of core perl files, use 423b8851fccSafresh1the module name 'Perl'. Additional parameters are allowed. The first is one 424b8851fccSafresh1of the strings "prog", "doc" or "all", to select either just program files, 425b8851fccSafresh1just manual files or all files. The remaining parameters are a list of 426b8851fccSafresh1directories. The filenames returned will be restricted to those under the 427b8851fccSafresh1specified directories. 428b8851fccSafresh1 429b8851fccSafresh1=item directories() 430b8851fccSafresh1 431b8851fccSafresh1This takes one mandatory parameter, the name of a module. It returns a list of 432b8851fccSafresh1all the directories from the package. Additional parameters are allowed. The 433b8851fccSafresh1first is one of the strings "prog", "doc" or "all", to select either just 434b8851fccSafresh1program directories, just manual directories or all directories. The remaining 435b8851fccSafresh1parameters are a list of directories. The directories returned will be 436b8851fccSafresh1restricted to those under the specified directories. This method returns only 437b8851fccSafresh1the leaf directories that contain files from the specified module. 438b8851fccSafresh1 439b8851fccSafresh1=item directory_tree() 440b8851fccSafresh1 441b8851fccSafresh1This is identical in operation to directories(), except that it includes all the 442b8851fccSafresh1intermediate directories back up to the specified directories. 443b8851fccSafresh1 444b8851fccSafresh1=item validate() 445b8851fccSafresh1 446b8851fccSafresh1This takes one mandatory parameter, the name of a module. It checks that all 447b8851fccSafresh1the files listed in the modules .packlist actually exist, and returns a list of 448b8851fccSafresh1any missing files. If an optional second argument which evaluates to true is 449b8851fccSafresh1given any missing files will be removed from the .packlist 450b8851fccSafresh1 451b8851fccSafresh1=item packlist() 452b8851fccSafresh1 453b8851fccSafresh1This returns the ExtUtils::Packlist object for the specified module. 454b8851fccSafresh1 455b8851fccSafresh1=item version() 456b8851fccSafresh1 457b8851fccSafresh1This returns the version number for the specified module. 458b8851fccSafresh1 459b8851fccSafresh1=back 460b8851fccSafresh1 461b8851fccSafresh1=head1 EXAMPLE 462b8851fccSafresh1 463b8851fccSafresh1See the example in L<ExtUtils::Packlist>. 464b8851fccSafresh1 465b8851fccSafresh1=head1 AUTHOR 466b8851fccSafresh1 467b8851fccSafresh1Alan Burlison <Alan.Burlison@uk.sun.com> 468b8851fccSafresh1 469b8851fccSafresh1=cut 470