More regression tests for caller() and fix one bug of #16658.
[p5sagit/p5-mst-13.2.git] / lib / ExtUtils / Packlist.pm
CommitLineData
93cd2f30 1package ExtUtils::Packlist;
17f410f9 2
f6d6199c 3use 5.006;
93cd2f30 4use strict;
5use Carp qw();
d6a466d7 6our $VERSION = '0.04';
93cd2f30 7
8# Used for generating filehandle globs. IO::File might not be available!
9my $fhname = "FH1";
10
11sub mkfh()
12{
13no strict;
14my $fh = \*{$fhname++};
15use strict;
16return($fh);
17}
18
19sub new($$)
20{
21my ($class, $packfile) = @_;
22$class = ref($class) || $class;
23my %self;
24tie(%self, $class, $packfile);
25return(bless(\%self, $class));
26}
27
28sub TIEHASH
29{
30my ($class, $packfile) = @_;
31my $self = { packfile => $packfile };
32bless($self, $class);
33$self->read($packfile) if (defined($packfile) && -f $packfile);
34return($self);
35}
36
37sub STORE
38{
39$_[0]->{data}->{$_[1]} = $_[2];
40}
41
42sub FETCH
43{
44return($_[0]->{data}->{$_[1]});
45}
46
47sub FIRSTKEY
48{
49my $reset = scalar(keys(%{$_[0]->{data}}));
50return(each(%{$_[0]->{data}}));
51}
52
53sub NEXTKEY
54{
55return(each(%{$_[0]->{data}}));
56}
57
58sub EXISTS
59{
60return(exists($_[0]->{data}->{$_[1]}));
61}
62
63sub DELETE
64{
65return(delete($_[0]->{data}->{$_[1]}));
66}
67
68sub CLEAR
69{
70%{$_[0]->{data}} = ();
71}
72
73sub DESTROY
74{
75}
76
77sub read($;$)
78{
79my ($self, $packfile) = @_;
80$self = tied(%$self) || $self;
81
82if (defined($packfile)) { $self->{packfile} = $packfile; }
83else { $packfile = $self->{packfile}; }
84Carp::croak("No packlist filename specified") if (! defined($packfile));
85my $fh = mkfh();
86open($fh, "<$packfile") || Carp::croak("Can't open file $packfile: $!");
87$self->{data} = {};
88my ($line);
89while (defined($line = <$fh>))
90 {
91 chomp $line;
411cc70a 92 my ($key, @kvs) = $line;
93 if ($key =~ /^(.*?)( \w+=.*)$/)
94 {
95 $key = $1;
96 @kvs = split(' ', $2);
97 }
9b604809 98 $key =~ s!/\./!/!g; # Some .packlists have spurious '/./' bits in the paths
93cd2f30 99 if (! @kvs)
100 {
101 $self->{data}->{$key} = undef;
102 }
103 else
104 {
105 my ($data) = {};
106 foreach my $kv (@kvs)
107 {
108 my ($k, $v) = split('=', $kv);
109 $data->{$k} = $v;
110 }
111 $self->{data}->{$key} = $data;
112 }
113 }
114close($fh);
115}
116
117sub write($;$)
118{
119my ($self, $packfile) = @_;
120$self = tied(%$self) || $self;
121if (defined($packfile)) { $self->{packfile} = $packfile; }
122else { $packfile = $self->{packfile}; }
123Carp::croak("No packlist filename specified") if (! defined($packfile));
124my $fh = mkfh();
125open($fh, ">$packfile") || Carp::croak("Can't open file $packfile: $!");
126foreach my $key (sort(keys(%{$self->{data}})))
127 {
128 print $fh ("$key");
129 if (ref($self->{data}->{$key}))
130 {
131 my $data = $self->{data}->{$key};
132 foreach my $k (sort(keys(%$data)))
133 {
134 print $fh (" $k=$data->{$k}");
135 }
136 }
137 print $fh ("\n");
138 }
139close($fh);
140}
141
142sub validate($;$)
143{
144my ($self, $remove) = @_;
145$self = tied(%$self) || $self;
146my @missing;
147foreach my $key (sort(keys(%{$self->{data}})))
148 {
149 if (! -e $key)
150 {
151 push(@missing, $key);
152 delete($self->{data}{$key}) if ($remove);
153 }
154 }
155return(@missing);
156}
157
9b604809 158sub packlist_file($)
159{
160my ($self) = @_;
161$self = tied(%$self) || $self;
162return($self->{packfile});
163}
164
93cd2f30 1651;
166
167__END__
168
169=head1 NAME
170
171ExtUtils::Packlist - manage .packlist files
172
173=head1 SYNOPSIS
174
175 use ExtUtils::Packlist;
176 my ($pl) = ExtUtils::Packlist->new('.packlist');
177 $pl->read('/an/old/.packlist');
178 my @missing_files = $pl->validate();
179 $pl->write('/a/new/.packlist');
180
181 $pl->{'/some/file/name'}++;
182 or
183 $pl->{'/some/other/file/name'} = { type => 'file',
184 from => '/some/file' };
185
186=head1 DESCRIPTION
187
188ExtUtils::Packlist provides a standard way to manage .packlist files.
189Functions are provided to read and write .packlist files. The original
190.packlist format is a simple list of absolute pathnames, one per line. In
191addition, this package supports an extended format, where as well as a filename
192each line may contain a list of attributes in the form of a space separated
193list of key=value pairs. This is used by the installperl script to
194differentiate between files and links, for example.
195
196=head1 USAGE
197
198The hash reference returned by the new() function can be used to examine and
199modify the contents of the .packlist. Items may be added/deleted from the
200.packlist by modifying the hash. If the value associated with a hash key is a
201scalar, the entry written to the .packlist by any subsequent write() will be a
202simple filename. If the value is a hash, the entry written will be the
203filename followed by the key=value pairs from the hash. Reading back the
204.packlist will recreate the original entries.
205
206=head1 FUNCTIONS
207
bbc7dcd2 208=over 4
93cd2f30 209
210=item new()
211
212This takes an optional parameter, the name of a .packlist. If the file exists,
213it will be opened and the contents of the file will be read. The new() method
214returns a reference to a hash. This hash holds an entry for each line in the
215.packlist. In the case of old-style .packlists, the value associated with each
216key is undef. In the case of new-style .packlists, the value associated with
217each key is a hash containing the key=value pairs following the filename in the
218.packlist.
219
220=item read()
221
222This takes an optional parameter, the name of the .packlist to be read. If
223no file is specified, the .packlist specified to new() will be read. If the
224.packlist does not exist, Carp::croak will be called.
225
226=item write()
227
228This takes an optional parameter, the name of the .packlist to be written. If
229no file is specified, the .packlist specified to new() will be overwritten.
230
231=item validate()
232
233This checks that every file listed in the .packlist actually exists. If an
234argument which evaluates to true is given, any missing files will be removed
235from the internal hash. The return value is a list of the missing files, which
236will be empty if they all exist.
237
9b604809 238=item packlist_file()
239
240This returns the name of the associated .packlist file
241
93cd2f30 242=back
243
ddf41153 244=head1 EXAMPLE
245
246Here's C<modrm>, a little utility to cleanly remove an installed module.
247
248 #!/usr/local/bin/perl -w
249
250 use strict;
251 use IO::Dir;
252 use ExtUtils::Packlist;
253 use ExtUtils::Installed;
254
255 sub emptydir($) {
256 my ($dir) = @_;
257 my $dh = IO::Dir->new($dir) || return(0);
258 my @count = $dh->read();
259 $dh->close();
260 return(@count == 2 ? 1 : 0);
261 }
262
263 # Find all the installed packages
264 print("Finding all installed modules...\n");
265 my $installed = ExtUtils::Installed->new();
266
267 foreach my $module (grep(!/^Perl$/, $installed->modules())) {
268 my $version = $installed->version($module) || "???";
269 print("Found module $module Version $version\n");
270 print("Do you want to delete $module? [n] ");
271 my $r = <STDIN>; chomp($r);
272 if ($r && $r =~ /^y/i) {
273 # Remove all the files
274 foreach my $file (sort($installed->files($module))) {
275 print("rm $file\n");
276 unlink($file);
277 }
278 my $pf = $installed->packlist($module)->packlist_file();
279 print("rm $pf\n");
280 unlink($pf);
281 foreach my $dir (sort($installed->directory_tree($module))) {
282 if (emptydir($dir)) {
283 print("rmdir $dir\n");
284 rmdir($dir);
285 }
286 }
287 }
288 }
289
93cd2f30 290=head1 AUTHOR
291
292Alan Burlison <Alan.Burlison@uk.sun.com>
293
294=cut