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