pa 1.0.3 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -6
- data/README.md +29 -14
- data/lib/pa.rb +34 -36
- data/lib/pa/cmd.rb +506 -414
- data/lib/pa/dir.rb +215 -175
- data/lib/pa/path.rb +282 -306
- data/lib/pa/state.rb +91 -52
- data/lib/pa/util.rb +32 -0
- data/lib/pa/version.rb +3 -0
- data/pa.gemspec +3 -5
- data/spec/pa/cmd_spec.rb +1 -1
- data/spec/pa/dir_spec.rb +19 -21
- data/spec/pa/path_spec.rb +22 -47
- metadata +22 -41
- data/LICENSE +0 -20
- data/version.rb +0 -9
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
Pa, a path libraray for Ruby
|
2
2
|
========================
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
| Homepage: | https://github.com/GutenYe/pa |
|
5
|
+
|----------------|--------------------------------------|
|
6
|
+
| Author: | Guten |
|
7
|
+
| License: | MIT-LICENSE |
|
8
|
+
| Documentation: | http://rubydoc.info/gems/pa/frames |
|
9
|
+
| Issue Tracker: | https://github.com/GutenYe/pa/issues |
|
10
|
+
|
9
11
|
|
10
12
|
Overview
|
11
13
|
--------
|
@@ -31,20 +33,33 @@ used with rspec
|
|
31
33
|
|
32
34
|
more see API doc
|
33
35
|
|
36
|
+
Install
|
37
|
+
----------
|
38
|
+
|
39
|
+
gem install pa
|
40
|
+
|
34
41
|
Contributing
|
35
42
|
-------------
|
36
43
|
|
37
|
-
* join the project
|
38
|
-
*
|
39
|
-
*
|
40
|
-
* improve documentation.
|
41
|
-
* feel free to post any ideas.
|
44
|
+
* Feel free to join the project and make contributions (by submitting a pull request)
|
45
|
+
* Submit any bugs/features/ideas to github issue tracker
|
46
|
+
* Coding Style Guide: https://gist.github.com/1105334
|
42
47
|
|
43
|
-
|
44
|
-
|
48
|
+
Contributors
|
49
|
+
------------
|
50
|
+
|
51
|
+
* [contributors](https://github.com/GutenYe/pa/contributors)
|
45
52
|
|
46
|
-
gem install pa
|
47
53
|
|
48
54
|
Copyright
|
49
55
|
---------
|
50
|
-
|
56
|
+
|
57
|
+
(the MIT License)
|
58
|
+
|
59
|
+
Copyright (c) 2011 Guten
|
60
|
+
|
61
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
62
|
+
|
63
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
64
|
+
|
65
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/pa.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "tagen/core"
|
2
|
-
|
3
1
|
=begin rdoc
|
4
2
|
Pa(Path) is similary to Pathname, but more powerful.
|
5
3
|
it combines fileutils, tmpdir, find, tempfile, File, Dir, Pathname
|
@@ -66,13 +64,37 @@ Example3:
|
|
66
64
|
|
67
65
|
=end
|
68
66
|
class Pa
|
67
|
+
autoload :Util, "pa/util"
|
68
|
+
autoload :VERSION, "pa/version"
|
69
|
+
|
69
70
|
Error = Class.new Exception
|
70
71
|
EUnkonwType = Class.new Error
|
71
72
|
|
73
|
+
class << self
|
74
|
+
def method_missing(name, *args, &blk)
|
75
|
+
# dir -> dir2
|
76
|
+
name2 = "#{name}2".to_sym
|
77
|
+
if public_methods.include?(name2)
|
78
|
+
ret = __send__(name2, *args)
|
79
|
+
return case ret
|
80
|
+
when Array
|
81
|
+
ret.map{|v| Pa(v)}
|
82
|
+
when String
|
83
|
+
Pa(ret)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
raise NoMethodError, "no method -- #{name}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
72
91
|
attr_reader :path
|
92
|
+
alias p path
|
93
|
+
alias path2 path
|
94
|
+
alias p2 path
|
73
95
|
|
74
96
|
# @param [String,#path] path
|
75
|
-
def initialize
|
97
|
+
def initialize(path)
|
76
98
|
@path = path.respond_to?(:path) ? path.path : path
|
77
99
|
initialize_variables
|
78
100
|
end
|
@@ -82,11 +104,9 @@ class Pa
|
|
82
104
|
end
|
83
105
|
include chainable
|
84
106
|
|
85
|
-
alias p path
|
86
|
-
|
87
107
|
# @param [String,#path]
|
88
108
|
# @return [Pa] the same Pa object
|
89
|
-
def replace
|
109
|
+
def replace(path)
|
90
110
|
@path = path.respond_to?(:path) ? path.path : path
|
91
111
|
initialize_variables
|
92
112
|
end
|
@@ -113,11 +133,9 @@ class Pa
|
|
113
133
|
ret = self.class.__send__(name, path, *args, &blk)
|
114
134
|
|
115
135
|
case ret
|
116
|
-
|
117
136
|
# e.g. readlink ..
|
118
137
|
when String
|
119
138
|
Pa(ret)
|
120
|
-
|
121
139
|
# e.g. directory?
|
122
140
|
else
|
123
141
|
ret
|
@@ -126,9 +144,7 @@ class Pa
|
|
126
144
|
end
|
127
145
|
|
128
146
|
def <=> other
|
129
|
-
other_path =
|
130
|
-
other_path =
|
131
|
-
if other.respond_to?(:path)
|
147
|
+
other_path = if other.respond_to?(:path)
|
132
148
|
other.path
|
133
149
|
elsif String === other
|
134
150
|
other
|
@@ -138,37 +154,20 @@ class Pa
|
|
138
154
|
|
139
155
|
path <=> other_path
|
140
156
|
end
|
141
|
-
|
142
157
|
end
|
143
158
|
|
159
|
+
require "pa/path"
|
160
|
+
require "pa/cmd"
|
161
|
+
require "pa/dir"
|
162
|
+
require "pa/state"
|
144
163
|
class Pa
|
145
|
-
module ClassMethods
|
146
|
-
UNDEFS = [:open, :fstat]
|
147
|
-
|
148
|
-
# missing method goes to File class method
|
149
|
-
def method_missing name, *args, &blk
|
150
|
-
raise NoMethodError, name.inspect if UNDEFS.include?(name)
|
151
|
-
return if args.size>1
|
152
|
-
File.__send__ name, get(args[0]), &blk
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
require_relative "pa/path"
|
158
|
-
require_relative "pa/cmd"
|
159
|
-
require_relative "pa/dir"
|
160
|
-
require_relative "pa/state"
|
161
|
-
class Pa
|
162
|
-
extend ClassMethods
|
163
|
-
extend ClassMethods::Path
|
164
|
-
extend ClassMethods::Dir
|
165
|
-
extend ClassMethods::State
|
166
|
-
extend ClassMethods::Cmd
|
167
|
-
|
168
164
|
include Path
|
165
|
+
include Dir
|
169
166
|
include State
|
167
|
+
include Cmd
|
170
168
|
end
|
171
169
|
|
170
|
+
|
172
171
|
module Kernel
|
173
172
|
private
|
174
173
|
# a very convient function.
|
@@ -180,4 +179,3 @@ private
|
|
180
179
|
Pa.new path
|
181
180
|
end
|
182
181
|
end
|
183
|
-
|
data/lib/pa/cmd.rb
CHANGED
@@ -9,418 +9,510 @@ rm family
|
|
9
9
|
rmdir path # it's clear: remove a directory
|
10
10
|
=end
|
11
11
|
class Pa
|
12
|
-
module
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
12
|
+
module Cmd
|
13
|
+
extend Util::Concern
|
14
|
+
module ClassMethods
|
15
|
+
# link
|
16
|
+
#
|
17
|
+
# @overload ln(src, dest)
|
18
|
+
# @overload ln([src,..], directory)
|
19
|
+
#
|
20
|
+
# @param [Array<String>, String] src_s support globbing
|
21
|
+
# @param [String,Pa] dest
|
22
|
+
# @param [Hash] o option
|
23
|
+
# @option o [Boolean] :force overwrite if exists.
|
24
|
+
# @return [nil]
|
25
|
+
def ln(src_s, dest, o={})
|
26
|
+
_ln(File.method(:link), src_s, dest, o)
|
27
|
+
end
|
28
|
+
|
29
|
+
# ln force
|
30
|
+
#
|
31
|
+
# @see ln
|
32
|
+
# @return [nil]
|
33
|
+
def ln_f(src_s, dest, o)
|
34
|
+
o[:force]=true
|
35
|
+
_ln(File.method(:link), src_s, dest, o)
|
36
|
+
end
|
37
|
+
|
38
|
+
# symbol link
|
39
|
+
#
|
40
|
+
# @see ln
|
41
|
+
# @return [nil]
|
42
|
+
def symln(src_s, dest, o)
|
43
|
+
_ln(File.method(:symlink), src_s, dest, o)
|
44
|
+
end
|
45
|
+
alias symlink ln
|
46
|
+
|
47
|
+
# symln force
|
48
|
+
#
|
49
|
+
# @see ln
|
50
|
+
# @return [nil]
|
51
|
+
def symln_f(src_s, dest, o)
|
52
|
+
o[:force]=true
|
53
|
+
_ln(File.method(:symlink), src_s, dest, o)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# @see File.readlink
|
58
|
+
def readlink(path)
|
59
|
+
File.readlink(get(path))
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# change directory
|
64
|
+
#
|
65
|
+
# @param [String,Pa] path
|
66
|
+
def cd(path=ENV["HOME"], &blk)
|
67
|
+
::Dir.chdir(get(path), &blk)
|
68
|
+
end
|
69
|
+
|
70
|
+
# chroot
|
71
|
+
# @see {Dir.chroot}
|
72
|
+
#
|
73
|
+
# @param [String] path
|
74
|
+
# @return [nil]
|
75
|
+
def chroot(path)
|
76
|
+
::Dir.chroot(get(path))
|
77
|
+
end
|
78
|
+
|
79
|
+
# touch a blank file
|
80
|
+
#
|
81
|
+
# @overload touch(*paths, o={})
|
82
|
+
# @param [String] *paths
|
83
|
+
# @param [Hash] o option
|
84
|
+
# @option o [Fixnum,String] :mode
|
85
|
+
# @option o [Boolean] :mkdir auto mkdir if path contained directory not exists.
|
86
|
+
# @option o [Boolean] :force
|
87
|
+
# @return [nil]
|
88
|
+
def touch(*args)
|
89
|
+
paths, o = Util.extract_options(args)
|
90
|
+
_touch(*paths, o)
|
91
|
+
end
|
92
|
+
|
93
|
+
# touch force
|
94
|
+
# @see touch
|
95
|
+
#
|
96
|
+
# @overload touch_f(*paths, o={})
|
97
|
+
# @return [nil]
|
98
|
+
def touch_f(*args)
|
99
|
+
paths, o = Util.extract_options(args)
|
100
|
+
o[:force]=true
|
101
|
+
_touch(*paths, o)
|
102
|
+
end
|
103
|
+
|
104
|
+
# make a directory
|
105
|
+
#
|
106
|
+
# @overload mkdir(*paths, o={})
|
107
|
+
# @param [String, Pa] *paths
|
108
|
+
# @param [Hash] o option
|
109
|
+
# @option o [Fixnum] :mode
|
110
|
+
# @option o [Boolean] :force
|
111
|
+
# @return [nil]
|
112
|
+
def mkdir(*args)
|
113
|
+
paths, o = Util.extract_options(args)
|
114
|
+
_mkdir(paths, o)
|
115
|
+
end
|
116
|
+
|
117
|
+
# mkdir force
|
118
|
+
# @see mkdir
|
119
|
+
#
|
120
|
+
# @overload mkdir_f(*paths, o={})
|
121
|
+
# @return [nil]
|
122
|
+
def mkdir_f(*args)
|
123
|
+
paths, o = Util.extract_options(args)
|
124
|
+
o[:force]=true
|
125
|
+
_mkdir(paths, o)
|
126
|
+
end
|
127
|
+
|
128
|
+
# make temp directory
|
129
|
+
#
|
130
|
+
# @param [Hash] o options
|
131
|
+
# @option o [Symbol] :prefix ("")
|
132
|
+
# @option o [Symbol] :suffix ("")
|
133
|
+
# @option o [Symbol] :tmpdir (ENV["TEMP"])
|
134
|
+
# @return [String] path
|
135
|
+
def mktmpdir(o={}, &blk)
|
136
|
+
p = _mktmpname(o)
|
137
|
+
File.mkdir(p)
|
138
|
+
begin blk.call(p) ensure ::Dir.delete(p) end if blk
|
139
|
+
p
|
140
|
+
end # def mktmpdir
|
141
|
+
|
142
|
+
def home(user=nil)
|
143
|
+
::Dir.home
|
144
|
+
end
|
145
|
+
|
146
|
+
# make temp file
|
147
|
+
# @see mktmpdir
|
148
|
+
#
|
149
|
+
# @param [Hash] o options
|
150
|
+
# @return [String] path
|
151
|
+
def mktmpfile(o={}, &blk)
|
152
|
+
p = _mktmpname(o)
|
153
|
+
begin
|
154
|
+
blk.call(p)
|
155
|
+
ensure
|
156
|
+
File.delete(p)
|
157
|
+
end if blk
|
158
|
+
p
|
159
|
+
end # mktmpfile
|
160
|
+
|
161
|
+
|
162
|
+
# rm file only
|
163
|
+
#
|
164
|
+
# @param [String] *paths support globbing
|
165
|
+
# @return [nil]
|
166
|
+
def rm(*paths)
|
167
|
+
paths, o = Util.extract_options(paths)
|
168
|
+
glob(*paths) { |pa|
|
169
|
+
if File.directory?(pa.p)
|
170
|
+
if o[:force]
|
171
|
+
next
|
172
|
+
else
|
173
|
+
raise Errno::EISDIR, "is a directory -- #{pa.p}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
next if pa.directory?
|
177
|
+
File.delete(pa.p)
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
181
|
+
def rm_f(*paths)
|
182
|
+
paths, o = Util.extract_options(paths)
|
183
|
+
o[:force] = true
|
184
|
+
rm *paths, o
|
185
|
+
end
|
186
|
+
|
187
|
+
# rm directory only. still remove if directory is not empty.
|
188
|
+
#
|
189
|
+
# @param [String] *paths support globbing
|
190
|
+
# @return [nil]
|
191
|
+
def rmdir(*paths)
|
192
|
+
paths, o = Util.extract_options(paths)
|
193
|
+
glob(*paths) { |pa|
|
194
|
+
if not File.directory?(pa.p)
|
195
|
+
if o[:force]
|
196
|
+
next
|
197
|
+
else
|
198
|
+
raise Errno::ENOTDIR, "not a directory -- #{pa.p}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
_rmdir(pa)
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
def rmdir_f(*paths)
|
206
|
+
paths, o = Util.extract_options(paths)
|
207
|
+
o[:force] = true
|
208
|
+
rmdir *paths, o
|
209
|
+
end
|
210
|
+
|
211
|
+
# rm recusive, rm both file and directory
|
212
|
+
#
|
213
|
+
# @see rm
|
214
|
+
# @return [nil]
|
215
|
+
def rm_r(*paths)
|
216
|
+
glob(*paths){ |pa|
|
217
|
+
File.directory?(pa.p) ? _rmdir(pa) : File.delete(pa.p)
|
218
|
+
}
|
219
|
+
end
|
220
|
+
alias rm_rf rm_r
|
221
|
+
|
222
|
+
# rm_if(path) if condition is true
|
223
|
+
#
|
224
|
+
# @example
|
225
|
+
# Pa.rm_if '/tmp/**/*.rb' do |pa|
|
226
|
+
# pa.name == 'old'
|
227
|
+
# end
|
228
|
+
#
|
229
|
+
# @param [String] *paths support globbing
|
230
|
+
# @yield [path]
|
231
|
+
# @yieldparam [Pa] path
|
232
|
+
# @yieldreturn [Boolean] rm_r path if true
|
233
|
+
# @return [nil]
|
234
|
+
def rm_if(*paths, &blk)
|
235
|
+
glob(*paths) do |pa|
|
236
|
+
rm_r pa if blk.call(pa)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# copy
|
241
|
+
#
|
242
|
+
# cp file dir
|
243
|
+
# cp 'a', 'dir' #=> dir/a
|
244
|
+
# cp 'a', 'dir/a' #=> dir/a
|
245
|
+
#
|
246
|
+
# cp file1 file2 .. dir
|
247
|
+
# cp ['a','b'], 'dir' #=> dir/a dir/b
|
248
|
+
#
|
249
|
+
# @example
|
250
|
+
# cp '*', 'dir' do |src, dest, o|
|
251
|
+
# skip if src.name=~'.o$'
|
252
|
+
# dest.replace 'dirc' if src.name=="foo"
|
253
|
+
# yield # use yield to do the actuactal cp work
|
254
|
+
# end
|
255
|
+
#
|
256
|
+
# @overload cp(src_s, dest, o)
|
257
|
+
# @param [Array<String>, String] src_s support globbing
|
258
|
+
# @param [String,Pa] dest
|
259
|
+
# @param [Hash] o option
|
260
|
+
# @option o [Boolean] :mkdir mkdir(dest) if dest not exists.
|
261
|
+
# @option o [Boolean] :verbose puts cmd when execute
|
262
|
+
# @option o [Boolean] :folsymlink follow symlink
|
263
|
+
# @option o [Boolean] :force force dest file if dest is a file
|
264
|
+
# @option o [Boolean] :special special copy, when cp a directory, only mkdir, not cp the directory's content, usefull in Pa.each_r
|
265
|
+
# @return [nil]
|
266
|
+
# @overload cp(src_s, dest, o)
|
267
|
+
# @yield [src,dest,o]
|
268
|
+
# @return [nil]
|
269
|
+
def cp(src_s, dest, o={}, &blk)
|
270
|
+
srcs = glob(*Util.wrap_array(src_s)).map{|v| v.path}
|
271
|
+
dest = Pa.get(dest)
|
272
|
+
|
273
|
+
if o[:mkdir] and (not File.exists?(dest))
|
274
|
+
Pa.mkdir dest
|
275
|
+
end
|
276
|
+
|
277
|
+
# cp file1 file2 .. dir
|
278
|
+
if srcs.size>1 and (not File.directory?(dest))
|
279
|
+
raise Errno::ENOTDIR, "dest not a directory when cp more than one src -- #{dest}"
|
280
|
+
end
|
281
|
+
|
282
|
+
srcs.each do |src|
|
283
|
+
dest1 = File.directory?(dest) ? File.join(dest, File.basename(src)) : dest
|
284
|
+
|
285
|
+
if blk
|
286
|
+
blk.call src, dest1, o, proc{_copy(src, dest1, o)}
|
287
|
+
else
|
288
|
+
_copy src, dest1, o
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def cp_f(src_s, dest, o={}, &blk)
|
295
|
+
o[:force] = true
|
296
|
+
cp src_s, dest, o, &blk
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
# a rename util
|
301
|
+
#
|
302
|
+
# @example
|
303
|
+
#
|
304
|
+
# Pa.rename('/home/guten.jpg') {|pa| pa.name+'_1'+pa.fext} # => '/home/guten_1.jpg'
|
305
|
+
# Pa('/home/guten.jpg').rename {|pa| pa.name+'_1'+pa.fext} # => <#Pa('/home/guten_1.jpg')>
|
306
|
+
#
|
307
|
+
# @param [String,Pa] src
|
308
|
+
# @yieldparam [Pa] pa
|
309
|
+
# @yieldreturn [String] fname
|
310
|
+
# @return [String,Pa] # Pa.rename return String. Pa#rename return Pa.
|
311
|
+
def rename(src, &blk)
|
312
|
+
src = Pa(src)
|
313
|
+
fname = blk.call(src)
|
314
|
+
src.dir.join(fname).path
|
315
|
+
end
|
316
|
+
|
317
|
+
# move, use rename for same device. and cp for cross device.
|
318
|
+
# @see cp
|
319
|
+
#
|
320
|
+
# @param [Hash] o option
|
321
|
+
# @option o [Boolean] :verbose
|
322
|
+
# @option o [Boolean] :mkdir
|
323
|
+
# @option o [Boolean] :fore
|
324
|
+
# @return [nil]
|
325
|
+
def mv(src_s, dest, o={}, &blk)
|
326
|
+
srcs = glob(*Util.wrap_array(src_s)).map{|v| get(v)}
|
327
|
+
dest = get(dest)
|
328
|
+
|
329
|
+
if o[:mkdir] and (not File.exists?(dest))
|
330
|
+
mkdir dest
|
331
|
+
end
|
332
|
+
|
333
|
+
# mv file1 file2 .. dir
|
334
|
+
if srcs.size>1 and (not File.directory?(dest))
|
335
|
+
raise Errno::ENOTDIR, "dest not a directory when mv more than one src -- #{dest}"
|
336
|
+
end
|
337
|
+
|
338
|
+
srcs.each do |src|
|
339
|
+
dest1 = File.directory?(dest) ? File.join(dest, File.basename(src)) : dest
|
340
|
+
|
341
|
+
if blk
|
342
|
+
blk.call src, dest1, o, proc{_move(src, dest1, o)}
|
343
|
+
else
|
344
|
+
_move src, dest1, o
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def mv_f(src_s, dest, o={}, &blk)
|
351
|
+
o[:force] = true
|
352
|
+
mv src_s, dest, o, &blk
|
353
|
+
end
|
354
|
+
|
355
|
+
# I'm recusive
|
356
|
+
#
|
357
|
+
# _move "file", "dir/file"
|
358
|
+
#
|
359
|
+
# @param [String] src
|
360
|
+
# @param [String] dest
|
361
|
+
def _move(src, dest, o)
|
362
|
+
raise Errno::EEXIST, "dest exists -- #{dest}" if File.exists?(dest) and (not o[:force])
|
363
|
+
|
364
|
+
# :force. mv "dir", "dira" and 'dira' exists and is a directory.
|
365
|
+
if File.exists?(dest) and File.directory?(dest)
|
366
|
+
ls(src) { |pa|
|
367
|
+
dest1 = File.join(dest, File.basename(pa.p))
|
368
|
+
_move pa.p, dest1, o
|
369
|
+
}
|
370
|
+
Pa.rm_r src
|
371
|
+
|
372
|
+
else
|
373
|
+
begin
|
374
|
+
Pa.rm_r dest if o[:force] and File.exists?(dest)
|
375
|
+
puts "rename #{src} #{dest}" if o[:verbose]
|
376
|
+
File.rename(src, dest)
|
377
|
+
rescue Errno::EXDEV # cross-device
|
378
|
+
_copy(src, dest, o)
|
379
|
+
Pa.rm_r src
|
380
|
+
end
|
381
|
+
|
382
|
+
end
|
383
|
+
end # def _move
|
384
|
+
|
385
|
+
def _touch(paths, o)
|
386
|
+
o[:mode] ||= 0644
|
387
|
+
paths.map!{|v|get(v)}
|
388
|
+
paths.each {|path|
|
389
|
+
if File.exists?(path)
|
390
|
+
o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{path}")
|
391
|
+
end
|
392
|
+
|
393
|
+
mkdir(File.dirname(p)) if o[:mkdir]
|
394
|
+
|
395
|
+
if win32?
|
396
|
+
# win32 BUG. must f.write("") then file can be deleted.
|
397
|
+
File.open(p, "w"){|f| f.chmod(o[:mode]); f.write("")}
|
398
|
+
else
|
399
|
+
File.open(p, "w"){|f| f.chmod(o[:mode])}
|
400
|
+
end
|
401
|
+
}
|
402
|
+
end
|
403
|
+
|
404
|
+
# @param [Array,String,#path] src_s
|
405
|
+
# @param [String,#path] dest
|
406
|
+
def _ln(method, src_s, dest, o={})
|
407
|
+
dest = get(dest)
|
408
|
+
glob(*Util.wrap_array(src_s)) {|src|
|
409
|
+
src = get(src)
|
410
|
+
dest = File.join(dest, File.basename(src)) if File.directory?(dest)
|
411
|
+
Pa.rm_r(dest) if o[:force] and File.exists?(dest)
|
412
|
+
method.call(src, dest)
|
413
|
+
}
|
414
|
+
end
|
415
|
+
|
416
|
+
def _mkdir(paths, o)
|
417
|
+
o[:mode] ||= 0744
|
418
|
+
paths.map!{|v|get(v)}
|
419
|
+
paths.each {|p|
|
420
|
+
if File.exists?(p)
|
421
|
+
o[:force] ? next : raise(Errno::EEXIST, "File exist -- #{p}")
|
422
|
+
end
|
423
|
+
|
424
|
+
stack = []
|
425
|
+
until p == stack.last
|
426
|
+
break if File.exists?(p)
|
427
|
+
stack << p
|
428
|
+
p = File.dirname(p)
|
429
|
+
end
|
430
|
+
|
431
|
+
stack.reverse.each do |path|
|
432
|
+
::Dir.mkdir(path)
|
433
|
+
File.chmod(o[:mode], path)
|
434
|
+
end
|
435
|
+
}
|
436
|
+
end
|
437
|
+
|
438
|
+
def _mktmpname(o={})
|
439
|
+
# :prefix :suffix :tmpdir
|
440
|
+
# $$-(time*100_000).to_i.to_s(36)
|
441
|
+
# parse o
|
442
|
+
o[:dir] ||= ENV["TEMP"]
|
443
|
+
o[:prefix] ||= ""
|
444
|
+
o[:suffix] ||= ""
|
445
|
+
|
446
|
+
# begin
|
447
|
+
collision = 0
|
448
|
+
path = "#{o[:dir]}/#{o[:prefix]}#{$$}-#{(Time.time*100_000).to_i.to_s(36)}"
|
449
|
+
orgi_path = path.dup
|
450
|
+
while File.exists?(path)
|
451
|
+
path = orgi_path+ collision.to_s
|
452
|
+
collision +=1
|
453
|
+
end
|
454
|
+
path << o[:suffix]
|
455
|
+
|
456
|
+
path
|
457
|
+
end # def mktmpname
|
458
|
+
|
459
|
+
# I'm recusive
|
460
|
+
# param@ [Pa] path
|
461
|
+
def _rmdir(pa, o={})
|
462
|
+
return if not File.exists?(pa.p)
|
463
|
+
pa.each {|pa1|
|
464
|
+
File.directory?(pa1.p) ? _rmdir(pa1, o) : File.delete(pa1.p)
|
465
|
+
}
|
466
|
+
File.directory?(pa.p) ? ::Dir.rmdir(pa.p) : File.delete(pa.p)
|
467
|
+
end
|
468
|
+
|
469
|
+
# I'm recursive
|
470
|
+
#
|
471
|
+
# @param [String] src
|
472
|
+
# @param [String] dest
|
473
|
+
def _copy(src, dest, o={})
|
474
|
+
raise Errno::EEXIST, "dest exists -- #{dest}" if File.exists?(dest) and (not o[:force])
|
475
|
+
|
476
|
+
case type=File.ftype(src)
|
477
|
+
|
478
|
+
when "file", "socket"
|
479
|
+
puts "cp #{src} #{dest}" if o[:verbose]
|
480
|
+
File.copy_stream(src, dest)
|
481
|
+
|
482
|
+
when "directory"
|
483
|
+
begin
|
484
|
+
Pa.mkdir dest
|
485
|
+
puts "mkdir #{dest}" if o[:verbose]
|
486
|
+
rescue Errno::EEXIST
|
487
|
+
end
|
488
|
+
|
489
|
+
return if o[:special]
|
490
|
+
|
491
|
+
each(src) { |pa|
|
492
|
+
_copy(pa.p, File.join(dest, File.basename(pa.p)), o)
|
493
|
+
}
|
494
|
+
|
495
|
+
when "link" # symbol link
|
496
|
+
if o[:folsymlink]
|
497
|
+
_copy(Pa.readlink(src), dest)
|
498
|
+
else
|
499
|
+
Pa.symln(Pa.readlink(src), dest, force: true)
|
500
|
+
puts "symlink #{src} #{dest}" if o[:verbose]
|
501
|
+
end
|
502
|
+
|
503
|
+
when "unknow"
|
504
|
+
raise EUnKnownType, "Can't handle unknow type(#{:type}) -- #{src}"
|
505
|
+
end
|
506
|
+
|
507
|
+
# chmod chown utime
|
508
|
+
src_stat = o[:folsymlink] ? File.stat(src) : File.lstat(src)
|
509
|
+
begin
|
510
|
+
File.chmod(src_stat.mode, dest)
|
511
|
+
#File.chown(src_stat.uid, src_stat.gid, dest)
|
512
|
+
File.utime(src_stat.atime, src_stat.mtime, dest)
|
513
|
+
rescue Errno::ENOENT
|
514
|
+
end
|
515
|
+
end # _copy
|
516
|
+
end
|
517
|
+
end
|
426
518
|
end
|