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