pa 1.1.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -4
- data/Gemfile.lock +8 -8
- data/lib/pa/cmd.rb +124 -87
- data/lib/pa/directory.rb +55 -19
- data/lib/pa/path.rb +38 -180
- data/lib/pa/state.rb +12 -4
- data/lib/pa/version.rb +1 -1
- data/lib/pa.rb +318 -38
- data/spec/pa/cmd_spec.rb +50 -17
- data/spec/pa/directory_spec.rb +107 -16
- data/spec/pa/path_spec.rb +71 -173
- data/spec/pa/state_spec.rb +9 -3
- data/spec/pa_spec.rb +261 -1
- data/spec/spec_helper.rb +39 -0
- metadata +9 -2
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
diff-lcs (1.1.
|
5
|
-
rspec (2.
|
6
|
-
rspec-core (~> 2.
|
7
|
-
rspec-expectations (~> 2.
|
8
|
-
rspec-mocks (~> 2.
|
9
|
-
rspec-core (2.
|
10
|
-
rspec-expectations (2.
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
rspec (2.8.0)
|
6
|
+
rspec-core (~> 2.8.0)
|
7
|
+
rspec-expectations (~> 2.8.0)
|
8
|
+
rspec-mocks (~> 2.8.0)
|
9
|
+
rspec-core (2.8.0)
|
10
|
+
rspec-expectations (2.8.0)
|
11
11
|
diff-lcs (~> 1.1.2)
|
12
|
-
rspec-mocks (2.
|
12
|
+
rspec-mocks (2.8.0)
|
13
13
|
thor (0.14.6)
|
14
14
|
watchr (0.7)
|
15
15
|
|
data/lib/pa/cmd.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
1
3
|
=begin
|
2
4
|
rm family
|
3
5
|
* rm _rm file only_
|
@@ -19,28 +21,26 @@ class Pa
|
|
19
21
|
#
|
20
22
|
# @param [Array<String>, String] src_s support globbing
|
21
23
|
# @param [String,Pa] dest
|
22
|
-
# @param [Hash] o option
|
23
|
-
# @option o [Boolean] :force overwrite if exists.
|
24
24
|
# @return [nil]
|
25
25
|
def ln(src_s, dest, o={})
|
26
|
-
_ln(
|
26
|
+
_ln(:link, src_s, dest, o)
|
27
27
|
end
|
28
28
|
|
29
29
|
# ln force
|
30
30
|
#
|
31
31
|
# @see ln
|
32
32
|
# @return [nil]
|
33
|
-
def ln_f(src_s, dest, o)
|
33
|
+
def ln_f(src_s, dest, o={})
|
34
34
|
o[:force]=true
|
35
|
-
_ln(
|
35
|
+
_ln(:link, src_s, dest, o)
|
36
36
|
end
|
37
37
|
|
38
38
|
# symbol link
|
39
39
|
#
|
40
40
|
# @see ln
|
41
41
|
# @return [nil]
|
42
|
-
def symln(src_s, dest, o)
|
43
|
-
_ln(
|
42
|
+
def symln(src_s, dest, o={})
|
43
|
+
_ln(:symlink, src_s, dest, o)
|
44
44
|
end
|
45
45
|
alias symlink ln
|
46
46
|
|
@@ -48,12 +48,11 @@ class Pa
|
|
48
48
|
#
|
49
49
|
# @see ln
|
50
50
|
# @return [nil]
|
51
|
-
def symln_f(src_s, dest, o)
|
51
|
+
def symln_f(src_s, dest, o={})
|
52
52
|
o[:force]=true
|
53
|
-
_ln(
|
53
|
+
_ln(:symlink, src_s, dest, o)
|
54
54
|
end
|
55
55
|
|
56
|
-
|
57
56
|
# @see File.readlink
|
58
57
|
def readlink(path)
|
59
58
|
File.readlink(get(path))
|
@@ -62,17 +61,25 @@ class Pa
|
|
62
61
|
# change directory
|
63
62
|
#
|
64
63
|
# @param [String,Pa] path
|
65
|
-
|
66
|
-
|
64
|
+
# @param [Hash] o
|
65
|
+
# @option o [Boolean] :verbose verbose mode
|
66
|
+
def cd(path=ENV["HOME"], o={}, &blk)
|
67
|
+
p = get(path)
|
68
|
+
puts "cd #{p}" if o[:verbose]
|
69
|
+
Dir.chdir(p, &blk)
|
67
70
|
end
|
68
71
|
|
69
72
|
# chroot
|
70
73
|
# @see {Dir.chroot}
|
71
74
|
#
|
72
75
|
# @param [String] path
|
76
|
+
# @param [Hash] o
|
77
|
+
# @option o [Boolean] :verbose verbose mode
|
73
78
|
# @return [nil]
|
74
|
-
def chroot(path)
|
75
|
-
|
79
|
+
def chroot(path, o={})
|
80
|
+
p = get(path)
|
81
|
+
puts "chdroot #{p}" if o[:verbose]
|
82
|
+
Dir.chroot(p)
|
76
83
|
end
|
77
84
|
|
78
85
|
# touch a blank file
|
@@ -83,10 +90,11 @@ class Pa
|
|
83
90
|
# @option o [Fixnum,String] :mode
|
84
91
|
# @option o [Boolean] :mkdir auto mkdir if path contained directory not exists.
|
85
92
|
# @option o [Boolean] :force
|
93
|
+
# @option o [Boolean] :verbose
|
86
94
|
# @return [nil]
|
87
95
|
def touch(*args)
|
88
96
|
paths, o = Util.extract_options(args)
|
89
|
-
_touch(
|
97
|
+
_touch(paths, o)
|
90
98
|
end
|
91
99
|
|
92
100
|
# touch force
|
@@ -96,8 +104,8 @@ class Pa
|
|
96
104
|
# @return [nil]
|
97
105
|
def touch_f(*args)
|
98
106
|
paths, o = Util.extract_options(args)
|
99
|
-
o[:force]=true
|
100
|
-
_touch(
|
107
|
+
o[:force] = true
|
108
|
+
_touch(paths, o)
|
101
109
|
end
|
102
110
|
|
103
111
|
# make a directory
|
@@ -107,6 +115,7 @@ class Pa
|
|
107
115
|
# @param [Hash] o option
|
108
116
|
# @option o [Fixnum] :mode
|
109
117
|
# @option o [Boolean] :force
|
118
|
+
# @option o [Boolean] :verbose
|
110
119
|
# @return [nil]
|
111
120
|
def mkdir(*args)
|
112
121
|
paths, o = Util.extract_options(args)
|
@@ -126,45 +135,84 @@ class Pa
|
|
126
135
|
|
127
136
|
# make temp directory
|
128
137
|
#
|
129
|
-
# @
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
+
# @overload mktmpdir(name, o={}, &blk)
|
139
|
+
# @param [Hash] o options
|
140
|
+
# @option o [String] :tmpdir (ENV["TEMP"])
|
141
|
+
# @option o [Symbol] :verbose
|
142
|
+
# @return [String] path
|
143
|
+
# @overload mktmpdir(o={}, &blk) # name=$$
|
144
|
+
def mktmpdir(*args, &blk)
|
145
|
+
(name,), o = Util.extract_options(args)
|
146
|
+
|
147
|
+
p = _mktmpname(name, o)
|
148
|
+
puts "mktmpdir #{p}" if o[:verbose]
|
149
|
+
|
150
|
+
Dir.mkdir(p)
|
151
|
+
|
152
|
+
begin
|
153
|
+
blk.call(p)
|
154
|
+
ensure
|
155
|
+
Dir.delete(p)
|
156
|
+
end if blk
|
157
|
+
|
138
158
|
p
|
139
159
|
end # def mktmpdir
|
140
160
|
|
141
|
-
def home
|
161
|
+
def home
|
142
162
|
Dir.home
|
143
163
|
end
|
144
164
|
|
145
165
|
# make temp file
|
146
166
|
# @see mktmpdir
|
147
167
|
#
|
148
|
-
# @
|
149
|
-
#
|
150
|
-
|
151
|
-
|
168
|
+
# @overload mktmpfile2(name=$$, o={}, &blk)
|
169
|
+
# @param [Hash] o options
|
170
|
+
# @option o [Boolean] :verbose
|
171
|
+
# @option o [String] :tmpdir
|
172
|
+
# @return [String] path
|
173
|
+
def mktmpfile2(*args, &blk)
|
174
|
+
(name,), o = Util.extract_options(args)
|
175
|
+
|
176
|
+
p = _mktmpname(name, o)
|
177
|
+
puts "mktmpfile #{p}" if o[:verbose]
|
178
|
+
|
152
179
|
begin
|
153
180
|
blk.call(p)
|
154
181
|
ensure
|
155
182
|
File.delete(p)
|
156
183
|
end if blk
|
184
|
+
|
157
185
|
p
|
158
|
-
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# @return [Pa] path
|
189
|
+
def mktmpfile(*args, &blk)
|
190
|
+
(name,), o = Util.extract_options(args)
|
191
|
+
|
192
|
+
p = _mktmpname(name, o)
|
193
|
+
puts "mktmpfile #{p}" if o[:verbose]
|
194
|
+
|
195
|
+
begin
|
196
|
+
blk.call(Pa(p))
|
197
|
+
ensure
|
198
|
+
File.delete(p)
|
199
|
+
end if blk
|
159
200
|
|
201
|
+
Pa(p)
|
202
|
+
end
|
160
203
|
|
161
204
|
# rm file only
|
162
205
|
#
|
163
|
-
# @
|
206
|
+
# @overload rm(*paths, o={})
|
207
|
+
# @param [String] *paths support globbing
|
208
|
+
# @param o [Boolean] :verbose
|
164
209
|
# @return [nil]
|
165
210
|
def rm(*paths)
|
166
211
|
paths, o = Util.extract_options(paths)
|
167
212
|
glob(*paths) { |pa|
|
213
|
+
extra_doc = o[:force] ? "-f " : nil
|
214
|
+
puts "rm #{extra_doc}#{pd.p}" if o[:verbose]
|
215
|
+
|
168
216
|
if File.directory?(pa.p)
|
169
217
|
if o[:force]
|
170
218
|
next
|
@@ -190,6 +238,9 @@ class Pa
|
|
190
238
|
def rmdir(*paths)
|
191
239
|
paths, o = Util.extract_options(paths)
|
192
240
|
glob(*paths) { |pa|
|
241
|
+
extra_doc = o[:force] ? "-f " : nil
|
242
|
+
puts "rmdir #{extra_doc}#{pa.p}" if o[:verbose]
|
243
|
+
|
193
244
|
if not File.directory?(pa.p)
|
194
245
|
if o[:force]
|
195
246
|
next
|
@@ -212,7 +263,9 @@ class Pa
|
|
212
263
|
# @see rm
|
213
264
|
# @return [nil]
|
214
265
|
def rm_r(*paths)
|
266
|
+
paths, o = Util.extract_options(paths)
|
215
267
|
glob(*paths){ |pa|
|
268
|
+
puts "rm -r #{pa.p}" if o[:verbose]
|
216
269
|
File.directory?(pa.p) ? _rmdir(pa) : File.delete(pa.p)
|
217
270
|
}
|
218
271
|
end
|
@@ -231,8 +284,9 @@ class Pa
|
|
231
284
|
# @yieldreturn [Boolean] rm_r path if true
|
232
285
|
# @return [nil]
|
233
286
|
def rm_if(*paths, &blk)
|
287
|
+
paths, o = Util.extract_options(paths)
|
234
288
|
glob(*paths) do |pa|
|
235
|
-
rm_r pa if blk.call(pa)
|
289
|
+
rm_r pa, o if blk.call(pa)
|
236
290
|
end
|
237
291
|
end
|
238
292
|
|
@@ -295,23 +349,6 @@ class Pa
|
|
295
349
|
cp src_s, dest, o, &blk
|
296
350
|
end
|
297
351
|
|
298
|
-
|
299
|
-
# a rename util
|
300
|
-
#
|
301
|
-
# @example
|
302
|
-
#
|
303
|
-
# Pa.rename2('/home/guten.jpg') {|pa| pa.name+'_1'+pa.fext} # => '/home/guten_1.jpg'
|
304
|
-
#
|
305
|
-
# @param [String,Pa] src
|
306
|
-
# @yieldparam [Pa] pa
|
307
|
-
# @yieldreturn [String] fname
|
308
|
-
# @return [String,Pa] # Pa.rename return String. Pa#rename return Pa.
|
309
|
-
def rename2(src, &blk)
|
310
|
-
src = Pa(src)
|
311
|
-
fname = blk.call(src)
|
312
|
-
src.dir.join(fname).path
|
313
|
-
end
|
314
|
-
|
315
352
|
# move, use rename for same device. and cp for cross device.
|
316
353
|
# @see cp
|
317
354
|
#
|
@@ -383,9 +420,12 @@ class Pa
|
|
383
420
|
def _touch(paths, o)
|
384
421
|
o[:mode] ||= 0644
|
385
422
|
paths.map!{|v|get(v)}
|
386
|
-
paths.each {|
|
387
|
-
|
388
|
-
|
423
|
+
paths.each {|p|
|
424
|
+
extra_doc = o[:force] ? "-f " : nil
|
425
|
+
puts "touch #{extra_doc}#{p}" if o[:verbose]
|
426
|
+
|
427
|
+
if File.exists?(p)
|
428
|
+
o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{p}")
|
389
429
|
end
|
390
430
|
|
391
431
|
mkdir(File.dirname(p)) if o[:mkdir]
|
@@ -399,22 +439,29 @@ class Pa
|
|
399
439
|
}
|
400
440
|
end
|
401
441
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
442
|
+
# @param [Array,String,#path] src_s
|
443
|
+
# @param [String,#path] dest
|
444
|
+
def _ln(method, src_s, dest, o={})
|
445
|
+
dest = get(dest)
|
446
|
+
glob(*Util.wrap_array(src_s)) {|src|
|
447
|
+
src = get(src)
|
448
|
+
dest = File.join(dest, File.basename(src)) if File.directory?(dest)
|
449
|
+
Pa.rm_r(dest) if o[:force] and File.exists?(dest)
|
450
|
+
extra_doc = ""
|
451
|
+
extra_doc << (method==:symlink ? "-s " : "")
|
452
|
+
extra_doc << (o[:force] ? "-f " : "")
|
453
|
+
puts "ln #{extra_doc}#{src} #{dest}" if o[:verbose]
|
454
|
+
|
455
|
+
File.send(method, src, dest)
|
456
|
+
}
|
457
|
+
end
|
413
458
|
|
414
459
|
def _mkdir(paths, o)
|
415
460
|
o[:mode] ||= 0744
|
416
461
|
paths.map!{|v|get(v)}
|
417
462
|
paths.each {|p|
|
463
|
+
puts "mkdir #{p}" if o[:verbose]
|
464
|
+
|
418
465
|
if File.exists?(p)
|
419
466
|
o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{p}")
|
420
467
|
end
|
@@ -433,23 +480,15 @@ class Pa
|
|
433
480
|
}
|
434
481
|
end
|
435
482
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
collision = 0
|
446
|
-
path = "#{o[:dir]}/#{o[:prefix]}#{$$}-#{(Time.time*100_000).to_i.to_s(36)}"
|
447
|
-
orgi_path = path.dup
|
448
|
-
while File.exists?(path)
|
449
|
-
path = orgi_path+ collision.to_s
|
450
|
-
collision +=1
|
451
|
-
end
|
452
|
-
path << o[:suffix]
|
483
|
+
# <name>.JNBNZG
|
484
|
+
def _mktmpname(name=nil, o={})
|
485
|
+
o[:tmpdir] ||= ENV["TEMP"]
|
486
|
+
name ||= $$
|
487
|
+
|
488
|
+
begin
|
489
|
+
random = SecureRandom.hex(3).upcase
|
490
|
+
path = "#{o[:tmpdir]}/#{name}.#{random}"
|
491
|
+
end while File.exists?(path)
|
453
492
|
|
454
493
|
path
|
455
494
|
end # def mktmpname
|
@@ -458,7 +497,7 @@ class Pa
|
|
458
497
|
# param@ [Pa] path
|
459
498
|
def _rmdir(pa, o={})
|
460
499
|
return if not File.exists?(pa.p)
|
461
|
-
|
500
|
+
Pa.each(pa) {|pa1|
|
462
501
|
File.directory?(pa1.p) ? _rmdir(pa1, o) : File.delete(pa1.p)
|
463
502
|
}
|
464
503
|
File.directory?(pa.p) ? Dir.rmdir(pa.p) : File.delete(pa.p)
|
@@ -479,8 +518,7 @@ class Pa
|
|
479
518
|
|
480
519
|
when "directory"
|
481
520
|
begin
|
482
|
-
Pa.mkdir dest
|
483
|
-
puts "mkdir #{dest}" if o[:verbose]
|
521
|
+
Pa.mkdir dest, :verbose => o[:verbose]
|
484
522
|
rescue Errno::EEXIST
|
485
523
|
end
|
486
524
|
|
@@ -494,8 +532,7 @@ class Pa
|
|
494
532
|
if o[:folsymlink]
|
495
533
|
_copy(Pa.readlink(src), dest)
|
496
534
|
else
|
497
|
-
Pa.symln(Pa.readlink(src), dest, force:
|
498
|
-
puts "symlink #{src} #{dest}" if o[:verbose]
|
535
|
+
Pa.symln(Pa.readlink(src), dest, :force => true, :verbose => o[:verbose])
|
499
536
|
end
|
500
537
|
|
501
538
|
when "unknow"
|
data/lib/pa/directory.rb
CHANGED
@@ -72,6 +72,14 @@ class Pa
|
|
72
72
|
ret
|
73
73
|
end
|
74
74
|
|
75
|
+
def tmpdir2
|
76
|
+
Dir.tmpdir
|
77
|
+
end
|
78
|
+
|
79
|
+
def tmpdir
|
80
|
+
Pa(Dir.tmpdir)
|
81
|
+
end
|
82
|
+
|
75
83
|
# is directory empty?
|
76
84
|
#
|
77
85
|
# @param [String] path
|
@@ -96,8 +104,9 @@ class Pa
|
|
96
104
|
# @overload each(path=".", o={})
|
97
105
|
# @param [String,Pa] path
|
98
106
|
# @prarm [Hash] o
|
99
|
-
# @option o [Boolean] :
|
100
|
-
# @option o [Boolean] :
|
107
|
+
# @option o [Boolean] :dot (true) include dot file
|
108
|
+
# @option o [Boolean] :backup (true) include backup file
|
109
|
+
# @option o [Boolean] :absolute (false) return absolute path
|
101
110
|
# @option o [Boolean] :error (false) yield(pa, err) instead of raise Errno::EPERM when Dir.open(dir)
|
102
111
|
# @return [Enumerator<String>]
|
103
112
|
# @overload each(path=".", o={})
|
@@ -107,6 +116,8 @@ class Pa
|
|
107
116
|
return Pa.to_enum(:each2, *args) unless blk
|
108
117
|
|
109
118
|
(path,), o = Util.extract_options(args)
|
119
|
+
o = {dot: true, backup: true}.merge(o)
|
120
|
+
|
110
121
|
path = path ? get(path) : "."
|
111
122
|
raise Errno::ENOENT, "`#{path}' doesn't exists." unless File.exists?(path)
|
112
123
|
raise Errno::ENOTDIR, "`#{path}' not a directoy." unless File.directory?(path)
|
@@ -119,20 +130,27 @@ class Pa
|
|
119
130
|
|
120
131
|
while (entry=dir.read)
|
121
132
|
next if %w(. ..).include? entry
|
122
|
-
next if o[:
|
123
|
-
next if o[:
|
133
|
+
next if not o[:dot] and entry=~/^\./
|
134
|
+
next if not o[:backup] and entry=~/~$/
|
135
|
+
|
136
|
+
p = if o[:absolute]
|
137
|
+
File.absolute_path(File.join(path, entry))
|
138
|
+
else
|
139
|
+
# => "foo" not "./foo"
|
140
|
+
path=="." ? entry : File.join(path, entry)
|
141
|
+
end
|
124
142
|
|
125
|
-
|
126
|
-
pa = path=="." ? entry : File.join(path, entry)
|
127
|
-
blk.call pa, err
|
143
|
+
blk.call p, err
|
128
144
|
end
|
129
145
|
end
|
130
146
|
|
131
147
|
def each(*args, &blk)
|
148
|
+
return Pa.to_enum(:each, *args) unless blk
|
149
|
+
|
132
150
|
args, o = Util.extract_options(args)
|
133
|
-
each2
|
151
|
+
each2(*args, o) { |path, err|
|
134
152
|
blk.call Pa(path), err
|
135
|
-
|
153
|
+
}
|
136
154
|
end
|
137
155
|
|
138
156
|
# each with recursive
|
@@ -181,11 +199,16 @@ class Pa
|
|
181
199
|
# @yieldparam [String] fname
|
182
200
|
# @return [Array<String>]
|
183
201
|
def ls2(*args, &blk)
|
202
|
+
(path,), o = Util.extract_options(args)
|
203
|
+
path ||= "."
|
184
204
|
blk ||= proc { true }
|
185
|
-
|
205
|
+
|
206
|
+
each2(path, o).with_object([]) { |(path),m|
|
186
207
|
base = File.basename(path)
|
187
|
-
|
188
|
-
|
208
|
+
|
209
|
+
blk_ret = blk.call(path, base)
|
210
|
+
file = o[:absolute] ? path : base
|
211
|
+
m << file if blk_ret
|
189
212
|
}
|
190
213
|
end
|
191
214
|
|
@@ -196,16 +219,17 @@ class Pa
|
|
196
219
|
# @yieldparam [String] fname
|
197
220
|
# @return [Array<String>]
|
198
221
|
def ls(*args, &blk)
|
199
|
-
|
222
|
+
(path,), o = Util.extract_options(args)
|
223
|
+
path ||= "."
|
200
224
|
blk ||= proc { true }
|
201
|
-
ret = []
|
202
225
|
|
203
|
-
|
204
|
-
|
205
|
-
ret << fname if rst
|
206
|
-
end
|
226
|
+
each2(path, o).with_object([]) { |(path), m|
|
227
|
+
base = File.basename(path)
|
207
228
|
|
208
|
-
|
229
|
+
blk_ret = blk.call(Pa(path), base)
|
230
|
+
file = o[:absolute] ? path : base
|
231
|
+
m << Pa(file) if blk_ret
|
232
|
+
}
|
209
233
|
end
|
210
234
|
|
211
235
|
# ls2 with recursive
|
@@ -247,5 +271,17 @@ class Pa
|
|
247
271
|
end
|
248
272
|
end
|
249
273
|
end
|
274
|
+
|
275
|
+
module InstanceMethods
|
276
|
+
DELEGATE_METHODS = [:each2, :each, :each2_r, :each_r, :ls2, :ls]
|
277
|
+
|
278
|
+
DELEGATE_METHODS.each { |mth|
|
279
|
+
class_eval <<-EOF
|
280
|
+
def #{mth}(*args, &blk)
|
281
|
+
Pa.#{mth}(path, *args, &blk)
|
282
|
+
end
|
283
|
+
EOF
|
284
|
+
}
|
285
|
+
end
|
250
286
|
end
|
251
287
|
end
|