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