10
use File::Path (); # for now
12
use File::Fu::Dir::Temp;
13
use File::Fu::File::Temp;
17
File::Fu::Dir - a directoryname object
23
my $dir = File::Fu->dir("path/to/dir");
24
$dir->e and warn "$dir exists";
26
$dir->l and warn "$dir is a link to ", $dir->readlink;
28
foreach my $entry ($dir->list) {
29
warn $entry . ': ' . $entry->stat->size, "\n"
35
use base 'File::Fu::Base';
46
my $dir = File::Fu::Dir->new($path);
48
my $dir = File::Fu::Dir->new(@path);
54
my $class = ref($package) || $package;
55
my $self = {$class->_init(@_)};
58
} # end subroutine new definition
59
########################################################################
61
=head1 Class Constants/Methods
65
Return the corresponding file class for this dir object.
67
my $fc = $class->file_class;
71
Always true for a directory.
75
Always false for a directory.
79
use constant top_class => 'File::Fu';
80
use constant file_class => 'File::Fu::File';
81
use constant token_class => 'File::Fu::Dir::Token';
82
use constant is_dir => 1;
83
use constant is_file => 0;
85
########################################################################
89
my $class = File::Fu::Dir->temp_dir_class;
95
my $class = ref($package) . '::Temp';
96
$class = __PACKAGE__ . '::Temp' unless($class->can('new'));
98
} # end subroutine temp_dir_class definition
99
########################################################################
101
=head2 temp_file_class
103
my $class = File::Fu::Dir->temp_file_class;
107
sub temp_file_class {
109
my $class = $package->file_class . '::Temp';
110
$class = __PACKAGE__->file_class.'::Temp' unless($class->can('new'));
112
} # end subroutine temp_file_class definition
113
########################################################################
115
=for internal head2 _init
116
my %fields = $class->_init(@_);
122
@_ or return(dirs => ['.']);
124
$_ eq '' ? ('') : split(/\/+/, $_)
126
@$dirs or $dirs = ['']; # XXX
127
return(dirs => $dirs);
128
} # end subroutine _init definition
129
########################################################################
135
my $string = $dir->stringify;
141
#Carp::carp("stringify", overload::StrVal($self));
142
#defined($self->{dirs}) or croak("how did this happen?");
143
my @dirs = @{$self->{dirs}};
144
#warn "I'm (", join(',', @{$self->{dirs}}), ")";
145
@dirs or return('/');
147
join('/', @dirs, ''); # always a trailing slash
148
} # end subroutine stringify definition
149
########################################################################
151
=begin shutup_pod_cover
155
=end shutup_pod_cover
159
*l = sub {-l shift->bare};
163
Stringify without the trailing slash/assertion.
165
my $str = $self->bare;
167
The trailing slash causes trouble when trying to address a symlink to a
168
directory via a dir object. Thus, C<-l $dir> doesn't work, but
175
my @dirs = @{$self->{dirs}};
176
@dirs or return('/');
178
join('/', @dirs); # always a trailing slash
179
} # end subroutine bare definition
180
########################################################################
184
Create a filename object with $dir as its parent.
186
my $file = $dir->file($filename);
188
my $file = $dir + $filename;
194
my ($name, $rev) = @_;
195
$rev and croak("bah");
197
# filename might have dir parts
199
my $bit = $self->file_class->new($name);
200
return $self->file_class->new_direct(
201
dir => $self->subdir($bit->dirname),
202
file => $bit->basename
206
return($self->file_class->new_direct(dir => $self, file => $name));
207
} # end subroutine file definition
208
########################################################################
212
Append a string only to the last directory part.
214
$dir->append('.tmp');
222
my ($bit, $rev) = @_;
224
$rev and return($bit . "$self"); # stringify is out-of-order
225
#carp("appending $bit");
226
#$self = $self->clone;
227
$self->{dirs}[-1] .= $bit;
229
} # end subroutine append definition
230
########################################################################
234
$newdir = $dir->subdir('foo');
242
my ($name, $rev) = @_;
243
$rev and croak("bah");
245
# appending to cwd means starting over
246
return($self->new($name)) if($self->is_cwd);
248
my %newbits = $self->_init($name);
249
$self = $self->clone;
250
push(@{$self->{dirs}}, @{$newbits{dirs}});
252
} # end subroutine subdir definition
253
########################################################################
257
Returns the $i'th part of the directory list.
259
my $part = $dir->part($i);
261
$dir->part(-1) is like $dir->basename, but not an object and not quite
262
like File::Basename::basename() when it comes to the / directory.
269
return($self->{dirs}[$i]);
270
} # end subroutine part definition
271
########################################################################
275
Shorthand for part(-1);
279
sub end {shift->part(-1)};
283
Retrieve the inner list of the directory's parts.
285
my @parts = $dir->parts;
287
my @parts = $dir->parts(0..2);
289
The returned parts will be contiguous, but the request can be a
290
two-element list (and can also end at -1.)
292
my @parts = $dir->parts(3, 7);
294
my @parts = $dir->parts(3, -1);
301
@want or return(@{$self->{dirs}});
304
$want[1] = $#{$self->{dirs}};
306
@want = $want[0]..$want[1];
308
# TODO else check contiguity?
309
return(@{$self->{dirs}}[@want]);
310
} # end subroutine parts definition
311
########################################################################
315
Returns a new dir object as the return of parts().
317
my $slice = $dir->slice(0);
319
my $slice = $dir->slice(0,3);
325
$self = $self->clone;
326
@{$self->{dirs}} = $self->parts(@_);
328
} # end subroutine slice definition
329
########################################################################
333
Execute a callback on each part of $dir. The sub should modify $_ (yes,
334
this is slightly unlike the map() builtin.)
336
If $parts is defined as an integer or array reference of integers, it
337
will be treated as a slice on the directory parts to which the map
340
$dir->map(sub {...}, [@parts]);
342
$dir &= sub {s/foo$/bar/};
344
So, to modify only the first directory part:
346
$dir->map(sub {s/foo$/bar/}, 0);
352
my ($sub, $parts) = @_;
353
my @parts = defined($parts) ? (ref($parts) ? @$parts : $parts) :
354
0..($#{$self->{dirs}});
355
# TODO actually use the parts() code for this
357
foreach my $dir (@{$self->{dirs}}[@parts]) {
363
} # end subroutine map definition
364
########################################################################
370
True if the $dir represents a relative (e.g. '.') directory.
372
my $bool = $dir->is_cwd;
379
my @dirs = @{$self->{dirs}};
380
return(@dirs == 1 and $dirs[0] eq '.');
381
} # end subroutine is_cwd definition
382
########################################################################
385
dirname('.') and basename('.') are both '.' -- also true for '/'
389
Returns the last part of the path as a Dir object.
391
my $bit = $dir->basename;
397
return($self->new($self->{dirs}[-1]));
398
} # end subroutine basename definition
399
########################################################################
403
Returns the parent parts of the path as a Dir object.
405
my $parent = $dir->dirname;
411
$self = $self->clone;
412
my $dirs = $self->{dirs};
413
if(@$dirs == 1 and $dirs->[0] eq '') {
414
return($self->new('/'));
417
@$dirs or return($self->new);
419
} # end subroutine dirname definition
420
########################################################################
424
Get an absolute name (without checking the filesystem.)
426
my $abs = $dir->absolute;
432
return $self if $self->is_absolute;
433
return $self->new(File::Spec->rel2abs($self->stringify));
434
} # end subroutine absolute definition
435
########################################################################
439
Get an absolute path (resolved on filesystem, so it must exist.)
441
my $abs = $dir->absolutely;
447
my $res = Cwd::abs_path($self->stringify);
448
defined($res) or croak("$self absolutely() not found");
449
return $self->new($res);
450
} # end subroutine absolutely definition
451
########################################################################
457
Calls opendir(), but throws an error if it fails.
461
Returns a directory handle, for e.g. readdir().
463
my @files = map({$dir + $_} grep({$_ !~ m/^\./} readdir($dh)));
470
opendir(my $dh, "$self") or die "cannot opendir '$self' $!";
472
} # end subroutine open definition
473
########################################################################
477
Update the timestamp of a directory (croak if it doesn't exist.)
486
} # end subroutine touch definition
487
########################################################################
491
my @paths = $dir->list(all => 1);
498
map({my $d = $self/$_; -d $d ? $d : $self+$_} $self->contents(@_));
499
} # end subroutine list definition
500
########################################################################
504
my $subref = $dir->lister(all => 1);
510
my $csub = $self->iterate_contents(@_);
513
while(defined(my $n = $csub->())) {
515
return(-d $d->bare ? $d : $self+$n)
521
} # end subroutine lister definition
522
########################################################################
526
Equivelant to readdir. With the 'all' option true, returns hidden names
527
too (but not the '.' and '..' entries.)
529
The return values are strings, not File::Fu objects.
531
my @names = $dir->contents(all => 1);
537
(@_ % 2) and croak('odd number of items in options hash');
539
my $dh = $self->open;
540
# XXX needs more cross-platformness
541
$opts{all} and return(grep({$_ !~ m/^\.{1,2}$/} readdir($dh)));
542
return(grep({$_ !~ m/^\./} readdir($dh)));
543
} # end subroutine contents definition
544
########################################################################
546
=head2 iterate_contents
548
Returns a subref which will iterate over the directory's contents.
550
my $subref = $dir->iterate_contents(all => 1);
554
sub iterate_contents {
556
(@_ % 2) and croak('odd number of items in options hash');
558
my $all = $opts{all};
559
my $dh = $self->open;
560
# XXX needs more cross-platformness
563
while(defined(my $n = readdir($dh))) {
565
return($n) unless($n =~ m/^\.{1,2}$/);
568
return($n) unless($n =~ m/^\./);
574
} # end subroutine iterate_contents definition
575
########################################################################
579
Not the same as File::Find::find().
581
my @files = $dir->find(sub {m/foo/});
589
my $finder = $self->finder(@_);
590
while(defined(my $ans = $finder->())) {
595
} # end subroutine find definition
596
########################################################################
600
Returns an iterator for finding files.
602
my $subref = $dir->finder(sub {$_->is_file and $_->file =~ m/foo/});
604
This allows a non-blocking find.
606
while(defined(my $path = $subref->())) {
607
$path or next; # 0 means 'not done yet'
608
# do something with $path (is a file or dir object)
613
my $finder = $dir->finder(sub {
615
if($_->is_dir and $_->part(-1) =~ m/^\.svn$/);
616
$_->is_file and m/\.pm$/;
623
my ($matcher, @opt) = @_;
625
my %opt = (all => 1);
632
$reader ||= $self->lister(all => $opt{all});
634
if(defined(my $path = $reader->())) {
635
if($path->is_dir and not $path->l) {
636
push(@stack, [$self, $reader]);
637
($self, $reader) = ($path, undef);
640
#warn " check $path\n";
641
my $ok = $matcher->(my $knob = File::Fu::Dir::FindKnob->new);
643
($self, $reader) = @{pop(@stack)};
648
redo FIND if($loops < 50);
649
return(0); # no match, but continue
653
($self, $reader) = @{pop(@stack)};
659
} # end subroutine finder definition
660
########################################################################
663
package File::Fu::Dir::FindKnob;
664
use Class::Accessor::Classy;
667
no Class::Accessor::Classy;
668
sub prune {shift->set_pruned(1); 0}
669
} # File::Fu::Dir::FindKnob
670
########################################################################
674
Create the directory or croak with an error.
685
my $mode = shift(@_);
686
mkdir($self, $mode) or croak("cannot mkdir('$self', $mode) $!");
689
mkdir($self) or croak("cannot mkdir('$self') $!");
692
} # end subroutine mkdir definition
693
########################################################################
697
Create the directory, with parents if needed.
705
# TODO pass mode, but the verbose parameter is silly (should have been
706
# a callback or something -- so we'll end up reimplementing mkpath?)
707
File::Path::mkpath("$self");
709
} # end subroutine create definition
710
########################################################################
714
Remove the directory or croak with an error.
722
rmdir($self) or croak("cannot rmdir('$self') $!");
723
} # end subroutine rmdir definition
724
########################################################################
728
Remove the directory and all of its children.
736
my $dir = $self->stringify;
737
File::Path::rmtree($dir);
738
-e $dir and croak("rmtree failed"); # XXX rmtree is buggy
739
} # end subroutine remove definition
740
########################################################################
750
$self->l or croak("not a link");
751
unlink($self->bare) or croak("unlink '$self' failed $!");
752
} # end subroutine unlink definition
753
########################################################################
757
Create a symlink which points to $dir.
759
my $link = $dir->symlink($linkname);
761
Note that symlinks are relative to where they live, so if $dir is a
762
relative path, it must be relative to $linkname.
766
sub symlink :method {
770
$name =~ s#/$##; # stringify and strip
771
symlink($self, $name) or
772
croak("symlink '$self' to '$name' failed $!");
773
return($self->new($name));
774
} # end subroutine symlink definition
775
########################################################################
779
my $to = $file->readlink;
783
sub readlink :method {
785
my $name = readlink($self->bare);
786
defined($name) or croak("cannot readlink '$self' $!");
787
return($self->new($name));
788
} # end subroutine readlink definition
789
########################################################################
791
=head1 Changing Directories
796
Change to the directory in self, returning a new '.' directory object.
804
chdir($self) or croak("cannot chdir '$self' $!");
805
# should return a new '.' object ?
806
return($self->new('.'));
807
} # end subroutine chdir definition
808
########################################################################
812
Change to $dir and run the given subroutine. The sub will be passed a
813
'./' directory object.
815
$dir->chdir_for(sub {...});
822
# we need to guarantee that we return, so we must implement the scoped
823
# version in order to implement the wrapper.
824
my $dot = $self->chdir_local;
825
# XXX bah. the $token binds weirdly in 5.6.2
826
return $sub->($self->new('.'));
827
} # end subroutine chdir_for definition
828
########################################################################
832
Change to $dir, but return to the current cwd when $token goes out of
835
my $token = $self->chdir_local;
841
my $now = $self->top_class->cwd;
843
return $self->token_class->new->return_to($now);
844
} # end subroutine chdir_local definition
845
########################################################################
847
package File::Fu::Dir::Token;
848
our @ISA = qw('File::Fu::Dir);
850
my $self = shift(@_);
851
$self->{return_to} = shift(@_) or croak("invalid usage");
854
sub DESTROY { my $ret = shift->{return_to} or return; $ret->chdir; }
856
########################################################################
858
=head1 Temporary Directories and Files
860
These methods use the $dir object as a parent location for the temp
861
path. To use your system's global temp space (e.g. '/tmp/'), just
862
replace $dir with 'File::Fu'.
864
File::Fu->temp_dir; # '/tmp/'
865
File::Fu->dir->temp_dir; # './'
866
File::Fu->dir("foo")->temp_dir; # 'foo/'
868
File::Fu->temp_file; # '/tmp/'
869
File::Fu->dir->temp_file; # './'
870
File::Fu->dir("foo")->temp_file; # 'foo/'
874
Return a temporary directory in $dir.
876
my $dir = $dir->temp_dir;
882
$self->temp_dir_class->new($self, @_);
883
} # end subroutine temp_dir definition
884
########################################################################
888
Return a filehandle to a temporary file in $dir.
890
my $handle = $dir->temp_file;
896
$self->temp_file_class->new($self, @_);
897
} # end subroutine temp_file definition
898
########################################################################
902
Eric Wilhelm @ <ewilhelm at cpan dot org>
904
http://scratchcomputing.com/
908
If you found this module on CPAN, please report any bugs or feature
909
requests through the web interface at L<http://rt.cpan.org>. I will be
910
notified, and then you'll automatically be notified of progress on your
911
bug as I make changes.
913
If you pulled this development version from my /svn/, please contact me
918
Copyright (C) 2008 Eric L. Wilhelm, All Rights Reserved.
922
Absolutely, positively NO WARRANTY, neither express or implied, is
923
offered with this software. You use this software at your own risk. In
924
case of loss, no person or entity owes you anything whatsoever. You
929
This program is free software; you can redistribute it and/or modify it
930
under the same terms as Perl itself.
935
# vi:ts=2:sw=2:et:sta