pa 1.1.4 → 1.2.0
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.
- 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
|