xref: /openbsd-src/gnu/usr.bin/perl/cpan/ExtUtils-Install/lib/ExtUtils/Packlist.pm (revision e068048151d29f2562a32185e21a8ba885482260)
1b8851fccSafresh1package ExtUtils::Packlist;
2b8851fccSafresh1use strict;
3eac174f2Safresh1
4b8851fccSafresh1use Carp qw();
5b8851fccSafresh1use Config;
6eac174f2Safresh1our $Relocations;
7*e0680481Safresh1our $VERSION = '2.22';
8b8851fccSafresh1$VERSION = eval $VERSION;
9b8851fccSafresh1
10b8851fccSafresh1# Used for generating filehandle globs.  IO::File might not be available!
11b8851fccSafresh1my $fhname = "FH1";
12b8851fccSafresh1
13b8851fccSafresh1=begin _undocumented
14b8851fccSafresh1
15b8851fccSafresh1=over
16b8851fccSafresh1
17b8851fccSafresh1=item mkfh()
18b8851fccSafresh1
19b8851fccSafresh1Make a filehandle. Same kind of idea as Symbol::gensym().
20b8851fccSafresh1
21b8851fccSafresh1=cut
22b8851fccSafresh1
23b8851fccSafresh1sub mkfh()
24b8851fccSafresh1{
25b8851fccSafresh1no strict;
26b8851fccSafresh1local $^W;
27b8851fccSafresh1my $fh = \*{$fhname++};
28b8851fccSafresh1use strict;
29b8851fccSafresh1return($fh);
30b8851fccSafresh1}
31b8851fccSafresh1
32b8851fccSafresh1=item __find_relocations
33b8851fccSafresh1
34b8851fccSafresh1Works out what absolute paths in the configuration have been located at run
35b8851fccSafresh1time relative to $^X, and generates a regexp that matches them
36b8851fccSafresh1
37b8851fccSafresh1=back
38b8851fccSafresh1
39b8851fccSafresh1=end _undocumented
40b8851fccSafresh1
41b8851fccSafresh1=cut
42b8851fccSafresh1
43b8851fccSafresh1sub __find_relocations
44b8851fccSafresh1{
45b8851fccSafresh1    my %paths;
46b8851fccSafresh1    while (my ($raw_key, $raw_val) = each %Config) {
47b8851fccSafresh1	my $exp_key = $raw_key . "exp";
48b8851fccSafresh1	next unless exists $Config{$exp_key};
49b8851fccSafresh1	next unless $raw_val =~ m!\.\.\./!;
50b8851fccSafresh1	$paths{$Config{$exp_key}}++;
51b8851fccSafresh1    }
52b8851fccSafresh1    # Longest prefixes go first in the alternatives
53b8851fccSafresh1    my $alternations = join "|", map {quotemeta $_}
54b8851fccSafresh1    sort {length $b <=> length $a} keys %paths;
55b8851fccSafresh1    qr/^($alternations)/o;
56b8851fccSafresh1}
57b8851fccSafresh1
58b8851fccSafresh1sub new($$)
59b8851fccSafresh1{
60b8851fccSafresh1my ($class, $packfile) = @_;
61b8851fccSafresh1$class = ref($class) || $class;
62b8851fccSafresh1my %self;
63b8851fccSafresh1tie(%self, $class, $packfile);
64b8851fccSafresh1return(bless(\%self, $class));
65b8851fccSafresh1}
66b8851fccSafresh1
67b8851fccSafresh1sub TIEHASH
68b8851fccSafresh1{
69b8851fccSafresh1my ($class, $packfile) = @_;
70b8851fccSafresh1my $self = { packfile => $packfile };
71b8851fccSafresh1bless($self, $class);
72b8851fccSafresh1$self->read($packfile) if (defined($packfile) && -f $packfile);
73b8851fccSafresh1return($self);
74b8851fccSafresh1}
75b8851fccSafresh1
76b8851fccSafresh1sub STORE
77b8851fccSafresh1{
78b8851fccSafresh1$_[0]->{data}->{$_[1]} = $_[2];
79b8851fccSafresh1}
80b8851fccSafresh1
81b8851fccSafresh1sub FETCH
82b8851fccSafresh1{
83b8851fccSafresh1return($_[0]->{data}->{$_[1]});
84b8851fccSafresh1}
85b8851fccSafresh1
86b8851fccSafresh1sub FIRSTKEY
87b8851fccSafresh1{
88b8851fccSafresh1my $reset = scalar(keys(%{$_[0]->{data}}));
89b8851fccSafresh1return(each(%{$_[0]->{data}}));
90b8851fccSafresh1}
91b8851fccSafresh1
92b8851fccSafresh1sub NEXTKEY
93b8851fccSafresh1{
94b8851fccSafresh1return(each(%{$_[0]->{data}}));
95b8851fccSafresh1}
96b8851fccSafresh1
97b8851fccSafresh1sub EXISTS
98b8851fccSafresh1{
99b8851fccSafresh1return(exists($_[0]->{data}->{$_[1]}));
100b8851fccSafresh1}
101b8851fccSafresh1
102b8851fccSafresh1sub DELETE
103b8851fccSafresh1{
104b8851fccSafresh1return(delete($_[0]->{data}->{$_[1]}));
105b8851fccSafresh1}
106b8851fccSafresh1
107b8851fccSafresh1sub CLEAR
108b8851fccSafresh1{
109b8851fccSafresh1%{$_[0]->{data}} = ();
110b8851fccSafresh1}
111b8851fccSafresh1
112b8851fccSafresh1sub DESTROY
113b8851fccSafresh1{
114b8851fccSafresh1}
115b8851fccSafresh1
116b8851fccSafresh1sub read($;$)
117b8851fccSafresh1{
118b8851fccSafresh1my ($self, $packfile) = @_;
119b8851fccSafresh1$self = tied(%$self) || $self;
120b8851fccSafresh1
121b8851fccSafresh1if (defined($packfile)) { $self->{packfile} = $packfile; }
122b8851fccSafresh1else { $packfile = $self->{packfile}; }
123b8851fccSafresh1Carp::croak("No packlist filename specified") if (! defined($packfile));
124b8851fccSafresh1my $fh = mkfh();
125b8851fccSafresh1open($fh, "<$packfile") || Carp::croak("Can't open file $packfile: $!");
126b8851fccSafresh1$self->{data} = {};
127b8851fccSafresh1my ($line);
128b8851fccSafresh1while (defined($line = <$fh>))
129b8851fccSafresh1   {
130b8851fccSafresh1   chomp $line;
131b8851fccSafresh1   my ($key, $data) = $line;
132b8851fccSafresh1   if ($key =~ /^(.*?)( \w+=.*)$/)
133b8851fccSafresh1      {
134b8851fccSafresh1      $key = $1;
135b8851fccSafresh1      $data = { map { split('=', $_) } split(' ', $2)};
136b8851fccSafresh1
137b8851fccSafresh1      if ($Config{userelocatableinc} && $data->{relocate_as})
138b8851fccSafresh1      {
139b8851fccSafresh1	  require File::Spec;
140b8851fccSafresh1	  require Cwd;
141b8851fccSafresh1	  my ($vol, $dir) = File::Spec->splitpath($packfile);
142b8851fccSafresh1	  my $newpath = File::Spec->catpath($vol, $dir, $data->{relocate_as});
143b8851fccSafresh1	  $key = Cwd::realpath($newpath);
144b8851fccSafresh1      }
145b8851fccSafresh1         }
146b8851fccSafresh1   $key =~ s!/\./!/!g;   # Some .packlists have spurious '/./' bits in the paths
147b8851fccSafresh1      $self->{data}->{$key} = $data;
148b8851fccSafresh1      }
149b8851fccSafresh1close($fh);
150b8851fccSafresh1}
151b8851fccSafresh1
152b8851fccSafresh1sub write($;$)
153b8851fccSafresh1{
154b8851fccSafresh1my ($self, $packfile) = @_;
155b8851fccSafresh1$self = tied(%$self) || $self;
156b8851fccSafresh1if (defined($packfile)) { $self->{packfile} = $packfile; }
157b8851fccSafresh1else { $packfile = $self->{packfile}; }
158b8851fccSafresh1Carp::croak("No packlist filename specified") if (! defined($packfile));
159b8851fccSafresh1my $fh = mkfh();
160b8851fccSafresh1open($fh, ">$packfile") || Carp::croak("Can't open file $packfile: $!");
161b8851fccSafresh1foreach my $key (sort(keys(%{$self->{data}})))
162b8851fccSafresh1   {
163b8851fccSafresh1       my $data = $self->{data}->{$key};
164b8851fccSafresh1       if ($Config{userelocatableinc}) {
165b8851fccSafresh1	   $Relocations ||= __find_relocations();
166b8851fccSafresh1	   if ($packfile =~ $Relocations) {
167b8851fccSafresh1	       # We are writing into a subdirectory of a run-time relocated
168b8851fccSafresh1	       # path. Figure out if the this file is also within a subdir.
169b8851fccSafresh1	       my $prefix = $1;
170b8851fccSafresh1	       if (File::Spec->no_upwards(File::Spec->abs2rel($key, $prefix)))
171b8851fccSafresh1	       {
172b8851fccSafresh1		   # The relocated path is within the found prefix
173b8851fccSafresh1		   my $packfile_prefix;
174b8851fccSafresh1		   (undef, $packfile_prefix)
175b8851fccSafresh1		       = File::Spec->splitpath($packfile);
176b8851fccSafresh1
177b8851fccSafresh1		   my $relocate_as
178b8851fccSafresh1		       = File::Spec->abs2rel($key, $packfile_prefix);
179b8851fccSafresh1
180b8851fccSafresh1		   if (!ref $data) {
181b8851fccSafresh1		       $data = {};
182b8851fccSafresh1		   }
183b8851fccSafresh1		   $data->{relocate_as} = $relocate_as;
184b8851fccSafresh1	       }
185b8851fccSafresh1	   }
186b8851fccSafresh1       }
187b8851fccSafresh1   print $fh ("$key");
188b8851fccSafresh1   if (ref($data))
189b8851fccSafresh1      {
190b8851fccSafresh1      foreach my $k (sort(keys(%$data)))
191b8851fccSafresh1         {
192b8851fccSafresh1         print $fh (" $k=$data->{$k}");
193b8851fccSafresh1         }
194b8851fccSafresh1      }
195b8851fccSafresh1   print $fh ("\n");
196b8851fccSafresh1   }
197b8851fccSafresh1close($fh);
198b8851fccSafresh1}
199b8851fccSafresh1
200b8851fccSafresh1sub validate($;$)
201b8851fccSafresh1{
202b8851fccSafresh1my ($self, $remove) = @_;
203b8851fccSafresh1$self = tied(%$self) || $self;
204b8851fccSafresh1my @missing;
205b8851fccSafresh1foreach my $key (sort(keys(%{$self->{data}})))
206b8851fccSafresh1   {
207b8851fccSafresh1   if (! -e $key)
208b8851fccSafresh1      {
209b8851fccSafresh1      push(@missing, $key);
210b8851fccSafresh1      delete($self->{data}{$key}) if ($remove);
211b8851fccSafresh1      }
212b8851fccSafresh1   }
213b8851fccSafresh1return(@missing);
214b8851fccSafresh1}
215b8851fccSafresh1
216b8851fccSafresh1sub packlist_file($)
217b8851fccSafresh1{
218b8851fccSafresh1my ($self) = @_;
219b8851fccSafresh1$self = tied(%$self) || $self;
220b8851fccSafresh1return($self->{packfile});
221b8851fccSafresh1}
222b8851fccSafresh1
223b8851fccSafresh11;
224b8851fccSafresh1
225b8851fccSafresh1__END__
226b8851fccSafresh1
227b8851fccSafresh1=head1 NAME
228b8851fccSafresh1
229b8851fccSafresh1ExtUtils::Packlist - manage .packlist files
230b8851fccSafresh1
231b8851fccSafresh1=head1 SYNOPSIS
232b8851fccSafresh1
233b8851fccSafresh1   use ExtUtils::Packlist;
234b8851fccSafresh1   my ($pl) = ExtUtils::Packlist->new('.packlist');
235b8851fccSafresh1   $pl->read('/an/old/.packlist');
236b8851fccSafresh1   my @missing_files = $pl->validate();
237b8851fccSafresh1   $pl->write('/a/new/.packlist');
238b8851fccSafresh1
239b8851fccSafresh1   $pl->{'/some/file/name'}++;
240b8851fccSafresh1      or
241b8851fccSafresh1   $pl->{'/some/other/file/name'} = { type => 'file',
242b8851fccSafresh1                                      from => '/some/file' };
243b8851fccSafresh1
244b8851fccSafresh1=head1 DESCRIPTION
245b8851fccSafresh1
246b8851fccSafresh1ExtUtils::Packlist provides a standard way to manage .packlist files.
247b8851fccSafresh1Functions are provided to read and write .packlist files.  The original
248b8851fccSafresh1.packlist format is a simple list of absolute pathnames, one per line.  In
249b8851fccSafresh1addition, this package supports an extended format, where as well as a filename
250b8851fccSafresh1each line may contain a list of attributes in the form of a space separated
251b8851fccSafresh1list of key=value pairs.  This is used by the installperl script to
252b8851fccSafresh1differentiate between files and links, for example.
253b8851fccSafresh1
254b8851fccSafresh1=head1 USAGE
255b8851fccSafresh1
256b8851fccSafresh1The hash reference returned by the new() function can be used to examine and
257b8851fccSafresh1modify the contents of the .packlist.  Items may be added/deleted from the
258b8851fccSafresh1.packlist by modifying the hash.  If the value associated with a hash key is a
259b8851fccSafresh1scalar, the entry written to the .packlist by any subsequent write() will be a
260b8851fccSafresh1simple filename.  If the value is a hash, the entry written will be the
261b8851fccSafresh1filename followed by the key=value pairs from the hash.  Reading back the
262b8851fccSafresh1.packlist will recreate the original entries.
263b8851fccSafresh1
264b8851fccSafresh1=head1 FUNCTIONS
265b8851fccSafresh1
266b8851fccSafresh1=over 4
267b8851fccSafresh1
268b8851fccSafresh1=item new()
269b8851fccSafresh1
270b8851fccSafresh1This takes an optional parameter, the name of a .packlist.  If the file exists,
271b8851fccSafresh1it will be opened and the contents of the file will be read.  The new() method
272b8851fccSafresh1returns a reference to a hash.  This hash holds an entry for each line in the
273b8851fccSafresh1.packlist.  In the case of old-style .packlists, the value associated with each
274b8851fccSafresh1key is undef.  In the case of new-style .packlists, the value associated with
275b8851fccSafresh1each key is a hash containing the key=value pairs following the filename in the
276b8851fccSafresh1.packlist.
277b8851fccSafresh1
278b8851fccSafresh1=item read()
279b8851fccSafresh1
280b8851fccSafresh1This takes an optional parameter, the name of the .packlist to be read.  If
281b8851fccSafresh1no file is specified, the .packlist specified to new() will be read.  If the
282b8851fccSafresh1.packlist does not exist, Carp::croak will be called.
283b8851fccSafresh1
284b8851fccSafresh1=item write()
285b8851fccSafresh1
286b8851fccSafresh1This takes an optional parameter, the name of the .packlist to be written.  If
287b8851fccSafresh1no file is specified, the .packlist specified to new() will be overwritten.
288b8851fccSafresh1
289b8851fccSafresh1=item validate()
290b8851fccSafresh1
291b8851fccSafresh1This checks that every file listed in the .packlist actually exists.  If an
292b8851fccSafresh1argument which evaluates to true is given, any missing files will be removed
293b8851fccSafresh1from the internal hash.  The return value is a list of the missing files, which
294b8851fccSafresh1will be empty if they all exist.
295b8851fccSafresh1
296b8851fccSafresh1=item packlist_file()
297b8851fccSafresh1
298b8851fccSafresh1This returns the name of the associated .packlist file
299b8851fccSafresh1
300b8851fccSafresh1=back
301b8851fccSafresh1
302b8851fccSafresh1=head1 EXAMPLE
303b8851fccSafresh1
304b8851fccSafresh1Here's C<modrm>, a little utility to cleanly remove an installed module.
305b8851fccSafresh1
306b8851fccSafresh1    #!/usr/local/bin/perl -w
307b8851fccSafresh1
308b8851fccSafresh1    use strict;
309b8851fccSafresh1    use IO::Dir;
310b8851fccSafresh1    use ExtUtils::Packlist;
311b8851fccSafresh1    use ExtUtils::Installed;
312b8851fccSafresh1
313b8851fccSafresh1    sub emptydir($) {
314b8851fccSafresh1	my ($dir) = @_;
315b8851fccSafresh1	my $dh = IO::Dir->new($dir) || return(0);
316b8851fccSafresh1	my @count = $dh->read();
317b8851fccSafresh1	$dh->close();
318b8851fccSafresh1	return(@count == 2 ? 1 : 0);
319b8851fccSafresh1    }
320b8851fccSafresh1
321b8851fccSafresh1    # Find all the installed packages
322b8851fccSafresh1    print("Finding all installed modules...\n");
323b8851fccSafresh1    my $installed = ExtUtils::Installed->new();
324b8851fccSafresh1
325b8851fccSafresh1    foreach my $module (grep(!/^Perl$/, $installed->modules())) {
326b8851fccSafresh1       my $version = $installed->version($module) || "???";
327b8851fccSafresh1       print("Found module $module Version $version\n");
328b8851fccSafresh1       print("Do you want to delete $module? [n] ");
329b8851fccSafresh1       my $r = <STDIN>; chomp($r);
330b8851fccSafresh1       if ($r && $r =~ /^y/i) {
331b8851fccSafresh1	  # Remove all the files
332b8851fccSafresh1	  foreach my $file (sort($installed->files($module))) {
333b8851fccSafresh1	     print("rm $file\n");
334b8851fccSafresh1	     unlink($file);
335b8851fccSafresh1	  }
336b8851fccSafresh1	  my $pf = $installed->packlist($module)->packlist_file();
337b8851fccSafresh1	  print("rm $pf\n");
338b8851fccSafresh1	  unlink($pf);
339b8851fccSafresh1	  foreach my $dir (sort($installed->directory_tree($module))) {
340b8851fccSafresh1	     if (emptydir($dir)) {
341b8851fccSafresh1		print("rmdir $dir\n");
342b8851fccSafresh1		rmdir($dir);
343b8851fccSafresh1	     }
344b8851fccSafresh1	  }
345b8851fccSafresh1       }
346b8851fccSafresh1    }
347b8851fccSafresh1
348b8851fccSafresh1=head1 AUTHOR
349b8851fccSafresh1
350b8851fccSafresh1Alan Burlison <Alan.Burlison@uk.sun.com>
351b8851fccSafresh1
352b8851fccSafresh1=cut
353