rbfind 1.8 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/LICENSE +1 -1
- data/bin/rbfind +413 -408
- data/lib/rbfind.rb +573 -718
- data/lib/rbfind/core.rb +82 -0
- data/lib/rbfind/csv.rb +54 -0
- data/lib/{humansiz.rb → rbfind/humansiz.rb} +30 -9
- data/lib/rbfind/table.rb +114 -0
- metadata +11 -9
data/lib/rbfind.rb
CHANGED
|
@@ -2,42 +2,13 @@
|
|
|
2
2
|
# rbfind.rb -- Find replacement with many features
|
|
3
3
|
#
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class String ; def ord ; self[0].ord ; end ; end
|
|
8
|
-
end
|
|
9
|
-
# :startdoc:
|
|
10
|
-
|
|
11
|
-
class Dir
|
|
12
|
-
|
|
13
|
-
SPECIAL_DIRS = %w(. ..)
|
|
14
|
-
CUR_DIR, SUPER_DIR = *SPECIAL_DIRS
|
|
15
|
-
|
|
16
|
-
# :call-seq:
|
|
17
|
-
# each!() { |e| ... } -> self
|
|
18
|
-
#
|
|
19
|
-
# Call block for all entries except "." and "..".
|
|
20
|
-
#
|
|
21
|
-
def each!
|
|
22
|
-
s = SPECIAL_DIRS.dup
|
|
23
|
-
each { |f|
|
|
24
|
-
next if s.delete f
|
|
25
|
-
yield f
|
|
26
|
-
}
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# :call-seq:
|
|
30
|
-
# entries!() -> ary
|
|
31
|
-
#
|
|
32
|
-
# All entries except "." and "..".
|
|
33
|
-
#
|
|
34
|
-
method_defined? :entries! or def entries!
|
|
35
|
-
entries - SPECIAL_DIRS
|
|
36
|
-
end
|
|
5
|
+
require "rbfind/core"
|
|
6
|
+
require "rbfind/csv"
|
|
37
7
|
|
|
38
|
-
end
|
|
39
8
|
|
|
9
|
+
module RbFind
|
|
40
10
|
|
|
11
|
+
VERSION = "2.0.2".freeze
|
|
41
12
|
|
|
42
13
|
=begin rdoc
|
|
43
14
|
|
|
@@ -48,130 +19,130 @@ tool.
|
|
|
48
19
|
|
|
49
20
|
In Ruby programs, you may call:
|
|
50
21
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# more terse
|
|
58
|
-
RbFind.run do puts path end
|
|
59
|
-
RbFind.run "dir" do puts path end
|
|
22
|
+
RbFind.run do puts path end
|
|
23
|
+
RbFind.run "dir" do puts path end
|
|
24
|
+
RbFind.run "dir1", "dir2" do puts path end
|
|
25
|
+
RbFind.run %w(dir1 dir2) do puts path end
|
|
26
|
+
RbFind.run "dir", :max_depth => 3 do puts path end
|
|
60
27
|
|
|
61
28
|
|
|
62
29
|
== File properties
|
|
63
30
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
f.readlink # symlink pointer or nil (*)
|
|
90
|
-
f.broken_link? # what you expect
|
|
91
|
-
f.arrow # ls-style "-> symlink" suffix (*)
|
|
31
|
+
name # file name (*)
|
|
32
|
+
path # file path relative to working directory (*)
|
|
33
|
+
fullpath # full file path (*)
|
|
34
|
+
path! # directories with a slash appended (*)
|
|
35
|
+
fullpath! # directories with a slash appended (*)
|
|
36
|
+
dirname # dirname of path
|
|
37
|
+
ext # file name extension
|
|
38
|
+
without_ext # file name without extension
|
|
39
|
+
depth # step depth
|
|
40
|
+
hidden? # filename starting with "." (No Windows version, yet.)
|
|
41
|
+
visible? # not hidden?
|
|
42
|
+
stat # file status information (File::Stat object)
|
|
43
|
+
mode # access mode (like 0755, 0644)
|
|
44
|
+
mtime # modify time (atime, ctime as well)
|
|
45
|
+
mage # age in seconds since walk started
|
|
46
|
+
age # alias for mage
|
|
47
|
+
user # owner
|
|
48
|
+
owner # dto. (alias)
|
|
49
|
+
group # group owner
|
|
50
|
+
user! # owner, "." if process owner
|
|
51
|
+
owner! # dto. (alias)
|
|
52
|
+
group! # group owner, "." if process owner
|
|
53
|
+
readlink # symlink pointer or nil (*)
|
|
54
|
+
broken_link? # what you expect
|
|
55
|
+
arrow # ls-style "-> symlink" suffix (*)
|
|
92
56
|
|
|
93
57
|
# (*) = colored version available (see below)
|
|
94
58
|
|
|
95
|
-
|
|
96
|
-
|
|
59
|
+
empty? # directory is empty
|
|
60
|
+
entries # directory entries
|
|
97
61
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
62
|
+
open { |o| ... } # open file
|
|
63
|
+
read n = nil # read first n bytes, nil reads to eof
|
|
64
|
+
lines { |l,i| ... } # open file and yield each |line,lineno|
|
|
65
|
+
grep re # lines with `l =~ re and colsep path, i, l'
|
|
66
|
+
binary? n = 1 # test whether first n blocks contain null characters
|
|
67
|
+
bin? # alias for binary?
|
|
104
68
|
|
|
105
|
-
|
|
69
|
+
vimswap? # it is a Vim swapfile
|
|
106
70
|
|
|
107
71
|
Further will be redirected to the stat object (selective):
|
|
108
72
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
73
|
+
directory?
|
|
74
|
+
executable?
|
|
75
|
+
file?
|
|
76
|
+
pipe?
|
|
77
|
+
socket?
|
|
78
|
+
symlink?
|
|
115
79
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
80
|
+
readable?
|
|
81
|
+
writable?
|
|
82
|
+
size
|
|
83
|
+
zero?
|
|
120
84
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
85
|
+
uid
|
|
86
|
+
gid
|
|
87
|
+
owned?
|
|
88
|
+
grpowned?
|
|
125
89
|
|
|
126
|
-
|
|
90
|
+
dir? # alias for directory?
|
|
127
91
|
|
|
128
92
|
Derivated from stat:
|
|
129
93
|
|
|
130
|
-
|
|
131
|
-
|
|
94
|
+
stype # one-letter (short) version of ftype
|
|
95
|
+
modes # rwxr-xr-x style modes
|
|
132
96
|
|
|
133
|
-
|
|
134
|
-
|
|
97
|
+
filesize # returns size for files, else nil
|
|
98
|
+
filesize { |s| s > 1024 } # returns block result for files
|
|
135
99
|
|
|
136
100
|
|
|
137
101
|
== Actions
|
|
138
102
|
|
|
139
|
-
|
|
140
|
-
|
|
103
|
+
done # exit from current entry
|
|
104
|
+
done! # dto.
|
|
105
|
+
prune # do not descend directory; abort current entry
|
|
106
|
+
prune! # dto.
|
|
107
|
+
no_vcs # omit .svn, CVS and .git directories
|
|
108
|
+
novcs # dto.
|
|
141
109
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
110
|
+
colsep path, ... # output parameters in a line separated by colons
|
|
111
|
+
col_sep # dto. (alias)
|
|
112
|
+
tabsep path, ... # separate by tabs
|
|
113
|
+
tab_sep #
|
|
114
|
+
spcsep path, ... # separate by spaces
|
|
115
|
+
spc_sep #
|
|
116
|
+
spacesep path, ... #
|
|
117
|
+
space_sep #
|
|
118
|
+
p # alias for space_sep
|
|
119
|
+
csv sep, path, ... # separate by user-defined separator
|
|
151
120
|
|
|
152
|
-
|
|
121
|
+
rename newname # rename, but leave it in the same directory
|
|
153
122
|
|
|
154
123
|
|
|
155
124
|
== Color support
|
|
156
125
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
126
|
+
cname # colorized name
|
|
127
|
+
cpath # colorized path
|
|
128
|
+
cpath! # colorized path!
|
|
129
|
+
cfullpath # colorized fullpath
|
|
130
|
+
cfullpath! # colorized fullpath!
|
|
131
|
+
creadlink # colored symlink pointer
|
|
132
|
+
carrow # colored "-> symlink" suffix
|
|
164
133
|
|
|
165
|
-
|
|
166
|
-
|
|
134
|
+
color arg # colorize argument
|
|
135
|
+
colour arg # alias
|
|
167
136
|
|
|
168
137
|
RbFind.colors str # define colors
|
|
169
138
|
RbFind.colours str # alias
|
|
170
139
|
|
|
171
140
|
Default color setup is "xxHbexfxcxdxbxegedabagacadAx".
|
|
172
|
-
In case you did not call RbFind.colors, the environment variables
|
|
141
|
+
In case you did not call RbFind::Walk.colors, the environment variables
|
|
173
142
|
RBFIND_COLORS and RBFIND_COLOURS are looked up. If neither is given
|
|
174
143
|
but LSCOLORS is set, the fields 2-13 default to that.
|
|
144
|
+
A Gnu LS_COLOR-style string may also be given, though glob patterns will
|
|
145
|
+
not be unregarded. If LS_COLORS is set, the colors default to that.
|
|
175
146
|
|
|
176
147
|
The letters mean:
|
|
177
148
|
a = black, b = red, c = green, d = brown, e = blue,
|
|
@@ -197,7 +168,7 @@ Derivated from stat:
|
|
|
197
168
|
13 whiteout
|
|
198
169
|
14 unknown
|
|
199
170
|
|
|
200
|
-
|
|
171
|
+
suffix # ls-like suffixes |@=/%* for pipe, ..., executable
|
|
201
172
|
|
|
202
173
|
|
|
203
174
|
== Encoding issues
|
|
@@ -205,12 +176,12 @@ Derivated from stat:
|
|
|
205
176
|
Ruby raises an ArgumentError if, for example, an ISO8859-1-encoded
|
|
206
177
|
string gets read in as UTF-8-encoded and then is matched against a
|
|
207
178
|
UTF-8-encoded regular expression. This will happen if you are
|
|
208
|
-
running RbFind from an environment with something like
|
|
209
|
-
|
|
179
|
+
running RbFind::Walk from an environment with something like
|
|
180
|
+
LANG="de_DE.UTF-8" and if you are searching directories containing
|
|
210
181
|
single-byte encoded file names or files with single-byte or binary
|
|
211
182
|
content.
|
|
212
183
|
|
|
213
|
-
The #grep facility will
|
|
184
|
+
The #grep facility will condone encoding mismatches by calling
|
|
214
185
|
the String#scrub! method. But neither the #lines and #read function
|
|
215
186
|
will do any transformation nor will the file names and the path
|
|
216
187
|
specifications be changed.
|
|
@@ -227,728 +198,612 @@ variables because these will be used in the further processing.
|
|
|
227
198
|
|
|
228
199
|
Find them all:
|
|
229
200
|
|
|
230
|
-
RbFind.
|
|
201
|
+
RbFind.run do puts path end
|
|
231
202
|
|
|
232
203
|
Omit version control:
|
|
233
204
|
|
|
234
|
-
RbFind.
|
|
235
|
-
|
|
236
|
-
puts
|
|
205
|
+
RbFind.run "myproject" do
|
|
206
|
+
prune if name == ".svn"
|
|
207
|
+
puts path
|
|
237
208
|
end
|
|
238
209
|
|
|
239
210
|
# or even
|
|
240
|
-
RbFind.
|
|
241
|
-
|
|
242
|
-
puts
|
|
211
|
+
RbFind.run "myproject" do
|
|
212
|
+
novcs
|
|
213
|
+
puts path
|
|
243
214
|
end
|
|
244
215
|
|
|
245
216
|
Mention directory contents before directory itself:
|
|
246
217
|
|
|
247
|
-
RbFind.
|
|
248
|
-
puts
|
|
218
|
+
RbFind.run "myproject", depth_first: true do
|
|
219
|
+
puts path
|
|
249
220
|
end
|
|
250
221
|
|
|
251
222
|
Limit search depth:
|
|
252
223
|
|
|
253
|
-
RbFind.
|
|
254
|
-
puts
|
|
224
|
+
RbFind.run max_depth: 2 do
|
|
225
|
+
puts path
|
|
255
226
|
end
|
|
256
227
|
|
|
257
228
|
Unsorted (alphabetical sort is default):
|
|
258
229
|
|
|
259
|
-
RbFind.
|
|
260
|
-
puts
|
|
230
|
+
RbFind.run sort: false do
|
|
231
|
+
puts path
|
|
261
232
|
end
|
|
262
233
|
|
|
263
234
|
Reverse sort:
|
|
264
235
|
|
|
265
|
-
RbFind.
|
|
266
|
-
puts
|
|
236
|
+
RbFind.run sort: true, reverse: true do
|
|
237
|
+
puts path
|
|
267
238
|
end
|
|
268
239
|
|
|
269
240
|
Sort without case sensitivity and preceding dot:
|
|
270
241
|
|
|
271
242
|
s = proc { |x| x =~ /^\.?/ ; $'.downcase }
|
|
272
|
-
RbFind.
|
|
273
|
-
puts
|
|
243
|
+
RbFind.run sort: s do
|
|
244
|
+
puts path
|
|
274
245
|
end
|
|
275
246
|
|
|
276
247
|
=end
|
|
277
248
|
|
|
278
|
-
class RbFind
|
|
279
249
|
|
|
280
|
-
|
|
250
|
+
class Done < Exception ; end
|
|
251
|
+
class Prune < Exception ; end
|
|
281
252
|
|
|
282
253
|
class <<self
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
params = case args.last
|
|
286
|
-
when Hash then args.pop
|
|
287
|
-
end
|
|
288
|
-
args.flatten!
|
|
289
|
-
if args.any? then
|
|
290
|
-
count = 0
|
|
291
|
-
args.each do |path|
|
|
292
|
-
f = new path, count, params, &block
|
|
293
|
-
count = f.count
|
|
294
|
-
end
|
|
295
|
-
else
|
|
296
|
-
f = new nil, 0, params, &block
|
|
297
|
-
f.count
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
def run *args, &block
|
|
301
|
-
open *args do |f| f.instance_eval &block end
|
|
254
|
+
def run *args, **params, &block
|
|
255
|
+
Walk.run *args, **params, &block
|
|
302
256
|
end
|
|
303
257
|
end
|
|
304
258
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
dl = :do_level_depth if params.delete :depth
|
|
314
|
-
md = params.delete :max_depth ; @max_depth = md.to_i if md
|
|
315
|
-
st = params.delete :sort ; @sort = sort_parser st
|
|
316
|
-
@follow = params.delete :follow
|
|
317
|
-
@error = params.delete :error
|
|
318
|
-
params.empty? or
|
|
319
|
-
raise RuntimeError, "Unknown parameter(s): #{params.keys.join ','}."
|
|
320
|
-
end
|
|
321
|
-
@do_level = method dl||:do_level
|
|
322
|
-
|
|
323
|
-
@start, @count = Time.now, count
|
|
324
|
-
@wd = Dir.getwd
|
|
325
|
-
if path then
|
|
326
|
-
@max_depth += 1 if @max_depth
|
|
327
|
-
File.lstat path
|
|
328
|
-
@wd = nil unless absolute_path? path
|
|
329
|
-
@levels.push path
|
|
330
|
-
walk
|
|
331
|
-
else
|
|
332
|
-
build_path
|
|
333
|
-
scan_dir
|
|
259
|
+
class Walk
|
|
260
|
+
|
|
261
|
+
class <<self
|
|
262
|
+
def run *args, **params, &block
|
|
263
|
+
i = new **params, &block
|
|
264
|
+
i.run *args
|
|
265
|
+
i.count
|
|
266
|
+
end
|
|
334
267
|
end
|
|
335
|
-
end
|
|
336
268
|
|
|
337
|
-
|
|
269
|
+
private
|
|
338
270
|
|
|
339
|
-
|
|
271
|
+
def initialize max_depth: nil, depth_first: nil, follow: nil,
|
|
272
|
+
sort: true, reverse: false, error: nil, &block
|
|
273
|
+
@max_depth = max_depth
|
|
274
|
+
@depth_first = depth_first
|
|
275
|
+
@follow = follow
|
|
276
|
+
@sort = sort_parser sort, reverse
|
|
277
|
+
@error = error
|
|
278
|
+
@block = block
|
|
340
279
|
|
|
341
|
-
|
|
280
|
+
ostat = $stdout.stat
|
|
281
|
+
@ostat = ostat if ostat.file?
|
|
342
282
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def fullpath ; @fullpath ; end
|
|
346
|
-
def path! ; append_slash @path ; end
|
|
347
|
-
def fullpath! ; append_slash @fullpath ; end
|
|
283
|
+
@wd, @start, @count = Dir.getwd, Time.now, 0
|
|
284
|
+
end
|
|
348
285
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
286
|
+
def sort_parser st, rev
|
|
287
|
+
r = case st
|
|
288
|
+
when Proc then proc { |l| l.sort_by! &st }
|
|
289
|
+
when nil, false, nil, "" then proc { }
|
|
290
|
+
else proc { |l| l.sort! }
|
|
291
|
+
end
|
|
292
|
+
rev ? proc { |l| r.call l ; l.reverse! } : r
|
|
293
|
+
end
|
|
353
294
|
|
|
354
|
-
|
|
355
|
-
def without_ext ; name[ /^(.+?)(?:\.[^.]+)?$/, 1 ].to_s ; end
|
|
295
|
+
public
|
|
356
296
|
|
|
357
|
-
|
|
297
|
+
attr_reader :wd, :start, :count, :depth
|
|
358
298
|
|
|
359
|
-
|
|
360
|
-
|
|
299
|
+
def run *args
|
|
300
|
+
@levels, @depth = [], 0
|
|
301
|
+
args.flatten!
|
|
302
|
+
args.compact!
|
|
303
|
+
if args.empty? then
|
|
304
|
+
visit_dir Dir::CUR_DIR
|
|
305
|
+
else
|
|
306
|
+
args.each { |base|
|
|
307
|
+
handle_error do
|
|
308
|
+
File.exists? base or raise "`#{base}` doesn't exist."
|
|
309
|
+
visit_depth base
|
|
310
|
+
end
|
|
311
|
+
}
|
|
312
|
+
end
|
|
313
|
+
ensure
|
|
314
|
+
@levels = @depth = nil
|
|
315
|
+
end
|
|
361
316
|
|
|
362
|
-
|
|
363
|
-
def mode ; stat.mode ; end
|
|
317
|
+
private
|
|
364
318
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
319
|
+
def join_path
|
|
320
|
+
(File.join @levels).freeze
|
|
321
|
+
end
|
|
368
322
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
323
|
+
def visit filename
|
|
324
|
+
@depth += 1
|
|
325
|
+
visit_depth filename
|
|
326
|
+
ensure
|
|
327
|
+
@depth -= 1
|
|
374
328
|
end
|
|
375
|
-
end
|
|
376
329
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
330
|
+
def visit_depth filename
|
|
331
|
+
@levels.push filename.dup.freeze
|
|
332
|
+
p_, @path = @path, join_path
|
|
333
|
+
if @depth_first then
|
|
334
|
+
enter_dir
|
|
335
|
+
call_block or raise "#{self.class}: prune doesn't work with :depth_first."
|
|
336
|
+
else
|
|
337
|
+
call_block and enter_dir
|
|
338
|
+
end
|
|
339
|
+
@count += 1
|
|
340
|
+
ensure
|
|
341
|
+
@path = p_
|
|
342
|
+
@levels.pop
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def enter_dir
|
|
346
|
+
return unless File.directory? @path
|
|
347
|
+
if File.symlink? @path then
|
|
348
|
+
return unless @follow and handle_error do
|
|
349
|
+
d = @path.dup
|
|
350
|
+
while d != Dir::CUR_DIR do
|
|
351
|
+
d, = File.split d
|
|
352
|
+
raise "cyclic recursion in #@path" if File.identical? d, @path
|
|
353
|
+
end
|
|
354
|
+
true
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
handle_error do
|
|
358
|
+
visit_dir @path
|
|
359
|
+
end
|
|
360
|
+
end
|
|
384
361
|
|
|
385
|
-
|
|
362
|
+
def visit_dir dir
|
|
363
|
+
return if @max_depth and @max_depth == @depth
|
|
364
|
+
list = (Dir.new dir).children
|
|
365
|
+
@sort.call list
|
|
366
|
+
list.each { |f| visit f }
|
|
367
|
+
ensure
|
|
368
|
+
end
|
|
386
369
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
370
|
+
def call_block
|
|
371
|
+
e = Entry.new @levels.last, @path, self
|
|
372
|
+
handle_error do
|
|
373
|
+
$_, $. = e.name, count
|
|
374
|
+
begin
|
|
375
|
+
e.instance_eval &@block
|
|
376
|
+
rescue Done
|
|
377
|
+
ensure
|
|
378
|
+
if !(e.name.equal? @levels.last) && e.name != @levels.last then
|
|
379
|
+
p = @path
|
|
380
|
+
e.name == (File.basename e.name) or
|
|
381
|
+
raise "#{self.class}: rename to `#{e.name}' may not be a path."
|
|
382
|
+
e.name.freeze
|
|
383
|
+
@levels.pop
|
|
384
|
+
@levels.push e.name
|
|
385
|
+
@path = join_path
|
|
386
|
+
File.rename p, @path
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
true
|
|
390
|
+
end
|
|
391
|
+
rescue Prune
|
|
392
|
+
end
|
|
390
393
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
394
|
+
def handle_error
|
|
395
|
+
yield
|
|
396
|
+
rescue
|
|
397
|
+
case @error
|
|
398
|
+
when Proc then @error.call
|
|
399
|
+
when String then instance_eval @error
|
|
400
|
+
else raise
|
|
401
|
+
end
|
|
402
|
+
nil
|
|
403
|
+
end
|
|
395
404
|
|
|
396
|
-
def now ; @start ; end
|
|
397
|
-
def age ; @start - stat.mtime ; end
|
|
398
|
-
alias age_secs age
|
|
399
|
-
alias age_s age_secs
|
|
400
|
-
|
|
401
|
-
# :stopdoc:
|
|
402
|
-
MINUTE = 60
|
|
403
|
-
HOUR = 60*MINUTE
|
|
404
|
-
DAY = 24*HOUR
|
|
405
|
-
# :startdoc:
|
|
406
|
-
|
|
407
|
-
def age_mins ; age / MINUTE ; end
|
|
408
|
-
alias age_m age_mins
|
|
409
|
-
def age_hours ; age / HOUR ; end
|
|
410
|
-
alias age_h age_hours
|
|
411
|
-
def age_days ; age / DAY ; end
|
|
412
|
-
alias age_d age_days
|
|
413
|
-
|
|
414
|
-
private
|
|
415
|
-
|
|
416
|
-
def method_missing sym, *args, &block
|
|
417
|
-
stat.send sym, *args, &block
|
|
418
|
-
rescue NoMethodError
|
|
419
|
-
super
|
|
420
405
|
end
|
|
421
406
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
def stype
|
|
430
|
-
m = stat.mode >> 12 rescue nil
|
|
431
|
-
case m
|
|
432
|
-
when 001 then "p"
|
|
433
|
-
when 002 then "c"
|
|
434
|
-
when 004 then "d"
|
|
435
|
-
when 006 then "b"
|
|
436
|
-
when 010 then "-"
|
|
437
|
-
when 012 then "l"
|
|
438
|
-
when 014 then "s"
|
|
439
|
-
when 016 then "w"
|
|
440
|
-
when nil then "#"
|
|
441
|
-
else "?"
|
|
407
|
+
|
|
408
|
+
class Entry
|
|
409
|
+
|
|
410
|
+
attr_reader :path, :name
|
|
411
|
+
|
|
412
|
+
def initialize name, path, walk
|
|
413
|
+
@name, @path, @walk = name, path, walk
|
|
442
414
|
end
|
|
443
|
-
end
|
|
444
415
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
m >>= 3
|
|
454
|
-
r.insert 0, ((h & 01).nonzero? ? "x" : "-")
|
|
455
|
-
r.insert 0, ((h & 02).nonzero? ? "w" : "-")
|
|
456
|
-
r.insert 0, ((h & 04).nonzero? ? "r" : "-")
|
|
457
|
-
}
|
|
458
|
-
if (m & 04).nonzero? then
|
|
459
|
-
r[ 2] = r[ 2, 1] == "x" ? "s" : "S"
|
|
460
|
-
end
|
|
461
|
-
if (m & 02).nonzero? then
|
|
462
|
-
r[ 5] = r[ 5, 1] == "x" ? "s" : "S"
|
|
463
|
-
end
|
|
464
|
-
if (m & 01).nonzero? then
|
|
465
|
-
r[ 8] = r[ 8, 1] == "x" ? "t" : "T"
|
|
466
|
-
end
|
|
467
|
-
r
|
|
468
|
-
end
|
|
416
|
+
def depth ; @walk.depth ; end
|
|
417
|
+
def now ; @walk.start ; end
|
|
418
|
+
|
|
419
|
+
def fullpath ; @fullpath ||= File.absolute_path @path, @walk.wd ; end
|
|
420
|
+
|
|
421
|
+
def stat ; @stat ||= File.lstat @path ; end
|
|
422
|
+
def rstat ; @rstat ||= File.stat @path ; end
|
|
423
|
+
|
|
469
424
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
yield stat.size if file?
|
|
480
|
-
else
|
|
481
|
-
stat.size if file?
|
|
425
|
+
private
|
|
426
|
+
def append_slash s ; (File.directory? s) ? (File.join s, "") : s ; end
|
|
427
|
+
public
|
|
428
|
+
|
|
429
|
+
def path! ; append_slash path ; end
|
|
430
|
+
def fullpath! ; append_slash fullpath ; end
|
|
431
|
+
|
|
432
|
+
def dirname
|
|
433
|
+
File.basename File.dirname fullpath
|
|
482
434
|
end
|
|
483
|
-
end
|
|
484
435
|
|
|
485
436
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
def cfullpath ; color fullpath ; end
|
|
489
|
-
def cpath! ; color path! ; end
|
|
490
|
-
def cfullpath! ; color fullpath! ; end
|
|
437
|
+
def ext ; File.extname name ; end
|
|
438
|
+
def without_ext ; name[ /^(.+?)(?:\.[^.]+)?$/, 1 ].to_s ; end
|
|
491
439
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
end
|
|
495
|
-
alias colour color
|
|
440
|
+
def hidden? ; name =~ /^\./ ; end
|
|
441
|
+
def visible? ; not hidden? ; end
|
|
496
442
|
|
|
497
|
-
DEFAULT_COLORS = "xxHbexfxcxdxbxegedabagacadAx"
|
|
498
443
|
|
|
499
|
-
|
|
444
|
+
def mode ; stat.mode ; end
|
|
500
445
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
when 0..7 then a.push 30 + fg
|
|
508
|
-
end
|
|
509
|
-
a.push 1 if $1 == $1.upcase
|
|
510
|
-
case bg
|
|
511
|
-
when 0..7 then a.push 40 + bg
|
|
512
|
-
end
|
|
513
|
-
e = a.join ";"
|
|
514
|
-
@cols.push e
|
|
446
|
+
private
|
|
447
|
+
def method_missing sym, *args, &block
|
|
448
|
+
if stat.respond_to? sym then
|
|
449
|
+
stat.send sym, *args, &block
|
|
450
|
+
else
|
|
451
|
+
super
|
|
515
452
|
end
|
|
516
453
|
end
|
|
517
|
-
|
|
454
|
+
public
|
|
455
|
+
|
|
456
|
+
def dir? ; stat.directory? ; end
|
|
518
457
|
|
|
519
|
-
def
|
|
520
|
-
|
|
521
|
-
|
|
458
|
+
def aage ; @walk.start - stat.atime ; end
|
|
459
|
+
def mage ; @walk.start - stat.mtime ; end
|
|
460
|
+
def cage ; @walk.start - stat.ctime ; end
|
|
461
|
+
alias age mage
|
|
462
|
+
|
|
463
|
+
# :call-seq:
|
|
464
|
+
# filesize => nil or int
|
|
465
|
+
# filesize { |size| ... } => obj
|
|
466
|
+
#
|
|
467
|
+
# Returns the files size. When the object is not a regular file,
|
|
468
|
+
# nil will be returned or the block will not be called.
|
|
469
|
+
#
|
|
470
|
+
def filesize
|
|
471
|
+
stat.file? or return
|
|
472
|
+
if block_given? then
|
|
473
|
+
yield stat.size
|
|
474
|
+
else
|
|
475
|
+
stat.size
|
|
476
|
+
end
|
|
522
477
|
end
|
|
523
|
-
alias coloured colored
|
|
524
478
|
|
|
525
479
|
private
|
|
480
|
+
def etc
|
|
481
|
+
Etc
|
|
482
|
+
rescue NameError
|
|
483
|
+
require "etc" and retry
|
|
484
|
+
raise
|
|
485
|
+
end
|
|
486
|
+
def get_user u ; (etc.getpwuid u).name rescue u.to_s ; end
|
|
487
|
+
def get_group g ; (etc.getgrgid g).name rescue g.to_s ; end
|
|
488
|
+
public
|
|
526
489
|
|
|
527
|
-
def
|
|
528
|
-
|
|
529
|
-
env = DEFAULT_COLORS.dup
|
|
530
|
-
els = ENV[ "LSCOLORS"]
|
|
531
|
-
if els then
|
|
532
|
-
env[ 2*2, els.length] = els
|
|
533
|
-
end
|
|
534
|
-
env
|
|
535
|
-
)
|
|
490
|
+
def user
|
|
491
|
+
get_user stat.uid
|
|
536
492
|
end
|
|
493
|
+
alias owner user
|
|
537
494
|
|
|
538
|
-
|
|
495
|
+
def user!
|
|
496
|
+
u = stat.uid
|
|
497
|
+
u == Process.uid ? "." : (get_user u)
|
|
498
|
+
end
|
|
499
|
+
alias owner! user!
|
|
539
500
|
|
|
501
|
+
def group
|
|
502
|
+
get_group stat.gid
|
|
503
|
+
end
|
|
540
504
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
def suffix
|
|
545
|
-
m = stat.mode >> 12 rescue nil
|
|
546
|
-
case m
|
|
547
|
-
when 001 then "|"
|
|
548
|
-
when 002 then " "
|
|
549
|
-
when 004 then "/"
|
|
550
|
-
when 006 then " "
|
|
551
|
-
when 010 then stat.executable? ? "*" : " "
|
|
552
|
-
when 012 then "@"
|
|
553
|
-
when 014 then "="
|
|
554
|
-
when 016 then "%"
|
|
555
|
-
else "?"
|
|
505
|
+
def group!
|
|
506
|
+
g = stat.gid
|
|
507
|
+
g == Process.gid ? "." : (get_group g)
|
|
556
508
|
end
|
|
557
|
-
end
|
|
558
509
|
|
|
559
|
-
autoload :Etc, "etc"
|
|
560
510
|
|
|
561
|
-
|
|
562
|
-
# user() -> str
|
|
563
|
-
#
|
|
564
|
-
# Return user name or uid as string if unavailable.
|
|
565
|
-
#
|
|
566
|
-
def user
|
|
567
|
-
u = stat.uid
|
|
568
|
-
(Etc.getpwuid u).name rescue u.to_s
|
|
569
|
-
end
|
|
570
|
-
alias owner user
|
|
571
|
-
|
|
572
|
-
# :call-seq:
|
|
573
|
-
# group() -> str
|
|
574
|
-
#
|
|
575
|
-
# Return group name or gid as string if unavailable.
|
|
576
|
-
#
|
|
577
|
-
def group
|
|
578
|
-
g = stat.gid
|
|
579
|
-
(Etc.getgrgid g).name rescue g.to_s
|
|
580
|
-
end
|
|
511
|
+
def readlink ; File.readlink @path if stat.symlink? ; end
|
|
581
512
|
|
|
513
|
+
def broken_link?
|
|
514
|
+
return if stat.symlink?
|
|
515
|
+
rstat
|
|
516
|
+
false
|
|
517
|
+
rescue
|
|
518
|
+
true
|
|
519
|
+
end
|
|
582
520
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
# +nil+ is returned.
|
|
588
|
-
#
|
|
589
|
-
def empty?
|
|
590
|
-
read_dir.each! { |f| return false }
|
|
591
|
-
true
|
|
592
|
-
rescue Errno::ENOTDIR
|
|
593
|
-
end
|
|
521
|
+
ARROW = " -> "
|
|
522
|
+
def arrow
|
|
523
|
+
ARROW + (File.readlink @path) if stat.symlink?
|
|
524
|
+
end
|
|
594
525
|
|
|
595
|
-
# :call-seq:
|
|
596
|
-
# contains?( name) -> true or false
|
|
597
|
-
#
|
|
598
|
-
# Check whether a directory contains an entry.
|
|
599
|
-
#
|
|
600
|
-
def contains? name
|
|
601
|
-
c = File.join @path, name
|
|
602
|
-
File.exists? c
|
|
603
|
-
end
|
|
604
526
|
|
|
605
|
-
# :call-seq:
|
|
606
|
-
# entires() -> ary
|
|
607
|
-
#
|
|
608
|
-
# Return all entries in an array. If the object is not a directory,
|
|
609
|
-
# +nil+ is returned.
|
|
610
|
-
#
|
|
611
|
-
def entries
|
|
612
|
-
read_dir.entries!
|
|
613
|
-
rescue Errno::ENOTDIR
|
|
614
|
-
end
|
|
615
527
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
528
|
+
# :call-seq:
|
|
529
|
+
# empty?() -> true or false
|
|
530
|
+
#
|
|
531
|
+
# Look up if the directory is empty. If the object is not a directory
|
|
532
|
+
# or not accessible, +nil+ is returned.
|
|
533
|
+
#
|
|
534
|
+
def empty?
|
|
535
|
+
(Dir.new @path).each_child { |f| return false }
|
|
536
|
+
true
|
|
537
|
+
rescue Errno::ENOTDIR
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
# :call-seq:
|
|
541
|
+
# contains?( name) -> true or false
|
|
542
|
+
#
|
|
543
|
+
# Check whether a directory contains an entry.
|
|
544
|
+
#
|
|
545
|
+
def contains? name
|
|
546
|
+
File.exists? File.join @path, name
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# :call-seq:
|
|
550
|
+
# entries() -> ary
|
|
551
|
+
#
|
|
552
|
+
# Return all entries in an array. If the object is not a directory,
|
|
553
|
+
# +nil+ is returned.
|
|
554
|
+
#
|
|
555
|
+
def entries
|
|
556
|
+
(Dir.new @path).children
|
|
557
|
+
rescue Errno::ENOTDIR
|
|
558
|
+
end
|
|
559
|
+
alias children entries
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def vcs?
|
|
563
|
+
%w(CVS .svn .git .hg .fslckout).include? name
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
# :call-seq:
|
|
568
|
+
# open() { |h| ... } -> obj
|
|
569
|
+
#
|
|
570
|
+
# Open the file for reading. If the object is not a regular file,
|
|
571
|
+
# nothing will be done.
|
|
572
|
+
#
|
|
573
|
+
def open &block
|
|
574
|
+
@ostat and @ostat.identical? @path and
|
|
575
|
+
raise "Refusing to open output file."
|
|
624
576
|
File.open @path, &block if file?
|
|
625
577
|
end
|
|
626
|
-
end
|
|
627
578
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
579
|
+
# :call-seq:
|
|
580
|
+
# read( n = nil) -> str or nil
|
|
581
|
+
# read( n = nil) { |b| ... } -> nil
|
|
582
|
+
#
|
|
583
|
+
# Read the first +n+ bytes or return +nil+ for others than regular
|
|
584
|
+
# files. +nil+ reads to end of file. If a block is given, chonks of
|
|
585
|
+
# +n+ bytes (or all) will be yielded.
|
|
586
|
+
#
|
|
587
|
+
def read n = nil
|
|
588
|
+
open { |o|
|
|
589
|
+
if block_given? then
|
|
590
|
+
if n then
|
|
591
|
+
while (r = o.read n) do
|
|
592
|
+
yield r
|
|
593
|
+
end
|
|
594
|
+
else
|
|
595
|
+
yield o.read
|
|
596
|
+
end
|
|
597
|
+
else
|
|
598
|
+
o.read n
|
|
641
599
|
end
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
end
|
|
645
|
-
}
|
|
646
|
-
end
|
|
600
|
+
}
|
|
601
|
+
end
|
|
647
602
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
l
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
603
|
+
# :call-seq:
|
|
604
|
+
# lines { |l,i| ... } -> nil
|
|
605
|
+
#
|
|
606
|
+
# Yield line by line together with the line number <code>i</code>.
|
|
607
|
+
#
|
|
608
|
+
def lines
|
|
609
|
+
block_given? or return lines do end
|
|
610
|
+
r = false
|
|
611
|
+
open { |file|
|
|
612
|
+
n = 0
|
|
613
|
+
file.each_line { |l|
|
|
614
|
+
l.chomp!
|
|
615
|
+
n += 1
|
|
616
|
+
$_, $. = l, n
|
|
617
|
+
r ||= true if yield l, n
|
|
618
|
+
}
|
|
619
|
+
r
|
|
662
620
|
}
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
end
|
|
621
|
+
end
|
|
666
622
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
end
|
|
673
|
-
lines { |l,i|
|
|
674
|
-
l.scrub!
|
|
675
|
-
l =~ re or next
|
|
676
|
-
if color then
|
|
677
|
-
l = "#$`\e[#{color}m#$&\e[m#$'"
|
|
623
|
+
def grep re, color = nil
|
|
624
|
+
case color
|
|
625
|
+
when /\A\d+(?:;\d+)*\z/, nil, false then
|
|
626
|
+
when true then color = "31;1" # red
|
|
627
|
+
else raise "Illegal color spec: #{color}"
|
|
678
628
|
end
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
629
|
+
lines { |l,i|
|
|
630
|
+
l.scrub!
|
|
631
|
+
l =~ re or next
|
|
632
|
+
color and l = "#$`\e[#{color}m#$&\e[m#$'"
|
|
633
|
+
colsep @path, i, l
|
|
634
|
+
true
|
|
635
|
+
}
|
|
636
|
+
end
|
|
682
637
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
638
|
+
# :call-seq:
|
|
639
|
+
# binary?( n = 1) -> true or false
|
|
640
|
+
#
|
|
641
|
+
# Test whether the first <code>n</code> blocks contain null characters.
|
|
642
|
+
#
|
|
643
|
+
def binary? n = 1
|
|
644
|
+
bs = stat.blksize
|
|
645
|
+
open { |file|
|
|
646
|
+
loop do
|
|
647
|
+
if n then
|
|
648
|
+
break if n <= 0
|
|
649
|
+
n -= 1
|
|
650
|
+
end
|
|
651
|
+
b = file.read bs
|
|
652
|
+
b or break
|
|
653
|
+
return true if b[ "\0"]
|
|
696
654
|
end
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
655
|
+
}
|
|
656
|
+
false
|
|
657
|
+
end
|
|
658
|
+
alias bin? binary?
|
|
659
|
+
|
|
660
|
+
def vimswap?
|
|
661
|
+
if name =~ /\A(\..+)?\.sw[a-z]\z/i then
|
|
662
|
+
mark = read 5
|
|
663
|
+
mark == "b0VIM"
|
|
700
664
|
end
|
|
701
|
-
|
|
702
|
-
false
|
|
703
|
-
end
|
|
704
|
-
alias bin? binary?
|
|
665
|
+
end
|
|
705
666
|
|
|
706
667
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
def prune ; raise Prune ; end
|
|
717
|
-
|
|
718
|
-
# :call-seq:
|
|
719
|
-
# novcs() -> nil
|
|
720
|
-
#
|
|
721
|
-
# Perform <code>prune</code> if the current object is a CVS, Subversion or
|
|
722
|
-
# Git directory.
|
|
723
|
-
#
|
|
724
|
-
def novcs
|
|
725
|
-
prune if %w(CVS .svn .git .hg .fslckout).include? name
|
|
726
|
-
end
|
|
727
|
-
alias no_vcs novcs
|
|
728
|
-
|
|
729
|
-
# :call-seq:
|
|
730
|
-
# vimswap? -> true or false
|
|
731
|
-
#
|
|
732
|
-
# Check whether the current object is a Vim swapfile.
|
|
733
|
-
#
|
|
734
|
-
def vimswap?
|
|
735
|
-
if name =~ /\A(\..+)?\.sw[a-z]\z/i then
|
|
736
|
-
mark = read 5
|
|
737
|
-
mark == "b0VIM"
|
|
668
|
+
|
|
669
|
+
def done ; raise Done ; end
|
|
670
|
+
alias done! done
|
|
671
|
+
|
|
672
|
+
def prune ; raise Prune ; end
|
|
673
|
+
alias prune! prune
|
|
674
|
+
|
|
675
|
+
def novcs
|
|
676
|
+
prune if vcs?
|
|
738
677
|
end
|
|
739
|
-
|
|
678
|
+
alias no_vcs novcs
|
|
740
679
|
|
|
741
|
-
# Windows has ":" in filenames ("C:\...")
|
|
742
|
-
COLON = File::ALT_SEPARATOR ? "|" : ":" # :nodoc:
|
|
743
680
|
|
|
744
|
-
|
|
745
|
-
csv COLON, *args
|
|
746
|
-
end
|
|
747
|
-
alias col_sep colsep
|
|
681
|
+
include Csv
|
|
748
682
|
|
|
749
|
-
def tabsep *args
|
|
750
|
-
csv "\t", *args
|
|
751
|
-
end
|
|
752
|
-
alias tab_sep tabsep
|
|
753
683
|
|
|
754
|
-
|
|
755
|
-
csv " ", *args
|
|
756
|
-
end
|
|
757
|
-
alias spc_sep spcsep
|
|
758
|
-
alias space_sep spc_sep
|
|
759
|
-
alias spacesep spcsep
|
|
684
|
+
def rename newname ; @name = newname ; end
|
|
760
685
|
|
|
761
|
-
def csv sep, *args
|
|
762
|
-
e = args.join sep
|
|
763
|
-
puts e
|
|
764
|
-
end
|
|
765
686
|
|
|
766
|
-
def rename newname
|
|
767
|
-
p = @path
|
|
768
|
-
nb = File.basename newname
|
|
769
|
-
newname == nb or raise RuntimeError,
|
|
770
|
-
"#{self.class}: rename to `#{newname}' may not be a path."
|
|
771
|
-
nb.freeze
|
|
772
|
-
@levels.pop
|
|
773
|
-
@levels.push nb
|
|
774
|
-
build_path
|
|
775
|
-
File.rename p, @path
|
|
776
|
-
nil
|
|
777
|
-
end
|
|
778
687
|
|
|
779
|
-
|
|
688
|
+
def cname ; color name ; end
|
|
689
|
+
def cpath ; color path ; end
|
|
690
|
+
def cfullpath ; color fullpath ; end
|
|
691
|
+
def cpath! ; color path! ; end
|
|
692
|
+
def cfullpath! ; color fullpath! ; end
|
|
780
693
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
when nil then +1
|
|
788
|
-
else
|
|
789
|
-
case st.to_s
|
|
790
|
-
when "^", "reverse", /^desc/, /^-/ then -1
|
|
791
|
-
when "unsorted", "*" then 0
|
|
792
|
-
else +1
|
|
793
|
-
end
|
|
694
|
+
def creadlink
|
|
695
|
+
l = readlink
|
|
696
|
+
if l then
|
|
697
|
+
s = rstat rescue nil
|
|
698
|
+
color_stat l, s
|
|
699
|
+
end
|
|
794
700
|
end
|
|
795
|
-
end
|
|
796
701
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
break if q == p
|
|
801
|
-
p = q
|
|
702
|
+
def carrow
|
|
703
|
+
r = creadlink
|
|
704
|
+
ARROW + r if r
|
|
802
705
|
end
|
|
803
|
-
p != Dir::CUR_DIR
|
|
804
|
-
end
|
|
805
706
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
File.join @wd, @path
|
|
810
|
-
else
|
|
811
|
-
@path
|
|
707
|
+
|
|
708
|
+
def color arg
|
|
709
|
+
color_stat arg, stat
|
|
812
710
|
end
|
|
813
|
-
|
|
814
|
-
@fullpath.freeze
|
|
815
|
-
@path.freeze
|
|
816
|
-
end
|
|
711
|
+
alias colour color
|
|
817
712
|
|
|
818
|
-
|
|
819
|
-
return if @max_depth and depth > @max_depth
|
|
820
|
-
build_path
|
|
821
|
-
@count += 1
|
|
822
|
-
@do_level.call
|
|
823
|
-
end
|
|
713
|
+
private
|
|
824
714
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
715
|
+
def color_stat arg, s
|
|
716
|
+
m = s.mode if s
|
|
717
|
+
code = case m && m >> 12
|
|
718
|
+
when 001 then 5
|
|
719
|
+
when 002 then 8
|
|
720
|
+
when 004 then
|
|
721
|
+
if (m & 0002).nonzero? then
|
|
722
|
+
if (m & 01000).nonzero? then 11
|
|
723
|
+
else 12
|
|
724
|
+
end
|
|
725
|
+
else 2
|
|
726
|
+
end
|
|
727
|
+
when 006 then 7
|
|
728
|
+
when 010 then
|
|
729
|
+
if (m & 0111).nonzero? then
|
|
730
|
+
if (m & 04000).nonzero? then 9
|
|
731
|
+
elsif (m & 02000).nonzero? then 10
|
|
732
|
+
else 6
|
|
733
|
+
end
|
|
734
|
+
else col_type or 0
|
|
735
|
+
end
|
|
736
|
+
when 012 then 3
|
|
737
|
+
when 014 then 4
|
|
738
|
+
when 016 then 13
|
|
739
|
+
when nil then 1
|
|
740
|
+
else 14
|
|
741
|
+
end
|
|
742
|
+
self.class.colored arg, code
|
|
830
743
|
end
|
|
831
|
-
scan_dir
|
|
832
|
-
end
|
|
833
744
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
745
|
+
def col_type
|
|
746
|
+
# Overwrite this to define custom colors
|
|
747
|
+
# Example:
|
|
748
|
+
# case ext
|
|
749
|
+
# when ".png", /\.jpe?g$/, /\.tiff?$/ then 15
|
|
750
|
+
# when /\.tar\.(gz|bz2)$/ then 16
|
|
751
|
+
# end
|
|
840
752
|
end
|
|
841
|
-
begin
|
|
842
|
-
call_block
|
|
843
|
-
rescue Prune
|
|
844
|
-
raise RuntimeError, "#{self.class}: prune doesn't work with :depth."
|
|
845
|
-
end
|
|
846
|
-
end
|
|
847
753
|
|
|
848
|
-
|
|
849
|
-
set_predefs name, count
|
|
850
|
-
@block.call self
|
|
851
|
-
end
|
|
754
|
+
DEFAULT_COLORS = "xxHbexfxcxdxbxegedabagacadAx"
|
|
852
755
|
|
|
853
|
-
|
|
854
|
-
b = @block.binding
|
|
855
|
-
b.local_variable_set "_", [ l, n]
|
|
856
|
-
b.eval "$_, $. = *_"
|
|
857
|
-
end
|
|
756
|
+
class <<self
|
|
858
757
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
end
|
|
863
|
-
end
|
|
864
|
-
|
|
865
|
-
def scan_dir
|
|
866
|
-
return unless File.directory? @path
|
|
867
|
-
if File.symlink? @path then
|
|
868
|
-
return unless @follow and handle_error do
|
|
869
|
-
d = @path
|
|
870
|
-
while d != Dir::CUR_DIR do
|
|
871
|
-
d, = File.split d
|
|
872
|
-
raise "circular recursion in #@path" if File.identical? d, @path
|
|
873
|
-
end
|
|
874
|
-
true
|
|
758
|
+
def colored arg, num
|
|
759
|
+
colors col_str
|
|
760
|
+
"\e[#{@colors[num]}m#{arg}\e[m"
|
|
875
761
|
end
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
762
|
+
alias coloured colored
|
|
763
|
+
|
|
764
|
+
def colors str
|
|
765
|
+
@colors ||= if str =~ /:/ then
|
|
766
|
+
h = {}
|
|
767
|
+
(str.split ":").each { |a|
|
|
768
|
+
t, c = a.split "="
|
|
769
|
+
h[ t] = c
|
|
770
|
+
}
|
|
771
|
+
%w(rs or di ln so pi ex bd cd su sg tw ow - -).map { |t| h[ t] }
|
|
772
|
+
else
|
|
773
|
+
cols = []
|
|
774
|
+
str.scan /(.)(.)/i do
|
|
775
|
+
fg, bg = $~.captures.map { |x| x.downcase.ord - ?a.ord }
|
|
776
|
+
a = []
|
|
777
|
+
case fg
|
|
778
|
+
when 0..7 then a.push 30 + fg
|
|
779
|
+
end
|
|
780
|
+
a.push 1 if $1 == $1.upcase
|
|
781
|
+
case bg
|
|
782
|
+
when 0..7 then a.push 40 + bg
|
|
783
|
+
end
|
|
784
|
+
e = a.join ";"
|
|
785
|
+
cols.push e
|
|
786
|
+
end
|
|
787
|
+
cols
|
|
788
|
+
end
|
|
891
789
|
end
|
|
892
|
-
|
|
893
|
-
end
|
|
790
|
+
alias colours colors
|
|
894
791
|
|
|
895
|
-
|
|
896
|
-
yield
|
|
897
|
-
rescue err||StandardError
|
|
898
|
-
if @error.respond_to? :call then
|
|
899
|
-
@error.call
|
|
900
|
-
elsif @error then
|
|
901
|
-
instance_eval @error
|
|
902
|
-
else
|
|
903
|
-
raise
|
|
904
|
-
end
|
|
905
|
-
nil
|
|
906
|
-
end
|
|
792
|
+
private
|
|
907
793
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
if (m & 0002).nonzero? then
|
|
915
|
-
if (m & 01000).nonzero? then 11
|
|
916
|
-
else 12
|
|
794
|
+
def col_str
|
|
795
|
+
ENV[ "RBFIND_COLORS"] || ENV[ "RBFIND_COLOURS"] || ENV[ "LS_COLORS"] || (
|
|
796
|
+
env = DEFAULT_COLORS.dup
|
|
797
|
+
els = ENV[ "LSCOLORS"]
|
|
798
|
+
if els then
|
|
799
|
+
env[ 2*2, els.length] = els
|
|
917
800
|
end
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
when 010 then
|
|
922
|
-
col_type or \
|
|
923
|
-
if (m & 0111).nonzero? then
|
|
924
|
-
if (m & 04000).nonzero? then 9
|
|
925
|
-
elsif (m & 02000).nonzero? then 10
|
|
926
|
-
else 6
|
|
927
|
-
end
|
|
928
|
-
else 0
|
|
929
|
-
end
|
|
930
|
-
when 012 then 3
|
|
931
|
-
when 014 then 4
|
|
932
|
-
when 016 then 13
|
|
933
|
-
when nil then 1
|
|
934
|
-
else 14
|
|
935
|
-
end
|
|
936
|
-
self.class.colored arg, code
|
|
937
|
-
end
|
|
938
|
-
|
|
939
|
-
def col_type
|
|
940
|
-
# Overwrite this to define custom colors
|
|
941
|
-
# Example:
|
|
942
|
-
# case ext
|
|
943
|
-
# when ".png", /\.jpe?g$/, /\.tiff?$/ then 15
|
|
944
|
-
# when /\.tar\.(gz|bz2)$/ then 16
|
|
945
|
-
# end
|
|
946
|
-
end
|
|
801
|
+
env
|
|
802
|
+
)
|
|
803
|
+
end
|
|
947
804
|
|
|
948
|
-
class <<self
|
|
949
|
-
def find *args
|
|
950
|
-
raise NotImplementedError, "This is not the standard Find."
|
|
951
805
|
end
|
|
806
|
+
|
|
952
807
|
end
|
|
953
808
|
|
|
954
809
|
end
|