This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Be sure to find the vmsish pragma for one-liners in exit.t.
[perl5.git] / lib / CPAN / CacheMgr.pm
CommitLineData
f9916dde
A
1# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
2# vim: ts=4 sts=4 sw=4:
3package CPAN::CacheMgr;
4use strict;
5use CPAN::InfoObj;
6@CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
7use Cwd qw(chdir);
8use File::Find;
9
10use vars qw(
11 $VERSION
12);
13$VERSION = "5.5";
14
15package CPAN::CacheMgr;
16use strict;
17
18#-> sub CPAN::CacheMgr::as_string ;
19sub as_string {
20 eval { require Data::Dumper };
21 if ($@) {
22 return shift->SUPER::as_string;
23 } else {
24 return Data::Dumper::Dumper(shift);
25 }
26}
27
28#-> sub CPAN::CacheMgr::cachesize ;
29sub cachesize {
30 shift->{DU};
31}
32
33#-> sub CPAN::CacheMgr::tidyup ;
34sub tidyup {
35 my($self) = @_;
36 return unless $CPAN::META->{LOCK};
37 return unless -d $self->{ID};
38 my @toremove = grep { $self->{SIZE}{$_}==0 } @{$self->{FIFO}};
39 for my $current (0..$#toremove) {
40 my $toremove = $toremove[$current];
41 $CPAN::Frontend->myprint(sprintf(
42 "DEL(%d/%d): %s \n",
43 $current+1,
44 scalar @toremove,
45 $toremove,
46 )
47 );
48 return if $CPAN::Signal;
49 $self->_clean_cache($toremove);
50 return if $CPAN::Signal;
51 }
52}
53
54#-> sub CPAN::CacheMgr::dir ;
55sub dir {
56 shift->{ID};
57}
58
59#-> sub CPAN::CacheMgr::entries ;
60sub entries {
61 my($self,$dir) = @_;
62 return unless defined $dir;
63 $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
64 $dir ||= $self->{ID};
65 my($cwd) = CPAN::anycwd();
66 chdir $dir or Carp::croak("Can't chdir to $dir: $!");
67 my $dh = DirHandle->new(File::Spec->curdir)
68 or Carp::croak("Couldn't opendir $dir: $!");
69 my(@entries);
70 for ($dh->read) {
71 next if $_ eq "." || $_ eq "..";
72 if (-f $_) {
73 push @entries, File::Spec->catfile($dir,$_);
74 } elsif (-d _) {
75 push @entries, File::Spec->catdir($dir,$_);
76 } else {
77 $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
78 }
79 }
80 chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
81 sort { -M $a <=> -M $b} @entries;
82}
83
84#-> sub CPAN::CacheMgr::disk_usage ;
85sub disk_usage {
86 my($self,$dir,$fast) = @_;
87 return if exists $self->{SIZE}{$dir};
88 return if $CPAN::Signal;
89 my($Du) = 0;
90 if (-e $dir) {
91 if (-d $dir) {
92 unless (-x $dir) {
93 unless (chmod 0755, $dir) {
94 $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
95 "permission to change the permission; cannot ".
96 "estimate disk usage of '$dir'\n");
97 $CPAN::Frontend->mysleep(5);
98 return;
99 }
100 }
101 } elsif (-f $dir) {
102 # nothing to say, no matter what the permissions
103 }
104 } else {
105 $CPAN::Frontend->mywarn("File or directory '$dir' has gone, ignoring\n");
106 return;
107 }
108 if ($fast) {
109 $Du = 0; # placeholder
110 } else {
111 find(
112 sub {
113 $File::Find::prune++ if $CPAN::Signal;
114 return if -l $_;
115 if ($^O eq 'MacOS') {
116 require Mac::Files;
117 my $cat = Mac::Files::FSpGetCatInfo($_);
118 $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
119 } else {
120 if (-d _) {
121 unless (-x _) {
122 unless (chmod 0755, $_) {
123 $CPAN::Frontend->mywarn("I have neither the -x permission nor ".
124 "the permission to change the permission; ".
125 "can only partially estimate disk usage ".
126 "of '$_'\n");
127 $CPAN::Frontend->mysleep(5);
128 return;
129 }
130 }
131 } else {
132 $Du += (-s _);
133 }
134 }
135 },
136 $dir
137 );
138 }
139 return if $CPAN::Signal;
140 $self->{SIZE}{$dir} = $Du/1024/1024;
141 unshift @{$self->{FIFO}}, $dir;
142 $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
143 $self->{DU} += $Du/1024/1024;
144 $self->{DU};
145}
146
147#-> sub CPAN::CacheMgr::_clean_cache ;
148sub _clean_cache {
149 my($self,$dir) = @_;
150 return unless -e $dir;
151 unless (File::Spec->canonpath(File::Basename::dirname($dir))
152 eq File::Spec->canonpath($CPAN::Config->{build_dir})) {
153 $CPAN::Frontend->mywarn("Directory '$dir' not below $CPAN::Config->{build_dir}, ".
154 "will not remove\n");
155 $CPAN::Frontend->mysleep(5);
156 return;
157 }
158 $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
159 if $CPAN::DEBUG;
160 File::Path::rmtree($dir);
161 my $id_deleted = 0;
162 if ($dir !~ /\.yml$/ && -f "$dir.yml") {
163 my $yaml_module = CPAN::_yaml_module();
164 if ($CPAN::META->has_inst($yaml_module)) {
165 my($peek_yaml) = eval { CPAN->_yaml_loadfile("$dir.yml"); };
166 if ($@) {
167 $CPAN::Frontend->mywarn("(parse error on '$dir.yml' removing anyway)");
168 unlink "$dir.yml" or
169 $CPAN::Frontend->mywarn("(Could not unlink '$dir.yml': $!)");
170 return;
171 } elsif (my $id = $peek_yaml->[0]{distribution}{ID}) {
172 $CPAN::META->delete("CPAN::Distribution", $id);
173
174 # XXX we should restore the state NOW, otherise this
175 # distro does not exist until we read an index. BUG ALERT(?)
176
177 # $CPAN::Frontend->mywarn (" +++\n");
178 $id_deleted++;
179 }
180 }
181 unlink "$dir.yml"; # may fail
182 unless ($id_deleted) {
183 CPAN->debug("no distro found associated with '$dir'");
184 }
185 }
186 $self->{DU} -= $self->{SIZE}{$dir};
187 delete $self->{SIZE}{$dir};
188}
189
190#-> sub CPAN::CacheMgr::new ;
191sub new {
192 my $class = shift;
193 my $time = time;
194 my($debug,$t2);
195 $debug = "";
196 my $self = {
197 ID => $CPAN::Config->{build_dir},
198 MAX => $CPAN::Config->{'build_cache'},
199 SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
200 DU => 0
201 };
202 File::Path::mkpath($self->{ID});
203 my $dh = DirHandle->new($self->{ID});
204 bless $self, $class;
205 $self->scan_cache;
206 $t2 = time;
207 $debug .= "timing of CacheMgr->new: ".($t2 - $time);
208 $time = $t2;
209 CPAN->debug($debug) if $CPAN::DEBUG;
210 $self;
211}
212
213#-> sub CPAN::CacheMgr::scan_cache ;
214sub scan_cache {
215 my $self = shift;
216 return if $self->{SCAN} eq 'never';
217 $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
218 unless $self->{SCAN} eq 'atstart';
219 return unless $CPAN::META->{LOCK};
220 $CPAN::Frontend->myprint(
221 sprintf("Scanning cache %s for sizes\n",
222 $self->{ID}));
223 my $e;
224 my @entries = $self->entries($self->{ID});
225 my $i = 0;
226 my $painted = 0;
227 for $e (@entries) {
228 my $symbol = ".";
229 if ($self->{DU} > $self->{MAX}) {
230 $symbol = "-";
231 $self->disk_usage($e,1);
232 } else {
233 $self->disk_usage($e);
234 }
235 $i++;
236 while (($painted/76) < ($i/@entries)) {
237 $CPAN::Frontend->myprint($symbol);
238 $painted++;
239 }
240 return if $CPAN::Signal;
241 }
242 $CPAN::Frontend->myprint("DONE\n");
243 $self->tidyup;
244}
245
2461;