File Coverage

blib/lib/App/FileRemoveUtils.pm
Criterion Covered Total %
statement 53 55 96.3
branch 23 28 82.1
condition 2 3 66.6
subroutine 9 9 100.0
pod 2 2 100.0
total 89 97 91.7


line stmt bran cond sub pod time code
1             package App::FileRemoveUtils;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2020-06-03'; # DATE
5             our $DIST = 'App-FileRemoveUtils'; # DIST
6             our $VERSION = '0.003'; # VERSION
7              
8 1     1   101733 use 5.010001;
  1         12  
9 1     1   5 use strict;
  1         4  
  1         21  
10 1     1   5 use warnings;
  1         2  
  1         22  
11 1     1   1843 use Log::ger;
  1         52  
  1         5  
12              
13 1     1   252 use Exporter 'import';
  1         3  
  1         716  
14             our @EXPORT_OK = qw(delete_all_empty_files delete_all_empty_dirs);
15              
16             our %SPEC;
17              
18             $SPEC{delete_all_empty_files} = {
19             v => 1.1,
20             summary => 'Delete all empty (zero-sized) files recursively',
21             args => {
22             },
23             features => {
24             dry_run=>{default=>1},
25             },
26             examples => [
27             {
28             summary => 'Show what files will be deleted (dry-mode by default)',
29             src => 'delete-all-empty-files',
30             src_plang => 'bash',
31             test => 0,
32             'x.doc.show_result' => 0,
33             },
34             {
35             summary => 'Actually delete files (disable dry-run mode)',
36             src => 'delete-all-empty-files --no-dry-run',
37             src_plang => 'bash',
38             test => 0,
39             'x.doc.show_result' => 0,
40             },
41             ],
42             };
43             sub delete_all_empty_files {
44 2     2 1 4640 require File::Find;
45 2         6 my %args = @_;
46              
47 2         4 my @files;
48             File::Find::find(
49             sub {
50 16     16   156 -l $_; # perform lstat instead of stat
51 16 100       344 return unless -f _;
52 12 100       97 return if -s _;
53 6         70 push @files, "$File::Find::dir/$_";
54             },
55 2         148 '.'
56             );
57              
58 2         15 for my $f (@files) {
59 6 100       23 if ($args{-dry_run}) {
60 3         11 log_info "[DRY-RUN] Deleting %s ...", $f;
61             } else {
62 3         22 log_info "Deleting %s ...", $f;
63 3 50       119 unlink $f or do {
64 0         0 log_error "Failed deleting %s: %s", $f, $!;
65             };
66             }
67             }
68              
69 2         28 [200, "OK", undef, {
70             'func.files' => \@files,
71             }];
72             }
73              
74             $SPEC{delete_all_empty_dirs} = {
75             v => 1.1,
76             summary => 'Delete all empty (zero-sized) subdirectories recursively',
77             args => {
78             },
79             features => {
80             dry_run=>{default=>1},
81             },
82             examples => [
83             {
84             summary => 'Show what directories will be deleted (dry-mode by default)',
85             src => 'delete-all-empty-dirs',
86             src_plang => 'bash',
87             test => 0,
88             'x.doc.show_result' => 0,
89             },
90             {
91             summary => 'Actually delete files (disable dry-run mode)',
92             src => 'delete-all-empty-dirs --no-dry-run',
93             src_plang => 'bash',
94             test => 0,
95             'x.doc.show_result' => 0,
96             },
97             ],
98             };
99             sub delete_all_empty_dirs {
100 2     2 1 6213 require File::Find;
101 2         575 require File::MoreUtil;
102 2         2333 my %args = @_;
103              
104 2         4 my %dirs; # key = path, value = {subdir => 1}
105             File::Find::find(
106             sub {
107 26 100 66 26   1049 return if $_ eq '.' || $_ eq '..';
108 24 50       282 return if -l $_;
109 24 100       238 return unless -d _;
110 12 100       39 return if File::MoreUtil::dir_has_non_subdirs($_);
111 10 100       773 my $path = ($File::Find::dir eq '.' ? '' : "$File::Find::dir/"). $_;
112 10         30 $dirs{$path} = { map {$_=>1} File::MoreUtil::get_dir_entries($_) };
  6         574  
113             },
114 2         107 '.'
115             );
116              
117 2         259 for my $dir (sort { length($b) <=> length($a) } keys %dirs) {
  17         30  
118 10 100       28 if ($args{-dry_run}) {
119 5 100       11 if (!(keys %{ $dirs{$dir} })) {
  5         24  
120 4         14 log_info "[DRY-RUN] Deleting %s ...", $dir;
121 4 50       27 $dir =~ m!(.+)/(.+)! or next;
122 4         12 my ($parent, $base) = ($1, $2);
123 4         13 delete $dirs{$parent}{$base};
124             }
125             } else {
126 5 50       22 if (File::MoreUtil::dir_empty($dir)) {
127 5         369 log_info "Deleting %s ...", $dir;
128 5 50       190 rmdir $dir or do {
129 0         0 log_error "Failed deleting %s: %s", $dir, $!;
130             };
131             }
132             }
133             }
134              
135 2         16 [200];
136             }
137              
138             1;
139             # ABSTRACT: Utilities related to removing/deleting files
140              
141             __END__
142              
143             =pod
144              
145             =encoding UTF-8
146              
147             =head1 NAME
148              
149             App::FileRemoveUtils - Utilities related to removing/deleting files
150              
151             =head1 VERSION
152              
153             This document describes version 0.003 of App::FileRemoveUtils (from Perl distribution App-FileRemoveUtils), released on 2020-06-03.
154              
155             =head1 DESCRIPTION
156              
157             This distribution provides the following command-line utilities:
158              
159             =over
160              
161             =item * L<delete-all-empty-dirs>
162              
163             =item * L<delete-all-empty-files>
164              
165             =back
166              
167             =head1 FUNCTIONS
168              
169              
170             =head2 delete_all_empty_dirs
171              
172             Usage:
173              
174             delete_all_empty_dirs() -> [status, msg, payload, meta]
175              
176             Delete all empty (zero-sized) subdirectories recursively.
177              
178             This function is not exported by default, but exportable.
179              
180             This function supports dry-run operation.
181              
182              
183             No arguments.
184              
185             Special arguments:
186              
187             =over 4
188              
189             =item * B<-dry_run> => I<bool>
190              
191             Pass -dry_run=E<gt>1 to enable simulation mode.
192              
193             =back
194              
195             Returns an enveloped result (an array).
196              
197             First element (status) is an integer containing HTTP status code
198             (200 means OK, 4xx caller error, 5xx function error). Second element
199             (msg) is a string containing error message, or 'OK' if status is
200             200. Third element (payload) is optional, the actual result. Fourth
201             element (meta) is called result metadata and is optional, a hash
202             that contains extra information.
203              
204             Return value: (any)
205              
206              
207              
208             =head2 delete_all_empty_files
209              
210             Usage:
211              
212             delete_all_empty_files() -> [status, msg, payload, meta]
213              
214             Delete all empty (zero-sized) files recursively.
215              
216             This function is not exported by default, but exportable.
217              
218             This function supports dry-run operation.
219              
220              
221             No arguments.
222              
223             Special arguments:
224              
225             =over 4
226              
227             =item * B<-dry_run> => I<bool>
228              
229             Pass -dry_run=E<gt>1 to enable simulation mode.
230              
231             =back
232              
233             Returns an enveloped result (an array).
234              
235             First element (status) is an integer containing HTTP status code
236             (200 means OK, 4xx caller error, 5xx function error). Second element
237             (msg) is a string containing error message, or 'OK' if status is
238             200. Third element (payload) is optional, the actual result. Fourth
239             element (meta) is called result metadata and is optional, a hash
240             that contains extra information.
241              
242             Return value: (any)
243              
244             =head1 HOMEPAGE
245              
246             Please visit the project's homepage at L<https://metacpan.org/release/App-FileRemoveUtils>.
247              
248             =head1 SOURCE
249              
250             Source repository is at L<https://github.com/perlancar/perl-App-FileRemoveUtils>.
251              
252             =head1 BUGS
253              
254             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-FileRemoveUtils>
255              
256             When submitting a bug or request, please include a test-file or a
257             patch to an existing test-file that illustrates the bug or desired
258             feature.
259              
260             =head1 SEE ALSO
261              
262             L<rmhere> from L<App::rmhere>
263              
264             =head1 AUTHOR
265              
266             perlancar <perlancar@cpan.org>
267              
268             =head1 COPYRIGHT AND LICENSE
269              
270             This software is copyright (c) 2020 by perlancar@cpan.org.
271              
272             This is free software; you can redistribute it and/or modify it under
273             the same terms as the Perl 5 programming language system itself.
274              
275             =cut