File Coverage

blib/lib/File/Path/Tiny.pm
Criterion Covered Total %
statement 85 90 94.4
branch 37 50 74.0
condition 16 33 48.4
subroutine 9 9 100.0
pod 4 4 100.0
total 151 186 81.1


line stmt bran cond sub pod time code
1             package File::Path::Tiny;
2              
3 2     2   127016 use strict;
  2         11  
  2         45  
4 2     2   9 use warnings;
  2         3  
  2         44  
5 2     2   20 use Cwd qw(cwd chdir);
  2         3  
  2         73  
6 2     2   8 use Carp ();
  2         3  
  2         1502  
7              
8             $File::Path::Tiny::VERSION = 0.9;
9              
10             sub mk {
11 16     16 1 11180 my ( $path, $mask ) = @_;
12 16 100       271 return 2 if -d $path;
13 12 100       90 if ( -e $path ) { $! = 20; return; }
  1         3  
  1         5  
14 11   100     68 $mask ||= '0777'; # Perl::Critic == Integer with leading zeros at ...
15 11 100       67 $mask = oct($mask) if substr( $mask, 0, 1 ) eq '0';
16 11         68 require File::Spec;
17 11         112 my ( $vol, $directories ) = File::Spec->splitpath( $path, 1 );
18 11         49 my @dirs = File::Spec->splitdir($directories);
19 11         16 my @list;
20              
21 11         30 while ( my ($_dir) = shift @dirs ) {
22 41 100       89 last if not defined $_dir;
23 30         50 push @list, $_dir;
24 30 100       50 next if ( $_dir eq '' );
25 28         202 my $progressive = File::Spec->catpath( $vol, File::Spec->catdir(@list), '' );
26 28 100       295 if ( !-d $progressive ) {
27 18 50 33     651 mkdir( $progressive, $mask ) or -d $progressive or return;
28             }
29             }
30 11 50       163 return 1 if -d $path;
31 0         0 return;
32             }
33              
34             sub rm {
35 120     120 1 44431 my ( $path, $fast ) = @_;
36 120         1310 my ( $orig_dev, $orig_ino ) = ( lstat $path )[ 0, 1 ];
37 120 100 100     1154 if ( -e _ && !-d _ ) { $! = 20; return; }
  3         21  
  3         20  
38 117 100       333 return 2 if !-d _;
39              
40 116 50       407 empty_dir( $path, $fast ) or return;
41 111         324 _bail_if_changed( $path, $orig_dev, $orig_ino );
42 111 50 33     3942 rmdir($path) or !-e $path or return;
43 111         929 return 1;
44             }
45              
46             sub empty_dir {
47 122     122 1 9968 my ( $path, $fast ) = @_;
48 122         1240 my ( $orig_dev, $orig_ino ) = ( lstat $path )[ 0, 1 ];
49 122 50 33     1039 if ( -e _ && !-d _ ) { $! = 20; return; }
  0         0  
  0         0  
50              
51 122         695 my ( $starting_point, $starting_dev, $starting_ino );
52 122 50       355 if ( !$fast ) {
53 122         245672 $starting_point = cwd();
54 122         3503 ( $starting_dev, $starting_ino ) = ( lstat $starting_point )[ 0, 1 ];
55 122 50       11177 chdir($path) or Carp::croak("Failed to change directory to “$path”: $!");
56 122         734 $path = '.';
57 122         1574 _bail_if_changed( $path, $orig_dev, $orig_ino );
58             }
59              
60 122 50       3108 opendir( DIR, $path ) or return;
61 122 100       2472 my @contents = grep { $_ ne '.' && $_ ne '..' } readdir(DIR);
  423         3291  
62 122         1191 closedir DIR;
63 122         439 _bail_if_changed( $path, $orig_dev, $orig_ino );
64              
65 122 100       2148 require File::Spec if @contents;
66 122         633 for my $thing (@contents) {
67 179         2343 my $long = File::Spec->catdir( $path, $thing );
68 179 100 100     57020 if ( !-l $long && -d _ ) {
69 80         305 _bail_if_changed( $path, $orig_dev, $orig_ino );
70 80 50 33     254 rm($long) or !-e $long or return;
71             }
72             else {
73 99         549 _bail_if_changed( $path, $orig_dev, $orig_ino );
74 89 50 33     3813 unlink $long or !-e $long or return;
75             }
76             }
77              
78 112         404 _bail_if_changed( $path, $orig_dev, $orig_ino );
79              
80 112 50       253 if ( !$fast ) {
81 112 50       2534 chdir($starting_point) or Carp::croak("Failed to change directory to “$starting_point”: $!");
82 112         369 _bail_if_changed( ".", $starting_dev, $starting_ino );
83             }
84              
85 112         654 return 1;
86             }
87              
88             sub mk_parent {
89 7     7 1 535 my ( $path, $mode ) = @_;
90 7         46 $path =~ s{/+$}{};
91              
92 7         42 require File::Spec;
93 7         47 my ( $v, $d, $f ) = File::Spec->splitpath( $path, 1 );
94 7         31 my @p = File::Spec->splitdir($d);
95              
96             # pop() is probably cheaper here, benchmark? $d = File::Spec->catdir(@p[0--$#p-1]);
97 7         11 pop @p;
98 7         36 $d = File::Spec->catdir(@p);
99              
100 7         43 my $parent = File::Spec->catpath( $v, $d, $f );
101 7         13 return mk( $parent, $mode );
102             }
103              
104             sub _bail_if_changed {
105 758     758   2650 my ( $path, $orig_dev, $orig_ino ) = @_;
106              
107 758         8260 my ( $cur_dev, $cur_ino ) = ( lstat $path )[ 0, 1 ];
108              
109 758 50 33     5198 if ( !defined $cur_dev || !defined $cur_ino ) {
110 0   0     0 $cur_dev ||= "undef(path went away?)";
111 0   0     0 $cur_ino ||= "undef(path went away?)";
112             }
113             else {
114 758         8704 $path = Cwd::abs_path($path);
115             }
116              
117 758 100 66     4426 if ( $orig_dev ne $cur_dev || $orig_ino ne $cur_ino ) {
118 10         95 local $Carp::CarpLevel += 1;
119 10         617 Carp::croak("directory $path changed: expected dev=$orig_dev ino=$orig_ino, actual dev=$cur_dev ino=$cur_ino, aborting");
120             }
121             }
122              
123             1;