File Coverage

blib/lib/File/chmod/Recursive.pm
Criterion Covered Total %
statement 24 96 25.0
branch 0 54 0.0
condition 0 27 0.0
subroutine 8 12 66.6
pod 3 3 100.0
total 35 192 18.2


line stmt bran cond sub pod time code
1             package File::chmod::Recursive;
2              
3             #######################
4             # LOAD MODULES
5             #######################
6 1     1   769 use strict;
  1         2  
  1         26  
7 1     1   5 use warnings;
  1         1  
  1         35  
8 1     1   12 use Carp qw(croak carp);
  1         2  
  1         56  
9              
10 1     1   5 use Cwd qw(abs_path);
  1         2  
  1         42  
11 1     1   4 use File::Find qw(find);
  1         7  
  1         58  
12 1     1   769 use File::chmod qw(chmod);
  1         2981  
  1         75  
13              
14             #######################
15             # VERSION
16             #######################
17             our $VERSION = '1.0.3';
18              
19             #######################
20             # EXPORT
21             #######################
22 1     1   6 use base qw(Exporter);
  1         1  
  1         323  
23             our ( @EXPORT, @EXPORT_OK );
24              
25             @EXPORT = qw(chmod_recursive);
26             @EXPORT_OK = qw(chmod_recursive rchmod chmodr);
27              
28             #######################
29             # CHMOD RECURSIVE
30             #######################
31             sub chmod_recursive {
32              
33             # Read Input
34 0     0 1   my @in = @_;
35              
36             # Default mode
37 0           my $mode = {
38             files => q(),
39             dirs => q(),
40             match_dirs => {},
41             match_files => {},
42             match => {},
43             };
44              
45             # Default _find_ settings
46 0           my %find_settings = (
47             follow => 0, # Do not Follow symlinks
48             no_chdir => 1, # Do not chdir
49             );
50              
51             # Verbose mode
52 0           my $verbose = 0;
53              
54             # Check Input
55 0           my $dir;
56 0 0         if ( ref $in[0] eq 'HASH' ) {
57              
58             # Usage chmod_recursive({}, $dir);
59              
60             # Get modes
61 0   0       $mode->{files} = $in[0]->{files} || q();
62 0   0       $mode->{dirs} = $in[0]->{dirs} || q();
63 0   0       $mode->{match_files} = $in[0]->{match_files} || {};
64 0   0       $mode->{match_dirs} = $in[0]->{match_dirs} || {};
65 0   0       $mode->{match} = $in[0]->{match} || {};
66              
67             # Check for _find_ settings
68 0 0         if ( $in[0]->{follow_symlinks} ) {
69 0           $find_settings{follow} = 1; # Follow Symlinks
70 0           $find_settings{follow_skip} = 2; # Skip duplicates
71             } ## end if ( $in[0]->{follow_symlinks...})
72 0 0         if ( $in[0]->{depth_first} ) {
73 0           $find_settings{bydepth} = 1;
74             }
75              
76             # Verbose on/off
77 0   0       $verbose = $in[0]->{verbose} || 0;
78              
79             } ## end if ( ref $in[0] eq 'HASH')
80              
81             else {
82              
83             # Usage chmod_recursive($mode, $dir);
84              
85             # Set modes
86 0           $mode->{files} = $in[0];
87 0           $mode->{dirs} = $in[0];
88             } ## end else [ if ( ref $in[0] eq 'HASH')]
89              
90             # Get directory
91 0   0       $dir = $in[1] || croak "Directory not provided";
92 0           $dir = abs_path($dir);
93 0 0         croak "$dir is not a directory" unless -d $dir;
94              
95             # Run chmod
96 0           my @updated;
97             {
98              
99             # Turn off warnings for file find
100 1     1   5 no warnings 'File::Find';
  1         2  
  1         876  
  0            
101              
102             # Turn off UMASK for File::chmod
103             # See: https://github.com/xenoterracide/File-chmod/issues/5
104 0           local $File::chmod::UMASK = 0;
105              
106             find(
107             {
108             %find_settings,
109             wanted => sub {
110              
111             # The main stuff
112              
113             # Get full path
114 0     0     my $path = $File::Find::name;
115              
116 0 0         if ( not -l $path ) { # Do not set permissions on symlinks
117              
118             # Process files
119 0 0         if ( -f $path ) {
    0          
120              
121 0           my $file_isa_match = 0;
122              
123             # Process file Matches
124 0           foreach
125 0           my $match_re ( keys %{ $mode->{match_files} } )
126             {
127 0 0         next if $file_isa_match;
128 0 0         next unless ( $path =~ m{$match_re} );
129 0           $file_isa_match = 1; # Done matching
130 0 0         if (
131             chmod(
132             $mode->{match_files}->{$match_re},
133             $path
134             )
135             )
136             {
137 0           push @updated, $path;
138             warn "chmod_recursive: $path -> "
139             . (
140             sprintf "%#o",
141 0 0         $mode->{match_files}->{$match_re}
142             )
143             . "\n"
144             if $verbose;
145             } ## end if ( chmod( $mode->{match_files...}))
146             } ## end foreach my $match_re ( keys...)
147              
148             # Process generic matches
149 0           foreach my $match_re ( keys %{ $mode->{match} } )
  0            
150             {
151 0 0         next if $file_isa_match;
152 0 0         next unless ( $path =~ m{$match_re} );
153 0           $file_isa_match = 1;
154 0 0         if (
155             chmod(
156             $mode->{match}->{$match_re},
157             $path
158             )
159             )
160             {
161 0           push @updated, $path;
162             warn "chmod_recursive: $path -> "
163             . (
164             sprintf "%#o",
165 0 0         $mode->{match}->{$match_re}
166             )
167             . "\n"
168             if $verbose;
169             } ## end if ( chmod( $mode->{match...}))
170             } ## end foreach my $match_re ( keys...)
171              
172             # Process non-matches
173 0 0 0       if (
      0        
174              
175             # Skip processed
176             ( not $file_isa_match )
177              
178             # And we're updating files
179             and ( $mode->{files} )
180              
181             # And succesfully updated
182             and ( chmod( $mode->{files}, $path ) )
183             )
184             {
185 0           push @updated, $path;
186             warn "chmod_recursive: $path -> "
187 0 0         . ( sprintf "%#o", $mode->{files} ) . "\n"
188             if $verbose;
189             } ## end if ( ( not $file_isa_match...))
190             } ## end if ( -f $path )
191              
192             # Process Dirs
193             elsif ( -d $path ) {
194              
195 0           my $dir_isa_match = 0;
196              
197             # Process Matches
198 0           foreach
199 0           my $match_re ( keys %{ $mode->{match_dirs} } )
200             {
201 0 0         next if $dir_isa_match;
202 0 0         next unless ( $path =~ m{$match_re} );
203 0           $dir_isa_match = 1; # Done matching
204 0 0         if (
205             chmod(
206             $mode->{match_dirs}->{$match_re},
207             $path
208             )
209             )
210             {
211 0           push @updated, $path;
212             warn "chmod_recursive: $path -> "
213             . (
214             sprintf "%#o",
215 0 0         $mode->{match_dirs}->{$match_re}
216             )
217             . "\n"
218             if $verbose;
219             } ## end if ( chmod( $mode->{match_dirs...}))
220             } ## end foreach my $match_re ( keys...)
221              
222             # Process generic matches
223 0           foreach my $match_re ( keys %{ $mode->{match} } )
  0            
224             {
225 0 0         next if $dir_isa_match;
226 0 0         next unless ( $path =~ m{$match_re} );
227 0           $dir_isa_match = 1; # Done matching
228 0 0         if (
229             chmod(
230             $mode->{match}->{$match_re},
231             $path
232             )
233             )
234             {
235 0           push @updated, $path;
236             warn "chmod_recursive: $path -> "
237             . (
238             sprintf "%#o",
239 0 0         $mode->{match}->{$match_re}
240             )
241             . "\n"
242             if $verbose;
243             } ## end if ( chmod( $mode->{match...}))
244             } ## end foreach my $match_re ( keys...)
245              
246             # Process non-matches
247 0 0 0       if (
      0        
248              
249             # Skip processed
250             ( not $dir_isa_match )
251              
252             # And we're updating files
253             and ( $mode->{dirs} )
254              
255             # And succesfully updated
256             and ( chmod( $mode->{dirs}, $path ) )
257             )
258             {
259 0           push @updated, $path;
260             warn "chmod_recursive: $path -> "
261 0 0         . ( sprintf "%#o", $mode->{dirs} ) . "\n"
262             if $verbose;
263             } ## end if ( ( not $dir_isa_match...))
264             } ## end elsif ( -d $path )
265              
266             } ## end if ( not -l $path )
267              
268             },
269             },
270 0           $dir
271             );
272             }
273              
274             # Done
275 0           return scalar @updated;
276             } ## end sub chmod_recursive
277              
278             #######################
279             # ALIASES
280             #######################
281 0     0 1   sub rchmod { return chmod_recursive(@_); }
282 0     0 1   sub chmodr { return chmod_recursive(@_); }
283              
284             #######################
285             1;
286              
287             __END__