line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# $Id$ |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package File::Find::Rule; |
4
|
1
|
|
|
1
|
|
256615
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
83
|
|
5
|
1
|
|
|
1
|
|
7
|
use File::Spec; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
6
|
1
|
|
|
1
|
|
78562
|
use Text::Glob 'glob_to_regex'; |
|
1
|
|
|
|
|
1109
|
|
|
1
|
|
|
|
|
77
|
|
7
|
1
|
|
|
1
|
|
80785
|
use Number::Compare; |
|
1
|
|
|
|
|
701
|
|
|
1
|
|
|
|
|
38
|
|
8
|
1
|
|
|
1
|
|
5
|
use Carp qw/croak/; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
43
|
|
9
|
1
|
|
|
1
|
|
6
|
use File::Find (); # we're only wrapping for now |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
68
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '0.33'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# we'd just inherit from Exporter, but I want the colon |
14
|
|
|
|
|
|
|
sub import { |
15
|
4
|
|
|
4
|
|
1204
|
my $pkg = shift; |
16
|
4
|
|
|
|
|
13
|
my $to = caller; |
17
|
4
|
|
|
|
|
9
|
for my $sym ( qw( find rule ) ) { |
18
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
911
|
|
19
|
8
|
|
|
|
|
12
|
*{"$to\::$sym"} = \&{$sym}; |
|
8
|
|
|
|
|
43
|
|
|
8
|
|
|
|
|
24
|
|
20
|
|
|
|
|
|
|
} |
21
|
4
|
|
|
|
|
53
|
for (grep /^:/, @_) { |
22
|
2
|
|
|
|
|
12
|
my ($extension) = /^:(.*)/; |
23
|
2
|
|
|
|
|
471
|
eval "require File::Find::Rule::$extension"; |
24
|
2
|
100
|
|
|
|
267
|
croak "couldn't bootstrap File::Find::Rule::$extension: $@" if $@; |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 NAME |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
File::Find::Rule - Alternative interface to File::Find |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head1 SYNOPSIS |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use File::Find::Rule; |
35
|
|
|
|
|
|
|
# find all the subdirectories of a given directory |
36
|
|
|
|
|
|
|
my @subdirs = File::Find::Rule->directory->in( $directory ); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# find all the .pm files in @INC |
39
|
|
|
|
|
|
|
my @files = File::Find::Rule->file() |
40
|
|
|
|
|
|
|
->name( '*.pm' ) |
41
|
|
|
|
|
|
|
->in( @INC ); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# as above, but without method chaining |
44
|
|
|
|
|
|
|
my $rule = File::Find::Rule->new; |
45
|
|
|
|
|
|
|
$rule->file; |
46
|
|
|
|
|
|
|
$rule->name( '*.pm' ); |
47
|
|
|
|
|
|
|
my @files = $rule->in( @INC ); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head1 DESCRIPTION |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
File::Find::Rule is a friendlier interface to File::Find. It allows |
52
|
|
|
|
|
|
|
you to build rules which specify the desired files and directories. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# the procedural shim |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
*rule = \&find; |
59
|
|
|
|
|
|
|
sub find { |
60
|
28
|
|
|
28
|
0
|
1291
|
my $object = __PACKAGE__->new(); |
61
|
28
|
|
|
|
|
51
|
my $not = 0; |
62
|
|
|
|
|
|
|
|
63
|
28
|
|
|
|
|
76
|
while (@_) { |
64
|
74
|
|
|
|
|
111
|
my $method = shift; |
65
|
74
|
|
|
|
|
84
|
my @args; |
66
|
|
|
|
|
|
|
|
67
|
74
|
100
|
|
|
|
177
|
if ($method =~ s/^\!//) { |
68
|
|
|
|
|
|
|
# jinkies, we're really negating this |
69
|
1
|
|
|
|
|
3
|
unshift @_, $method; |
70
|
1
|
|
|
|
|
4
|
$not = 1; |
71
|
1
|
|
|
|
|
5
|
next; |
72
|
|
|
|
|
|
|
} |
73
|
73
|
100
|
|
|
|
295
|
unless (defined prototype $method) { |
74
|
53
|
|
|
|
|
137
|
my $args = shift; |
75
|
53
|
100
|
|
|
|
158
|
@args = ref $args eq 'ARRAY' ? @$args : $args; |
76
|
|
|
|
|
|
|
} |
77
|
73
|
100
|
|
|
|
140
|
if ($not) { |
78
|
1
|
|
|
|
|
3
|
$not = 0; |
79
|
1
|
|
|
|
|
4
|
@args = $object->new->$method(@args); |
80
|
1
|
|
|
|
|
4
|
$method = "not"; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
73
|
|
|
|
|
532
|
my @return = $object->$method(@args); |
84
|
73
|
100
|
|
|
|
508
|
return @return if $method eq 'in'; |
85
|
|
|
|
|
|
|
} |
86
|
13
|
|
|
|
|
48
|
$object; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head1 METHODS |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=over |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=item C<new> |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
A constructor. You need not invoke C<new> manually unless you wish |
97
|
|
|
|
|
|
|
to, as each of the rule-making methods will auto-create a suitable |
98
|
|
|
|
|
|
|
object if called as class methods. |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub new { |
103
|
57
|
|
|
57
|
1
|
668
|
my $referent = shift; |
104
|
57
|
|
66
|
|
|
257
|
my $class = ref $referent || $referent; |
105
|
57
|
|
|
|
|
494
|
bless { |
106
|
|
|
|
|
|
|
rules => [], |
107
|
|
|
|
|
|
|
subs => {}, |
108
|
|
|
|
|
|
|
iterator => [], |
109
|
|
|
|
|
|
|
extras => {}, |
110
|
|
|
|
|
|
|
maxdepth => undef, |
111
|
|
|
|
|
|
|
mindepth => undef, |
112
|
|
|
|
|
|
|
}, $class; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub _force_object { |
116
|
159
|
|
|
159
|
|
196
|
my $object = shift; |
117
|
159
|
100
|
|
|
|
380
|
$object = $object->new() |
118
|
|
|
|
|
|
|
unless ref $object; |
119
|
159
|
|
|
|
|
680
|
$object; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=back |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=head2 Matching Rules |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=over |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item C<name( @patterns )> |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Specifies names that should match. May be globs or regular |
131
|
|
|
|
|
|
|
expressions. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
$set->name( '*.mp3', '*.ogg' ); # mp3s or oggs |
134
|
|
|
|
|
|
|
$set->name( qr/\.(mp3|ogg)$/ ); # the same as a regex |
135
|
|
|
|
|
|
|
$set->name( 'foo.bar' ); # just things named foo.bar |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=cut |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub _flatten { |
140
|
21
|
|
|
21
|
|
26
|
my @flat; |
141
|
21
|
|
|
|
|
53
|
while (@_) { |
142
|
24
|
|
|
|
|
38
|
my $item = shift; |
143
|
24
|
100
|
|
|
|
116
|
ref $item eq 'ARRAY' ? push @_, @{ $item } : push @flat, $item; |
|
1
|
|
|
|
|
4
|
|
144
|
|
|
|
|
|
|
} |
145
|
21
|
|
|
|
|
61
|
return @flat; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub name { |
149
|
21
|
|
|
21
|
1
|
1099
|
my $self = _force_object shift; |
150
|
21
|
100
|
|
|
|
129
|
my @names = map { ref $_ eq "Regexp" ? $_ : glob_to_regex $_ } _flatten( @_ ); |
|
23
|
|
|
|
|
388
|
|
151
|
|
|
|
|
|
|
|
152
|
21
|
|
|
|
|
71
|
push @{ $self->{rules} }, { |
|
23
|
|
|
|
|
161
|
|
153
|
|
|
|
|
|
|
rule => 'name', |
154
|
21
|
|
|
|
|
1206
|
code => join( ' || ', map { "m{$_}" } @names ), |
155
|
|
|
|
|
|
|
args => \@_, |
156
|
|
|
|
|
|
|
}; |
157
|
|
|
|
|
|
|
|
158
|
21
|
|
|
|
|
99
|
$self; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item -X tests |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Synonyms are provided for each of the -X tests. See L<perlfunc/-X> for |
164
|
|
|
|
|
|
|
details. None of these methods take arguments. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Test | Method Test | Method |
167
|
|
|
|
|
|
|
------|------------- ------|---------------- |
168
|
|
|
|
|
|
|
-r | readable -R | r_readable |
169
|
|
|
|
|
|
|
-w | writeable -W | r_writeable |
170
|
|
|
|
|
|
|
-w | writable -W | r_writable |
171
|
|
|
|
|
|
|
-x | executable -X | r_executable |
172
|
|
|
|
|
|
|
-o | owned -O | r_owned |
173
|
|
|
|
|
|
|
| | |
174
|
|
|
|
|
|
|
-e | exists -f | file |
175
|
|
|
|
|
|
|
-z | empty -d | directory |
176
|
|
|
|
|
|
|
-s | nonempty -l | symlink |
177
|
|
|
|
|
|
|
| -p | fifo |
178
|
|
|
|
|
|
|
-u | setuid -S | socket |
179
|
|
|
|
|
|
|
-g | setgid -b | block |
180
|
|
|
|
|
|
|
-k | sticky -c | character |
181
|
|
|
|
|
|
|
| -t | tty |
182
|
|
|
|
|
|
|
-M | modified | |
183
|
|
|
|
|
|
|
-A | accessed -T | ascii |
184
|
|
|
|
|
|
|
-C | changed -B | binary |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Though some tests are fairly meaningless as binary flags (C<modified>, |
187
|
|
|
|
|
|
|
C<accessed>, C<changed>), they have been included for completeness. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# find nonempty files |
190
|
|
|
|
|
|
|
$rule->file, |
191
|
|
|
|
|
|
|
->nonempty; |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=cut |
194
|
|
|
|
|
|
|
|
195
|
1
|
|
|
1
|
|
7
|
use vars qw( %X_tests ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
192
|
|
196
|
|
|
|
|
|
|
%X_tests = ( |
197
|
|
|
|
|
|
|
-r => readable => -R => r_readable => |
198
|
|
|
|
|
|
|
-w => writeable => -W => r_writeable => |
199
|
|
|
|
|
|
|
-w => writable => -W => r_writable => |
200
|
|
|
|
|
|
|
-x => executable => -X => r_executable => |
201
|
|
|
|
|
|
|
-o => owned => -O => r_owned => |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
-e => exists => -f => file => |
204
|
|
|
|
|
|
|
-z => empty => -d => directory => |
205
|
|
|
|
|
|
|
-s => nonempty => -l => symlink => |
206
|
|
|
|
|
|
|
=> -p => fifo => |
207
|
|
|
|
|
|
|
-u => setuid => -S => socket => |
208
|
|
|
|
|
|
|
-g => setgid => -b => block => |
209
|
|
|
|
|
|
|
-k => sticky => -c => character => |
210
|
|
|
|
|
|
|
=> -t => tty => |
211
|
|
|
|
|
|
|
-M => modified => |
212
|
|
|
|
|
|
|
-A => accessed => -T => ascii => |
213
|
|
|
|
|
|
|
-C => changed => -B => binary => |
214
|
|
|
|
|
|
|
); |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
for my $test (keys %X_tests) { |
217
|
0
|
|
|
0
|
|
0
|
my $sub = eval 'sub () { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
13
|
|
|
|
|
90
|
|
|
13
|
|
|
|
|
24
|
|
|
13
|
|
|
|
|
61
|
|
|
13
|
|
|
|
|
69
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
3
|
|
|
|
|
16
|
|
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
15
|
|
|
3
|
|
|
|
|
16
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
218
|
|
|
|
|
|
|
my $self = _force_object shift; |
219
|
|
|
|
|
|
|
push @{ $self->{rules} }, { |
220
|
|
|
|
|
|
|
code => "' . $test . ' \$_", |
221
|
|
|
|
|
|
|
rule => "'.$X_tests{$test}.'", |
222
|
|
|
|
|
|
|
}; |
223
|
|
|
|
|
|
|
$self; |
224
|
|
|
|
|
|
|
} '; |
225
|
1
|
|
|
1
|
|
12
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
60
|
|
226
|
|
|
|
|
|
|
*{ $X_tests{$test} } = $sub; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item stat tests |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
The following C<stat> based methods are provided: C<dev>, C<ino>, |
233
|
|
|
|
|
|
|
C<mode>, C<nlink>, C<uid>, C<gid>, C<rdev>, C<size>, C<atime>, |
234
|
|
|
|
|
|
|
C<mtime>, C<ctime>, C<blksize>, and C<blocks>. See L<perlfunc/stat> |
235
|
|
|
|
|
|
|
for details. |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
Each of these can take a number of targets, which will follow |
238
|
|
|
|
|
|
|
L<Number::Compare> semantics. |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
$rule->size( 7 ); # exactly 7 |
241
|
|
|
|
|
|
|
$rule->size( ">7Ki" ); # larger than 7 * 1024 * 1024 bytes |
242
|
|
|
|
|
|
|
$rule->size( ">=7" ) |
243
|
|
|
|
|
|
|
->size( "<=90" ); # between 7 and 90, inclusive |
244
|
|
|
|
|
|
|
$rule->size( 7, 9, 42 ); # 7, 9 or 42 |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=cut |
247
|
|
|
|
|
|
|
|
248
|
1
|
|
|
1
|
|
5
|
use vars qw( @stat_tests ); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
228
|
|
249
|
|
|
|
|
|
|
@stat_tests = qw( dev ino mode nlink uid gid rdev |
250
|
|
|
|
|
|
|
size atime mtime ctime blksize blocks ); |
251
|
|
|
|
|
|
|
{ |
252
|
|
|
|
|
|
|
my $i = 0; |
253
|
|
|
|
|
|
|
for my $test (@stat_tests) { |
254
|
|
|
|
|
|
|
my $index = $i++; # to close over |
255
|
|
|
|
|
|
|
my $sub = sub { |
256
|
7
|
|
|
7
|
|
16
|
my $self = _force_object shift; |
257
|
|
|
|
|
|
|
|
258
|
7
|
|
|
|
|
16
|
my @tests = map { Number::Compare->parse_to_perl($_) } @_; |
|
7
|
|
|
|
|
41
|
|
259
|
|
|
|
|
|
|
|
260
|
7
|
|
|
|
|
30
|
push @{ $self->{rules} }, { |
|
7
|
|
|
|
|
37
|
|
261
|
|
|
|
|
|
|
rule => $test, |
262
|
|
|
|
|
|
|
args => \@_, |
263
|
|
|
|
|
|
|
code => 'do { my $val = (stat $_)['.$index.'] || 0;'. |
264
|
7
|
|
|
|
|
177
|
join ('||', map { "(\$val $_)" } @tests ).' }', |
265
|
|
|
|
|
|
|
}; |
266
|
7
|
|
|
|
|
26
|
$self; |
267
|
|
|
|
|
|
|
}; |
268
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1187
|
|
269
|
|
|
|
|
|
|
*$test = $sub; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=item C<any( @rules )> |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=item C<or( @rules )> |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
Allows shortcircuiting boolean evaluation as an alternative to the |
278
|
|
|
|
|
|
|
default and-like nature of combined rules. C<any> and C<or> are |
279
|
|
|
|
|
|
|
interchangeable. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# find avis, movs, things over 200M and empty files |
282
|
|
|
|
|
|
|
$rule->any( File::Find::Rule->name( '*.avi', '*.mov' ), |
283
|
|
|
|
|
|
|
File::Find::Rule->size( '>200M' ), |
284
|
|
|
|
|
|
|
File::Find::Rule->file->empty, |
285
|
|
|
|
|
|
|
); |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=cut |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub any { |
290
|
10
|
|
|
10
|
1
|
22
|
my $self = _force_object shift; |
291
|
|
|
|
|
|
|
# compile all the subrules to code fragments |
292
|
10
|
|
|
|
|
18
|
push @{ $self->{rules} }, { |
|
10
|
|
|
|
|
44
|
|
293
|
|
|
|
|
|
|
rule => "any", |
294
|
|
|
|
|
|
|
code => '(' . join( ' || ', map '( ' . $_->_compile . ' )', @_ ). ')', |
295
|
|
|
|
|
|
|
args => \@_, |
296
|
|
|
|
|
|
|
}; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# merge all the subs hashes of the kids into ourself |
299
|
10
|
|
|
|
|
27
|
%{ $self->{subs} } = map { %{ $_->{subs} } } $self, @_; |
|
10
|
|
|
|
|
26
|
|
|
28
|
|
|
|
|
28
|
|
|
28
|
|
|
|
|
62
|
|
300
|
10
|
|
|
|
|
29
|
$self; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
*or = \&any; |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=item C<none( @rules )> |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=item C<not( @rules )> |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
Negates a rule. (The inverse of C<any>.) C<none> and C<not> are |
310
|
|
|
|
|
|
|
interchangeable. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# files that aren't 8.3 safe |
313
|
|
|
|
|
|
|
$rule->file |
314
|
|
|
|
|
|
|
->not( $rule->new->name( qr/^[^.]{1,8}(\.[^.]{0,3})?$/ ) ); |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=cut |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub not { |
319
|
3
|
|
|
3
|
1
|
10
|
my $self = _force_object shift; |
320
|
|
|
|
|
|
|
|
321
|
3
|
|
|
|
|
13
|
push @{ $self->{rules} }, { |
|
3
|
|
|
|
|
12
|
|
322
|
|
|
|
|
|
|
rule => 'not', |
323
|
|
|
|
|
|
|
args => \@_, |
324
|
3
|
|
|
|
|
6
|
code => '(' . join ( ' && ', map { "!(". $_->_compile . ")" } @_ ) . ")", |
325
|
|
|
|
|
|
|
}; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# merge all the subs hashes into us |
328
|
3
|
|
|
|
|
11
|
%{ $self->{subs} } = map { %{ $_->{subs} } } $self, @_; |
|
3
|
|
|
|
|
8
|
|
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
16
|
|
329
|
3
|
|
|
|
|
16
|
$self; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
*none = \¬ |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=item C<prune> |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
Traverse no further. This rule always matches. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=cut |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub prune () { |
341
|
4
|
|
|
4
|
1
|
11
|
my $self = _force_object shift; |
342
|
|
|
|
|
|
|
|
343
|
4
|
|
|
|
|
6
|
push @{ $self->{rules} }, |
|
4
|
|
|
|
|
16
|
|
344
|
|
|
|
|
|
|
{ |
345
|
|
|
|
|
|
|
rule => 'prune', |
346
|
|
|
|
|
|
|
code => '$File::Find::prune = 1' |
347
|
|
|
|
|
|
|
}; |
348
|
4
|
|
|
|
|
13
|
$self; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=item C<discard> |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
Don't keep this file. This rule always matches. |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=cut |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub discard () { |
358
|
6
|
|
|
6
|
1
|
78
|
my $self = _force_object shift; |
359
|
|
|
|
|
|
|
|
360
|
6
|
|
|
|
|
9
|
push @{ $self->{rules} }, { |
|
6
|
|
|
|
|
25
|
|
361
|
|
|
|
|
|
|
rule => 'discard', |
362
|
|
|
|
|
|
|
code => '$discarded = 1', |
363
|
|
|
|
|
|
|
}; |
364
|
6
|
|
|
|
|
18
|
$self; |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=item C<exec( \&subroutine( $shortname, $path, $fullname ) )> |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
Allows user-defined rules. Your subroutine will be invoked with C<$_> |
370
|
|
|
|
|
|
|
set to the current short name, and with parameters of the name, the |
371
|
|
|
|
|
|
|
path you're in, and the full relative filename. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
Return a true value if your rule matched. |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# get things with long names |
376
|
|
|
|
|
|
|
$rules->exec( sub { length > 20 } ); |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
=cut |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub exec { |
381
|
14
|
|
|
14
|
1
|
39
|
my $self = _force_object shift; |
382
|
14
|
|
|
|
|
20
|
my $code = shift; |
383
|
|
|
|
|
|
|
|
384
|
14
|
|
|
|
|
19
|
push @{ $self->{rules} }, { |
|
14
|
|
|
|
|
56
|
|
385
|
|
|
|
|
|
|
rule => 'exec', |
386
|
|
|
|
|
|
|
code => $code, |
387
|
|
|
|
|
|
|
}; |
388
|
14
|
|
|
|
|
67
|
$self; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=item C<grep( @specifiers )> |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Opens a file and tests it each line at a time. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
For each line it evaluates each of the specifiers, stopping at the |
396
|
|
|
|
|
|
|
first successful match. A specifier may be a regular expression or a |
397
|
|
|
|
|
|
|
subroutine. The subroutine will be invoked with the same parameters |
398
|
|
|
|
|
|
|
as an ->exec subroutine. |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
It is possible to provide a set of negative specifiers by enclosing |
401
|
|
|
|
|
|
|
them in anonymous arrays. Should a negative specifier match the |
402
|
|
|
|
|
|
|
iteration is aborted and the clause is failed. For example: |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
$rule->grep( qr/^#!.*\bperl/, [ sub { 1 } ] ); |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Is a passing clause if the first line of a file looks like a perl |
407
|
|
|
|
|
|
|
shebang line. |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=cut |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub grep { |
412
|
1
|
|
|
1
|
1
|
4
|
my $self = _force_object shift; |
413
|
1
|
50
|
|
|
|
6
|
my @pattern = map { |
414
|
1
|
|
|
|
|
2
|
ref $_ |
415
|
|
|
|
|
|
|
? ref $_ eq 'ARRAY' |
416
|
2
|
100
|
|
|
|
10
|
? map { [ ( ref $_ ? $_ : qr/$_/ ) => 0 ] } @$_ |
|
|
50
|
|
|
|
|
|
417
|
|
|
|
|
|
|
: [ $_ => 1 ] |
418
|
|
|
|
|
|
|
: [ qr/$_/ => 1 ] |
419
|
|
|
|
|
|
|
} @_; |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
$self->exec( sub { |
422
|
3
|
|
|
3
|
|
9
|
local *FILE; |
423
|
3
|
50
|
|
|
|
160
|
open FILE, $_ or return; |
424
|
3
|
|
|
|
|
12
|
local ($_, $.); |
425
|
3
|
|
|
|
|
2597
|
while (<FILE>) { |
426
|
3
|
|
|
|
|
14
|
for my $p (@pattern) { |
427
|
5
|
|
|
|
|
14
|
my ($rule, $ret) = @$p; |
428
|
5
|
50
|
|
|
|
1958
|
return $ret |
|
|
100
|
|
|
|
|
|
429
|
|
|
|
|
|
|
if ref $rule eq 'Regexp' |
430
|
|
|
|
|
|
|
? /$rule/ |
431
|
|
|
|
|
|
|
: $rule->(@_); |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
} |
434
|
0
|
|
|
|
|
0
|
return; |
435
|
1
|
|
|
|
|
9
|
} ); |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=item C<maxdepth( $level )> |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Descend at most C<$level> (a non-negative integer) levels of directories |
441
|
|
|
|
|
|
|
below the starting point. |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
May be invoked many times per rule, but only the most recent value is |
444
|
|
|
|
|
|
|
used. |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=item C<mindepth( $level )> |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
Do not apply any tests at levels less than C<$level> (a non-negative |
449
|
|
|
|
|
|
|
integer). |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=item C<extras( \%extras )> |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Specifies extra values to pass through to C<File::File::find> as part |
454
|
|
|
|
|
|
|
of the options hash. |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
For example this allows you to specify following of symlinks like so: |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
my $rule = File::Find::Rule->extras({ follow => 1 }); |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
May be invoked many times per rule, but only the most recent value is |
461
|
|
|
|
|
|
|
used. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=cut |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
for my $setter (qw( maxdepth mindepth extras )) { |
466
|
|
|
|
|
|
|
my $sub = sub { |
467
|
23
|
|
|
23
|
|
54
|
my $self = _force_object shift; |
468
|
23
|
|
|
|
|
56
|
$self->{$setter} = shift; |
469
|
23
|
|
|
|
|
65
|
$self; |
470
|
|
|
|
|
|
|
}; |
471
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
240
|
|
472
|
|
|
|
|
|
|
*$setter = $sub; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=item C<relative> |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
Trim the leading portion of any path found |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=cut |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub relative () { |
483
|
1
|
|
|
1
|
1
|
6
|
my $self = _force_object shift; |
484
|
1
|
|
|
|
|
3
|
$self->{relative} = 1; |
485
|
1
|
|
|
|
|
3
|
$self; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=item C<not_*> |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
Negated version of the rule. An effective shortand related to ! in |
491
|
|
|
|
|
|
|
the procedural interface. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
$foo->not_name('*.pl'); |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
$foo->not( $foo->new->name('*.pl' ) ); |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=cut |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
0
|
|
0
|
sub DESTROY {} |
500
|
|
|
|
|
|
|
sub AUTOLOAD { |
501
|
1
|
|
|
1
|
|
3
|
our $AUTOLOAD; |
502
|
1
|
50
|
|
|
|
8
|
$AUTOLOAD =~ /::not_([^:]*)$/ |
503
|
|
|
|
|
|
|
or croak "Can't locate method $AUTOLOAD"; |
504
|
1
|
|
|
|
|
3
|
my $method = $1; |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
my $sub = sub { |
507
|
1
|
|
|
1
|
|
3
|
my $self = _force_object shift; |
508
|
1
|
|
|
|
|
4
|
$self->not( $self->new->$method(@_) ); |
509
|
1
|
|
|
|
|
6
|
}; |
510
|
|
|
|
|
|
|
{ |
511
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
628
|
|
|
1
|
|
|
|
|
2
|
|
512
|
1
|
|
|
|
|
6
|
*$AUTOLOAD = $sub; |
513
|
|
|
|
|
|
|
} |
514
|
1
|
|
|
|
|
4
|
&$sub; |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=back |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=head2 Query Methods |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=over |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=item C<in( @directories )> |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
Evaluates the rule, returns a list of paths to matching files and |
526
|
|
|
|
|
|
|
directories. |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=cut |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
sub in { |
531
|
40
|
|
|
40
|
1
|
454
|
my $self = _force_object shift; |
532
|
|
|
|
|
|
|
|
533
|
40
|
|
|
|
|
51
|
my @found; |
534
|
40
|
|
|
|
|
109
|
my $fragment = $self->_compile; |
535
|
40
|
|
|
|
|
57
|
my %subs = %{ $self->{subs} }; |
|
40
|
|
|
|
|
129
|
|
536
|
|
|
|
|
|
|
|
537
|
40
|
50
|
66
|
|
|
129
|
warn "relative mode handed multiple paths - that's a bit silly\n" |
538
|
|
|
|
|
|
|
if $self->{relative} && @_ > 1; |
539
|
|
|
|
|
|
|
|
540
|
40
|
|
|
|
|
63
|
my $topdir; |
541
|
40
|
|
|
|
|
121
|
my $code = 'sub { |
542
|
|
|
|
|
|
|
(my $path = $File::Find::name) =~ s#^(?:\./+)+##; |
543
|
|
|
|
|
|
|
my @args = ($_, $File::Find::dir, $path); |
544
|
|
|
|
|
|
|
my $maxdepth = $self->{maxdepth}; |
545
|
|
|
|
|
|
|
my $mindepth = $self->{mindepth}; |
546
|
|
|
|
|
|
|
my $relative = $self->{relative}; |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
# figure out the relative path and depth |
549
|
|
|
|
|
|
|
my $relpath = $File::Find::name; |
550
|
|
|
|
|
|
|
$relpath =~ s{^\Q$topdir\E/?}{}; |
551
|
|
|
|
|
|
|
my $depth = scalar File::Spec->splitdir($relpath); |
552
|
|
|
|
|
|
|
#print "name: \'$File::Find::name\' "; |
553
|
|
|
|
|
|
|
#print "relpath: \'$relpath\' depth: $depth relative: $relative\n"; |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
defined $maxdepth && $depth >= $maxdepth |
556
|
|
|
|
|
|
|
and $File::Find::prune = 1; |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
defined $mindepth && $depth < $mindepth |
559
|
|
|
|
|
|
|
and return; |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
#print "Testing \'$_\'\n"; |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
my $discarded; |
564
|
|
|
|
|
|
|
return unless ' . $fragment . '; |
565
|
|
|
|
|
|
|
return if $discarded; |
566
|
|
|
|
|
|
|
if ($relative) { |
567
|
|
|
|
|
|
|
push @found, $relpath if $relpath ne ""; |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
else { |
570
|
|
|
|
|
|
|
push @found, $path; |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
}'; |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
#use Data::Dumper; |
575
|
|
|
|
|
|
|
#print Dumper \%subs; |
576
|
|
|
|
|
|
|
#warn "Compiled sub: '$code'\n"; |
577
|
|
|
|
|
|
|
|
578
|
40
|
50
|
|
|
|
22785
|
my $sub = eval "$code" or die "compile error '$code' $@"; |
579
|
40
|
|
|
|
|
245
|
for my $path (@_) { |
580
|
|
|
|
|
|
|
# $topdir is used for relative and maxdepth |
581
|
40
|
|
|
|
|
65
|
$topdir = $path; |
582
|
|
|
|
|
|
|
# slice off the trailing slash if there is one (the |
583
|
|
|
|
|
|
|
# maxdepth/mindepth code is fussy) |
584
|
40
|
50
|
|
|
|
251
|
$topdir =~ s{/?$}{} |
585
|
|
|
|
|
|
|
unless $topdir eq '/'; |
586
|
40
|
|
|
|
|
77
|
$self->_call_find( { %{ $self->{extras} }, wanted => $sub }, $path ); |
|
40
|
|
|
|
|
370
|
|
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
|
589
|
40
|
|
|
|
|
2656
|
return @found; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
sub _call_find { |
593
|
40
|
|
|
40
|
|
59
|
my $self = shift; |
594
|
40
|
|
|
|
|
4920
|
File::Find::find( @_ ); |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub _compile { |
598
|
61
|
|
|
61
|
|
98
|
my $self = shift; |
599
|
|
|
|
|
|
|
|
600
|
61
|
100
|
|
|
|
62
|
return '1' unless @{ $self->{rules} }; |
|
61
|
|
|
|
|
189
|
|
601
|
|
|
|
|
|
|
my $code = join " && ", map { |
602
|
86
|
100
|
|
|
|
175
|
if (ref $_->{code}) { |
|
55
|
|
|
|
|
102
|
|
603
|
14
|
|
|
|
|
140
|
my $key = "$_->{code}"; |
604
|
14
|
|
|
|
|
43
|
$self->{subs}{$key} = $_->{code}; |
605
|
14
|
|
|
|
|
59
|
"\$subs{'$key'}->(\@args) # $_->{rule}\n"; |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
else { |
608
|
72
|
|
|
|
|
318
|
"( $_->{code} ) # $_->{rule}\n"; |
609
|
|
|
|
|
|
|
} |
610
|
55
|
|
|
|
|
90
|
} @{ $self->{rules} }; |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
#warn $code; |
613
|
55
|
|
|
|
|
213
|
return $code; |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=item C<start( @directories )> |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Starts a find across the specified directories. Matching items may |
619
|
|
|
|
|
|
|
then be queried using L</match>. This allows you to use a rule as an |
620
|
|
|
|
|
|
|
iterator. |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
my $rule = File::Find::Rule->file->name("*.jpeg")->start( "/web" ); |
623
|
|
|
|
|
|
|
while ( defined ( my $image = $rule->match ) ) { |
624
|
|
|
|
|
|
|
... |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
=cut |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
sub start { |
630
|
1
|
|
|
1
|
1
|
3
|
my $self = _force_object shift; |
631
|
|
|
|
|
|
|
|
632
|
1
|
|
|
|
|
5
|
$self->{iterator} = [ $self->in( @_ ) ]; |
633
|
1
|
|
|
|
|
5
|
$self; |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
=item C<match> |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
Returns the next file which matches, false if there are no more. |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
=cut |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub match { |
643
|
11
|
|
|
11
|
1
|
84
|
my $self = _force_object shift; |
644
|
|
|
|
|
|
|
|
645
|
11
|
|
|
|
|
15
|
return shift @{ $self->{iterator} }; |
|
11
|
|
|
|
|
102
|
|
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
1; |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
__END__ |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=back |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=head2 Extensions |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
Extension modules are available from CPAN in the File::Find::Rule |
657
|
|
|
|
|
|
|
namespace. In order to use these extensions either use them directly: |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
use File::Find::Rule::ImageSize; |
660
|
|
|
|
|
|
|
use File::Find::Rule::MMagic; |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# now your rules can use the clauses supplied by the ImageSize and |
663
|
|
|
|
|
|
|
# MMagic extension |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
or, specify that File::Find::Rule should load them for you: |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
use File::Find::Rule qw( :ImageSize :MMagic ); |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
For notes on implementing your own extensions, consult |
670
|
|
|
|
|
|
|
L<File::Find::Rule::Extending> |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=head2 Further examples |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=over |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=item Finding perl scripts |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
my $finder = File::Find::Rule->or |
679
|
|
|
|
|
|
|
( |
680
|
|
|
|
|
|
|
File::Find::Rule->name( '*.pl' ), |
681
|
|
|
|
|
|
|
File::Find::Rule->exec( |
682
|
|
|
|
|
|
|
sub { |
683
|
|
|
|
|
|
|
if (open my $fh, $_) { |
684
|
|
|
|
|
|
|
my $shebang = <$fh>; |
685
|
|
|
|
|
|
|
close $fh; |
686
|
|
|
|
|
|
|
return $shebang =~ /^#!.*\bperl/; |
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
return 0; |
689
|
|
|
|
|
|
|
} ), |
690
|
|
|
|
|
|
|
); |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
Based upon this message http://use.perl.org/comments.pl?sid=7052&cid=10842 |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=item ignore CVS directories |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
my $rule = File::Find::Rule->new; |
697
|
|
|
|
|
|
|
$rule->or($rule->new |
698
|
|
|
|
|
|
|
->directory |
699
|
|
|
|
|
|
|
->name('CVS') |
700
|
|
|
|
|
|
|
->prune |
701
|
|
|
|
|
|
|
->discard, |
702
|
|
|
|
|
|
|
$rule->new); |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
Note here the use of a null rule. Null rules match anything they see, |
705
|
|
|
|
|
|
|
so the effect is to match (and discard) directories called 'CVS' or to |
706
|
|
|
|
|
|
|
match anything. |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=back |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=head1 TWO FOR THE PRICE OF ONE |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
File::Find::Rule also gives you a procedural interface. This is |
713
|
|
|
|
|
|
|
documented in L<File::Find::Rule::Procedural> |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
=head1 EXPORTS |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
L</find>, L</rule> |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=head1 TAINT MODE INTERACTION |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
As of 0.32 File::Find::Rule doesn't capture the current working directory in |
722
|
|
|
|
|
|
|
a taint-unsafe manner. File::Find itself still does operations that the taint |
723
|
|
|
|
|
|
|
system will flag as insecure but you can use the L</extras> feature to ask |
724
|
|
|
|
|
|
|
L<File::Find> to internally C<untaint> file paths with a regex like so: |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
my $rule = File::Find::Rule->extras({ untaint => 1 }); |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
Please consult L<File::Find>'s documentation for C<untaint>, |
729
|
|
|
|
|
|
|
C<untaint_pattern>, and C<untaint_skip> for more information. |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=head1 BUGS |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
The code makes use of the C<our> keyword and as such requires perl version |
734
|
|
|
|
|
|
|
5.6.0 or newer. |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
Currently it isn't possible to remove a clause from a rule object. If |
737
|
|
|
|
|
|
|
this becomes a significant issue it will be addressed. |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=head1 AUTHOR |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
Richard Clamp <richardc@unixbeard.net> with input gained from this |
742
|
|
|
|
|
|
|
use.perl discussion: http://use.perl.org/~richardc/journal/6467 |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
Additional proofreading and input provided by Kake, Greg McCarroll, |
745
|
|
|
|
|
|
|
and Andy Lester andy@petdance.com. |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
=head1 COPYRIGHT |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
Copyright (C) 2002, 2003, 2004, 2006, 2009, 2011 Richard Clamp. All Rights Reserved. |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it |
752
|
|
|
|
|
|
|
under the same terms as Perl itself. |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
=head1 SEE ALSO |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
L<File::Find>, L<Text::Glob>, L<Number::Compare>, find(1) |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
If you want to know about the procedural interface, see |
759
|
|
|
|
|
|
|
L<File::Find::Rule::Procedural>, and if you have an idea for a neat |
760
|
|
|
|
|
|
|
extension L<File::Find::Rule::Extending> |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=cut |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
Implementation notes: |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
$self->rules is an array of hashrefs. it may be a code fragment or a call |
767
|
|
|
|
|
|
|
to a subroutine. |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
Anonymous subroutines are stored in the $self->subs hashref keyed on the |
770
|
|
|
|
|
|
|
stringfied version of the coderef. |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
When one File::Find::Rule object is combined with another, such as in the any |
773
|
|
|
|
|
|
|
and not operations, this entire hash is merged. |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
The _compile method walks the rules element and simply glues the code |
776
|
|
|
|
|
|
|
fragments together so they can be compiled into an anyonymous File::Find |
777
|
|
|
|
|
|
|
match sub for speed |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
[*] There's probably a win to be made with the current model in making |
781
|
|
|
|
|
|
|
stat calls use C<_>. For |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
find( file => size => "> 20M" => size => "< 400M" ); |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
up to 3 stats will happen for each candidate. Adding a priming _ |
786
|
|
|
|
|
|
|
would be a bit blind if the first operation was C< name => 'foo' >, |
787
|
|
|
|
|
|
|
since that can be tested by a single regex. Simply checking what the |
788
|
|
|
|
|
|
|
next type of operation doesn't work since any arbritary exec sub may |
789
|
|
|
|
|
|
|
or may not stat. Potentially worse, they could stat something else |
790
|
|
|
|
|
|
|
like so: |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
# extract from the worlds stupidest make(1) |
793
|
|
|
|
|
|
|
find( exec => sub { my $f = $_; $f =~ s/\.c$/.o/ && !-e $f } ); |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
Maybe the best way is to treat C<_> as invalid after calling an exec, |
796
|
|
|
|
|
|
|
and doc that C<_> will only be meaningful after stat and -X tests if |
797
|
|
|
|
|
|
|
they're wanted in exec blocks. |