trema 0.3.21 → 0.4.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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -1
- data/Gemfile +4 -4
- data/README.md +6 -9
- data/Rakefile +508 -24
- data/build.rb +4 -9
- data/cruise.rb +3 -3
- data/features/switch_event/add_forward_entry.feature +1 -0
- data/features/switch_event/delete_forward_entry.feature +1 -0
- data/features/switch_event/dump_forward_entries.feature +1 -0
- data/features/switch_event/set_forward_entries.feature +1 -0
- data/ruby/trema/compat.h +36 -0
- data/ruby/trema/controller.c +23 -7
- data/ruby/trema/default-logger.c +1 -1
- data/ruby/trema/features-reply.c +1 -1
- data/ruby/trema/switch-event.c +11 -10
- data/ruby/trema/switch.c +11 -11
- data/ruby/trema/version.rb +1 -1
- data/spec/support/matchers/constant.rb +25 -0
- data/spec/trema/barrier-request_spec.rb +1 -0
- data/spec/trema/controller_spec.rb +11 -28
- data/spec/trema/error_spec.rb +0 -46
- data/spec/trema/packet-out_spec.rb +1 -1
- data/spec/trema/port-status_spec.rb +8 -5
- data/spec/trema_spec.rb +64 -24
- data/src/lib/checks.h +2 -2
- data/src/lib/messenger.c +3 -3
- data/src/lib/openflow_message.c +8 -1
- data/src/lib/openflow_message.h +1 -0
- data/src/lib/openflow_switch_interface.c +1 -1
- data/src/switch_manager/secure_channel_listener.c +1 -1
- data/src/switch_manager/secure_channel_receiver.c +1 -1
- data/trema.gemspec +3 -3
- data/unittests/lib/daemon_test.c +1 -1
- data/unittests/lib/hash_table_test.c +1 -1
- metadata +87 -113
- data/.mono.rant +0 -4107
- data/Rantfile +0 -739
data/.mono.rant
DELETED
@@ -1,4107 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# .mono.rant - Monolithic rant script, autogenerated by rant-import 0.5.7.
|
4
|
-
#
|
5
|
-
# Copyright (C) 2005 Stefan Lang <langstefan@gmx.at>
|
6
|
-
#
|
7
|
-
# This program is free software.
|
8
|
-
# You can distribute/modify this program under the terms of
|
9
|
-
# the GNU LGPL, Lesser General Public License version 2.1.
|
10
|
-
|
11
|
-
|
12
|
-
require 'getoptlong'
|
13
|
-
|
14
|
-
|
15
|
-
require 'rbconfig'
|
16
|
-
|
17
|
-
unless Process::Status.method_defined?(:success?) # new in 1.8.2
|
18
|
-
class Process::Status
|
19
|
-
def success?; exitstatus == 0; end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
unless Regexp.respond_to? :union # new in 1.8.1
|
23
|
-
def Regexp.union(*patterns)
|
24
|
-
return /(?!)/ if patterns.empty?
|
25
|
-
Regexp.new(patterns.join("|"))
|
26
|
-
end
|
27
|
-
end
|
28
|
-
if RUBY_VERSION < "1.8.2"
|
29
|
-
class Array
|
30
|
-
undef_method :flatten, :flatten!
|
31
|
-
def flatten
|
32
|
-
cp = self.dup
|
33
|
-
cp.flatten!
|
34
|
-
cp
|
35
|
-
end
|
36
|
-
def flatten!
|
37
|
-
res = []
|
38
|
-
flattened = false
|
39
|
-
self.each { |e|
|
40
|
-
if e.respond_to? :to_ary
|
41
|
-
res.concat(e.to_ary)
|
42
|
-
flattened = true
|
43
|
-
else
|
44
|
-
res << e
|
45
|
-
end
|
46
|
-
}
|
47
|
-
if flattened
|
48
|
-
replace(res)
|
49
|
-
flatten!
|
50
|
-
self
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
class String
|
57
|
-
def _rant_sub_ext(ext, new_ext = nil)
|
58
|
-
if new_ext
|
59
|
-
self.sub(/#{Regexp.escape ext}$/, new_ext)
|
60
|
-
else
|
61
|
-
self.sub(/(\.[^.]*$)|$/, ".#{ext}")
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
module Rant
|
67
|
-
VERSION = '0.5.7'
|
68
|
-
|
69
|
-
@__rant_no_value__ = Object.new.freeze
|
70
|
-
def self.__rant_no_value__
|
71
|
-
@__rant_no_value__
|
72
|
-
end
|
73
|
-
|
74
|
-
module Env
|
75
|
-
OS = ::Config::CONFIG['target']
|
76
|
-
RUBY = ::Config::CONFIG['ruby_install_name']
|
77
|
-
RUBY_BINDIR = ::Config::CONFIG['bindir']
|
78
|
-
RUBY_EXE = File.join(RUBY_BINDIR, RUBY + ::Config::CONFIG["EXEEXT"])
|
79
|
-
|
80
|
-
@@zip_bin = false
|
81
|
-
@@tar_bin = false
|
82
|
-
|
83
|
-
if OS =~ /mswin/i
|
84
|
-
def on_windows?; true; end
|
85
|
-
else
|
86
|
-
def on_windows?; false; end
|
87
|
-
end
|
88
|
-
|
89
|
-
def have_zip?
|
90
|
-
if @@zip_bin == false
|
91
|
-
@@zip_bin = find_bin "zip"
|
92
|
-
end
|
93
|
-
!@@zip_bin.nil?
|
94
|
-
end
|
95
|
-
def have_tar?
|
96
|
-
if @@tar_bin == false
|
97
|
-
@@tar_bin = find_bin "tar"
|
98
|
-
end
|
99
|
-
!@@tar_bin.nil?
|
100
|
-
end
|
101
|
-
def pathes
|
102
|
-
path = ENV[on_windows? ? "Path" : "PATH"]
|
103
|
-
return [] unless path
|
104
|
-
path.split(on_windows? ? ";" : ":")
|
105
|
-
end
|
106
|
-
def find_bin bin_name
|
107
|
-
if on_windows?
|
108
|
-
bin_name_exe = nil
|
109
|
-
if bin_name !~ /\.[^\.]{1,3}$/i
|
110
|
-
bin_name_exe = bin_name + ".exe"
|
111
|
-
end
|
112
|
-
pathes.each { |dir|
|
113
|
-
file = File.join(dir, bin_name)
|
114
|
-
return file if test(?f, file)
|
115
|
-
if bin_name_exe
|
116
|
-
file = File.join(dir, bin_name_exe)
|
117
|
-
return file if test(?f, file)
|
118
|
-
end
|
119
|
-
}
|
120
|
-
else
|
121
|
-
pathes.each { |dir|
|
122
|
-
file = File.join(dir, bin_name)
|
123
|
-
return file if test(?x, file)
|
124
|
-
}
|
125
|
-
end
|
126
|
-
nil
|
127
|
-
end
|
128
|
-
def shell_path path
|
129
|
-
if on_windows?
|
130
|
-
path = path.tr("/", "\\")
|
131
|
-
if path.include? ' '
|
132
|
-
'"' + path + '"'
|
133
|
-
else
|
134
|
-
path
|
135
|
-
end
|
136
|
-
else
|
137
|
-
if path.include? ' '
|
138
|
-
"'" + path + "'"
|
139
|
-
else
|
140
|
-
path
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
extend self
|
145
|
-
end # module Env
|
146
|
-
|
147
|
-
module Sys
|
148
|
-
def sp(arg)
|
149
|
-
if arg.respond_to? :to_ary
|
150
|
-
arg.to_ary.map{ |e| sp e }.join(' ')
|
151
|
-
else
|
152
|
-
_escaped_path arg
|
153
|
-
end
|
154
|
-
end
|
155
|
-
def escape(arg)
|
156
|
-
if arg.respond_to? :to_ary
|
157
|
-
arg.to_ary.map{ |e| escape e }.join(' ')
|
158
|
-
else
|
159
|
-
_escaped arg
|
160
|
-
end
|
161
|
-
end
|
162
|
-
if Env.on_windows?
|
163
|
-
def _escaped_path(path)
|
164
|
-
_escaped(path.to_s.tr("/", "\\"))
|
165
|
-
end
|
166
|
-
def _escaped(arg)
|
167
|
-
sarg = arg.to_s
|
168
|
-
return sarg unless sarg.include?(" ")
|
169
|
-
sarg << "\\" if sarg[-1].chr == "\\"
|
170
|
-
"\"#{sarg}\""
|
171
|
-
end
|
172
|
-
def regular_filename(fn)
|
173
|
-
fn.to_str.tr("\\", "/").gsub(%r{/{2,}}, "/")
|
174
|
-
end
|
175
|
-
else
|
176
|
-
def _escaped_path(path)
|
177
|
-
path.to_s.gsub(/(?=\s)/, "\\")
|
178
|
-
end
|
179
|
-
alias _escaped _escaped_path
|
180
|
-
def regular_filename(fn)
|
181
|
-
fn.to_str.gsub(%r{/{2,}}, "/")
|
182
|
-
end
|
183
|
-
end
|
184
|
-
private :_escaped_path
|
185
|
-
private :_escaped
|
186
|
-
def split_all(path)
|
187
|
-
names = regular_filename(path).split(%r{/})
|
188
|
-
names[0] = "/" if names[0] && names[0].empty?
|
189
|
-
names
|
190
|
-
end
|
191
|
-
extend self
|
192
|
-
end # module Sys
|
193
|
-
|
194
|
-
|
195
|
-
ROOT_RANTFILE = "root.rant"
|
196
|
-
SUB_RANTFILE = "sub.rant"
|
197
|
-
RANTFILES = [ "Rantfile", "rantfile", ROOT_RANTFILE ]
|
198
|
-
|
199
|
-
CODE_IMPORTS = []
|
200
|
-
|
201
|
-
class RantAbortException < StandardError
|
202
|
-
end
|
203
|
-
|
204
|
-
class RantDoneException < StandardError
|
205
|
-
end
|
206
|
-
|
207
|
-
class Error < StandardError
|
208
|
-
end
|
209
|
-
|
210
|
-
module Generators
|
211
|
-
end
|
212
|
-
|
213
|
-
module RantVar
|
214
|
-
|
215
|
-
class Error < Rant::Error
|
216
|
-
end
|
217
|
-
|
218
|
-
class ConstraintError < Error
|
219
|
-
|
220
|
-
attr_reader :constraint, :val
|
221
|
-
|
222
|
-
def initialize(constraint, val, msg = nil)
|
223
|
-
@msg = msg
|
224
|
-
@constraint = constraint
|
225
|
-
@val = val
|
226
|
-
end
|
227
|
-
|
228
|
-
def message
|
229
|
-
val_desc = @val.inspect
|
230
|
-
val_desc[7..-1] = "..." if val_desc.length > 10
|
231
|
-
"#{val_desc} doesn't match constraint: #@constraint"
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
class NotAConstraintFactoryError < Error
|
236
|
-
attr_reader :obj
|
237
|
-
def initialize(obj, msg = nil)
|
238
|
-
@msg = msg
|
239
|
-
@obj = obj
|
240
|
-
end
|
241
|
-
def message
|
242
|
-
obj_desc = @obj.inspect
|
243
|
-
obj_desc[7..-1] = "..." if obj_desc.length > 10
|
244
|
-
"#{obj_desc} is not a valid constraint factory"
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
class InvalidVidError < Error
|
249
|
-
def initialize(vid, msg = nil)
|
250
|
-
@msg = msg
|
251
|
-
@vid = vid
|
252
|
-
end
|
253
|
-
def message
|
254
|
-
vid_desc = @vid.inspect
|
255
|
-
vid_desc[7..-1] = "..." if vid_desc.length > 10
|
256
|
-
"#{vid_desc} is not a valid var identifier"
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
class InvalidConstraintError < Error
|
261
|
-
end
|
262
|
-
|
263
|
-
class QueryError < Error
|
264
|
-
end
|
265
|
-
|
266
|
-
class Space
|
267
|
-
|
268
|
-
@@env_ref = Object.new
|
269
|
-
|
270
|
-
def initialize
|
271
|
-
@store = {}
|
272
|
-
@constraints = {}
|
273
|
-
end
|
274
|
-
|
275
|
-
def query(*args, &block)
|
276
|
-
case args.size
|
277
|
-
when 0
|
278
|
-
raise QueryError, "no arguments", caller
|
279
|
-
when 1
|
280
|
-
arg = args.first
|
281
|
-
if Hash === arg
|
282
|
-
if arg.size == 1
|
283
|
-
arg.each { |k,v|
|
284
|
-
self[k] = v if self[k].nil?
|
285
|
-
}
|
286
|
-
self
|
287
|
-
else
|
288
|
-
init_all arg
|
289
|
-
end
|
290
|
-
else
|
291
|
-
self[arg]
|
292
|
-
end
|
293
|
-
when 2, 3
|
294
|
-
vid, cf, val = *args
|
295
|
-
constrain vid,
|
296
|
-
get_factory(cf).rant_constraint
|
297
|
-
self[vid] = val if val
|
298
|
-
else
|
299
|
-
raise QueryError, "too many arguments"
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
def restrict vid, ct, *ct_args
|
304
|
-
if vid.respond_to? :to_ary
|
305
|
-
vid.to_ary.each { |v| restrict(v, ct, *ct_args) }
|
306
|
-
else
|
307
|
-
constrain vid,
|
308
|
-
get_factory(ct).rant_constraint(*ct_args)
|
309
|
-
end
|
310
|
-
self
|
311
|
-
end
|
312
|
-
|
313
|
-
def get_factory id
|
314
|
-
if String === id || Symbol === id
|
315
|
-
id = Constraints.const_get(id) rescue nil
|
316
|
-
end
|
317
|
-
unless id.respond_to? :rant_constraint
|
318
|
-
raise NotAConstraintFactoryError.new(id), caller
|
319
|
-
end
|
320
|
-
id
|
321
|
-
end
|
322
|
-
private :get_factory
|
323
|
-
|
324
|
-
def [](vid)
|
325
|
-
vid = RantVar.valid_vid vid
|
326
|
-
val = @store[vid]
|
327
|
-
val.equal?(@@env_ref) ? ENV[vid] : val
|
328
|
-
end
|
329
|
-
|
330
|
-
def []=(vid, val)
|
331
|
-
vid = RantVar.valid_vid(vid)
|
332
|
-
c = @constraints[vid]
|
333
|
-
if @store[vid] == @@env_ref
|
334
|
-
ENV[vid] = c ? c.filter(val) : val
|
335
|
-
else
|
336
|
-
@store[vid] = c ? c.filter(val) : val
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
|
-
def env(*vars)
|
341
|
-
vars.flatten.each { |var|
|
342
|
-
vid = RantVar.valid_vid(var)
|
343
|
-
cur_val = @store[vid]
|
344
|
-
next if cur_val == @@env_ref
|
345
|
-
ENV[vid] = cur_val unless cur_val.nil?
|
346
|
-
@store[vid] = @@env_ref
|
347
|
-
}
|
348
|
-
nil
|
349
|
-
end
|
350
|
-
|
351
|
-
def set_all hash
|
352
|
-
unless Hash === hash
|
353
|
-
raise QueryError,
|
354
|
-
"set_all argument has to be a hash"
|
355
|
-
end
|
356
|
-
hash.each_pair { |k, v|
|
357
|
-
self[k] = v
|
358
|
-
}
|
359
|
-
end
|
360
|
-
|
361
|
-
def init_all hash
|
362
|
-
unless Hash === hash
|
363
|
-
raise QueryError,
|
364
|
-
"init_all argument has to be a hash"
|
365
|
-
end
|
366
|
-
hash.each_pair { |k, v|
|
367
|
-
self[k] = v if self[k].nil?
|
368
|
-
}
|
369
|
-
end
|
370
|
-
|
371
|
-
def constrain vid, constraint
|
372
|
-
vid = RantVar.valid_vid(vid)
|
373
|
-
unless RantVar.valid_constraint? constraint
|
374
|
-
raise InvalidConstraintError, constraint
|
375
|
-
end
|
376
|
-
@constraints[vid] = constraint
|
377
|
-
if @store.member? vid
|
378
|
-
begin
|
379
|
-
val = @store[vid]
|
380
|
-
@store[vid] = constraint.filter(@store[vid])
|
381
|
-
rescue
|
382
|
-
@store[vid] = constraint.default
|
383
|
-
raise ConstraintError.new(constraint, val)
|
384
|
-
end
|
385
|
-
else
|
386
|
-
@store[vid] = constraint.default
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
def has_var?(vid)
|
391
|
-
!self[vid].nil?
|
392
|
-
end
|
393
|
-
|
394
|
-
def _set(vid, val) #:nodoc:
|
395
|
-
@store[vid] = val
|
396
|
-
end
|
397
|
-
|
398
|
-
def _get(vid) #:nodoc:
|
399
|
-
@store[vid]
|
400
|
-
end
|
401
|
-
|
402
|
-
def _init(vid, val) #:nodoc:
|
403
|
-
@store[vid] ||= val
|
404
|
-
end
|
405
|
-
|
406
|
-
end # class Space
|
407
|
-
|
408
|
-
module Constraint
|
409
|
-
def matches? val
|
410
|
-
filter val
|
411
|
-
true
|
412
|
-
rescue
|
413
|
-
return false
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
def valid_vid(obj)
|
418
|
-
case obj
|
419
|
-
when String: obj
|
420
|
-
when Symbol: obj.to_s
|
421
|
-
else
|
422
|
-
if obj.respond_to? :to_str
|
423
|
-
obj.to_str
|
424
|
-
else
|
425
|
-
raise InvalidVidError.new(obj)
|
426
|
-
end
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
def valid_constraint?(obj)
|
431
|
-
obj.respond_to?(:filter) &&
|
432
|
-
obj.respond_to?(:matches?) &&
|
433
|
-
obj.respond_to?(:default)
|
434
|
-
end
|
435
|
-
|
436
|
-
module_function :valid_constraint?, :valid_vid
|
437
|
-
|
438
|
-
module Constraints
|
439
|
-
class AutoList
|
440
|
-
include Constraint
|
441
|
-
class << self
|
442
|
-
alias rant_constraint new
|
443
|
-
end
|
444
|
-
def filter(val)
|
445
|
-
if val.respond_to? :to_ary
|
446
|
-
val.to_ary
|
447
|
-
elsif val.nil?
|
448
|
-
raise ConstraintError.new(self, val)
|
449
|
-
else
|
450
|
-
[val]
|
451
|
-
end
|
452
|
-
end
|
453
|
-
def default
|
454
|
-
[]
|
455
|
-
end
|
456
|
-
def to_s
|
457
|
-
"list or single, non-nil value"
|
458
|
-
end
|
459
|
-
end
|
460
|
-
end # module Constraints
|
461
|
-
end # module RantVar
|
462
|
-
end # module Rant
|
463
|
-
|
464
|
-
|
465
|
-
require 'fileutils'
|
466
|
-
|
467
|
-
|
468
|
-
module Rant
|
469
|
-
def FileList(arg)
|
470
|
-
if arg.respond_to?(:to_rant_filelist)
|
471
|
-
arg.to_rant_filelist
|
472
|
-
elsif arg.respond_to?(:to_ary)
|
473
|
-
FileList.new(arg.to_ary)
|
474
|
-
else
|
475
|
-
raise TypeError,
|
476
|
-
"cannot convert #{arg.class} into Rant::FileList"
|
477
|
-
end
|
478
|
-
end
|
479
|
-
module_function :FileList
|
480
|
-
class FileList
|
481
|
-
include Enumerable
|
482
|
-
|
483
|
-
ESC_SEPARATOR = Regexp.escape(File::SEPARATOR)
|
484
|
-
ESC_ALT_SEPARATOR = File::ALT_SEPARATOR ?
|
485
|
-
Regexp.escape(File::ALT_SEPARATOR) : nil
|
486
|
-
|
487
|
-
class << self
|
488
|
-
def [](*patterns)
|
489
|
-
new.hide_dotfiles.include(*patterns)
|
490
|
-
end
|
491
|
-
def glob(*patterns)
|
492
|
-
fl = new.hide_dotfiles.ignore(".", "..").include(*patterns)
|
493
|
-
if block_given? then yield fl else fl end
|
494
|
-
end
|
495
|
-
def glob_all(*patterns)
|
496
|
-
fl = new.ignore(".", "..").include(*patterns)
|
497
|
-
if block_given? then yield fl else fl end
|
498
|
-
end
|
499
|
-
end
|
500
|
-
|
501
|
-
def initialize(store = [])
|
502
|
-
@pending = false
|
503
|
-
@def_glob_dotfiles = true
|
504
|
-
@items = store
|
505
|
-
@ignore_rx = nil
|
506
|
-
@keep = {}
|
507
|
-
@actions = []
|
508
|
-
end
|
509
|
-
alias _object_dup dup
|
510
|
-
private :_object_dup
|
511
|
-
def dup
|
512
|
-
c = _object_dup
|
513
|
-
c.items = @items.dup
|
514
|
-
c.actions = @actions.dup
|
515
|
-
c.ignore_rx = @ignore_rx.dup if @ignore_rx
|
516
|
-
c.instance_variable_set(:@keep, @keep.dup)
|
517
|
-
c
|
518
|
-
end
|
519
|
-
def copy
|
520
|
-
c = _object_dup
|
521
|
-
c.items = @items.map { |entry| entry.dup }
|
522
|
-
c.actions = @actions.dup
|
523
|
-
c.ignore_rx = @ignore_rx.dup if @ignore_rx
|
524
|
-
h_keep = {}
|
525
|
-
@keep.each_key { |entry| h_keep[entry] = true }
|
526
|
-
c.instance_variable_set(:@keep, h_keep)
|
527
|
-
c
|
528
|
-
end
|
529
|
-
def glob_dotfiles?
|
530
|
-
@def_glob_dotfiles
|
531
|
-
end
|
532
|
-
def glob_dotfiles=(flag)
|
533
|
-
@def_glob_dotfiles = flag ? true : false
|
534
|
-
end
|
535
|
-
def hide_dotfiles
|
536
|
-
@def_glob_dotfiles = false
|
537
|
-
self
|
538
|
-
end
|
539
|
-
def glob_dotfiles
|
540
|
-
@def_glob_dotfiles = true
|
541
|
-
self
|
542
|
-
end
|
543
|
-
|
544
|
-
protected
|
545
|
-
attr_accessor :actions, :items
|
546
|
-
attr_accessor :pending
|
547
|
-
attr_accessor :ignore_rx
|
548
|
-
|
549
|
-
public
|
550
|
-
def each(&block)
|
551
|
-
resolve if @pending
|
552
|
-
@items.each(&block)
|
553
|
-
self
|
554
|
-
end
|
555
|
-
def to_ary
|
556
|
-
resolve if @pending
|
557
|
-
@items
|
558
|
-
end
|
559
|
-
alias to_a to_ary
|
560
|
-
alias entries to_ary # entries: defined in Enumerable
|
561
|
-
def to_rant_filelist
|
562
|
-
self
|
563
|
-
end
|
564
|
-
def +(other)
|
565
|
-
if other.respond_to? :to_rant_filelist
|
566
|
-
c = other.to_rant_filelist.dup
|
567
|
-
c.actions.concat(@actions)
|
568
|
-
c.items.concat(@items)
|
569
|
-
c.pending = !c.actions.empty?
|
570
|
-
c
|
571
|
-
elsif other.respond_to? :to_ary
|
572
|
-
c = dup
|
573
|
-
c.actions <<
|
574
|
-
[:apply_ary_method_1, :concat, other.to_ary.dup]
|
575
|
-
c.pending = true
|
576
|
-
c
|
577
|
-
else
|
578
|
-
raise TypeError,
|
579
|
-
"cannot add #{other.class} to Rant::FileList"
|
580
|
-
end
|
581
|
-
end
|
582
|
-
def <<(file)
|
583
|
-
@actions << [:apply_ary_method_1, :push, file]
|
584
|
-
@keep[file] = true
|
585
|
-
@pending = true
|
586
|
-
self
|
587
|
-
end
|
588
|
-
def keep(entry)
|
589
|
-
@keep[entry] = true
|
590
|
-
@items << entry
|
591
|
-
self
|
592
|
-
end
|
593
|
-
def concat(ary)
|
594
|
-
if @pending
|
595
|
-
ary = ary.to_ary.dup
|
596
|
-
@actions << [:apply_ary_method_1, :concat, ary]
|
597
|
-
else
|
598
|
-
ix = ignore_rx and ary = ary.to_ary.reject { |f| f =~ ix }
|
599
|
-
@items.concat(ary)
|
600
|
-
end
|
601
|
-
self
|
602
|
-
end
|
603
|
-
def size
|
604
|
-
resolve if @pending
|
605
|
-
@items.size
|
606
|
-
end
|
607
|
-
alias length size
|
608
|
-
def empty?
|
609
|
-
resolve if @pending
|
610
|
-
@items.empty?
|
611
|
-
end
|
612
|
-
def join(sep = ' ')
|
613
|
-
resolve if @pending
|
614
|
-
@items.join(sep)
|
615
|
-
end
|
616
|
-
def pop
|
617
|
-
resolve if @pending
|
618
|
-
@items.pop
|
619
|
-
end
|
620
|
-
def push(entry)
|
621
|
-
resolve if @pending
|
622
|
-
@items.push(entry) if entry !~ ignore_rx
|
623
|
-
self
|
624
|
-
end
|
625
|
-
def shift
|
626
|
-
resolve if @pending
|
627
|
-
@items.shift
|
628
|
-
end
|
629
|
-
def unshift(entry)
|
630
|
-
resolve if @pending
|
631
|
-
@items.unshift(entry) if entry !~ ignore_rx
|
632
|
-
self
|
633
|
-
end
|
634
|
-
if Object.method_defined?(:fcall) || Object.method_defined?(:funcall) # in Ruby 1.9 like __send__
|
635
|
-
@@__send_private__ = Object.method_defined?(:fcall) ? :fcall : :funcall
|
636
|
-
def resolve
|
637
|
-
@pending = false
|
638
|
-
@actions.each{ |action| self.__send__(@@__send_private__, *action) }.clear
|
639
|
-
ix = ignore_rx
|
640
|
-
if ix
|
641
|
-
@items.reject! { |f| f =~ ix && !@keep[f] }
|
642
|
-
end
|
643
|
-
self
|
644
|
-
end
|
645
|
-
else
|
646
|
-
def resolve
|
647
|
-
@pending = false
|
648
|
-
@actions.each{ |action| self.__send__(*action) }.clear
|
649
|
-
ix = ignore_rx
|
650
|
-
if ix
|
651
|
-
@items.reject! { |f| f =~ ix && !@keep[f] }
|
652
|
-
end
|
653
|
-
self
|
654
|
-
end
|
655
|
-
end
|
656
|
-
def include(*pats)
|
657
|
-
@def_glob_dotfiles ? glob_all(*pats) : glob_unix(*pats)
|
658
|
-
end
|
659
|
-
alias glob include
|
660
|
-
def glob_unix(*patterns)
|
661
|
-
patterns.flatten.each { |pat|
|
662
|
-
@actions << [:apply_glob_unix, pat]
|
663
|
-
}
|
664
|
-
@pending = true
|
665
|
-
self
|
666
|
-
end
|
667
|
-
def glob_all(*patterns)
|
668
|
-
patterns.flatten.each { |pat|
|
669
|
-
@actions << [:apply_glob_all, pat]
|
670
|
-
}
|
671
|
-
@pending = true
|
672
|
-
self
|
673
|
-
end
|
674
|
-
if RUBY_VERSION < "1.8.2"
|
675
|
-
FN_DOTFILE_RX_ = ESC_ALT_SEPARATOR ?
|
676
|
-
/(^|(#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+)\..*
|
677
|
-
((#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+|$)/x :
|
678
|
-
/(^|#{ESC_SEPARATOR}+)\..* (#{ESC_SEPARATOR}+|$)/x
|
679
|
-
def apply_glob_unix(pattern)
|
680
|
-
inc_files = Dir.glob(pattern)
|
681
|
-
unless pattern =~ /(^|\/)\./
|
682
|
-
inc_files.reject! { |fn| fn =~ FN_DOTFILE_RX_ }
|
683
|
-
end
|
684
|
-
@items.concat(inc_files)
|
685
|
-
end
|
686
|
-
else
|
687
|
-
def apply_glob_unix(pattern)
|
688
|
-
@items.concat(Dir.glob(pattern))
|
689
|
-
end
|
690
|
-
end
|
691
|
-
private :apply_glob_unix
|
692
|
-
def apply_glob_all(pattern)
|
693
|
-
@items.concat(Dir.glob(pattern, File::FNM_DOTMATCH))
|
694
|
-
end
|
695
|
-
private :apply_glob_all
|
696
|
-
def exclude(*patterns)
|
697
|
-
patterns.each { |pat|
|
698
|
-
if Regexp === pat
|
699
|
-
@actions << [:apply_exclude_rx, pat]
|
700
|
-
else
|
701
|
-
@actions << [:apply_exclude, pat]
|
702
|
-
end
|
703
|
-
}
|
704
|
-
@pending = true
|
705
|
-
self
|
706
|
-
end
|
707
|
-
def ignore(*patterns)
|
708
|
-
patterns.each { |pat|
|
709
|
-
add_ignore_rx(Regexp === pat ? pat : mk_all_rx(pat))
|
710
|
-
}
|
711
|
-
@pending = true
|
712
|
-
self
|
713
|
-
end
|
714
|
-
def add_ignore_rx(rx)
|
715
|
-
@ignore_rx =
|
716
|
-
if @ignore_rx
|
717
|
-
Regexp.union(@ignore_rx, rx)
|
718
|
-
else
|
719
|
-
rx
|
720
|
-
end
|
721
|
-
end
|
722
|
-
private :add_ignore_rx
|
723
|
-
def apply_exclude(pattern)
|
724
|
-
@items.reject! { |elem|
|
725
|
-
File.fnmatch?(pattern, elem, File::FNM_DOTMATCH) && !@keep[elem]
|
726
|
-
}
|
727
|
-
end
|
728
|
-
private :apply_exclude
|
729
|
-
def apply_exclude_rx(rx)
|
730
|
-
@items.reject! { |elem|
|
731
|
-
elem =~ rx && !@keep[elem]
|
732
|
-
}
|
733
|
-
end
|
734
|
-
private :apply_exclude_rx
|
735
|
-
def exclude_name(*names)
|
736
|
-
names.each { |name|
|
737
|
-
@actions << [:apply_exclude_rx, mk_all_rx(name)]
|
738
|
-
}
|
739
|
-
@pending = true
|
740
|
-
self
|
741
|
-
end
|
742
|
-
alias shun exclude_name
|
743
|
-
if File::ALT_SEPARATOR
|
744
|
-
def mk_all_rx(file)
|
745
|
-
/(^|(#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+)#{Regexp.escape(file)}
|
746
|
-
((#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+|$)/x
|
747
|
-
end
|
748
|
-
else
|
749
|
-
def mk_all_rx(file)
|
750
|
-
/(^|#{ESC_SEPARATOR}+)#{Regexp.escape(file)}
|
751
|
-
(#{ESC_SEPARATOR}+|$)/x
|
752
|
-
end
|
753
|
-
end
|
754
|
-
private :mk_all_rx
|
755
|
-
def exclude_path(*patterns)
|
756
|
-
patterns.each { |pat|
|
757
|
-
@actions << [:apply_exclude_path, pat]
|
758
|
-
}
|
759
|
-
@pending = true
|
760
|
-
self
|
761
|
-
end
|
762
|
-
def apply_exclude_path(pattern)
|
763
|
-
flags = File::FNM_DOTMATCH|File::FNM_PATHNAME
|
764
|
-
@items.reject! { |elem|
|
765
|
-
File.fnmatch?(pattern, elem, flags) && !@keep[elem]
|
766
|
-
}
|
767
|
-
end
|
768
|
-
private :apply_exclude
|
769
|
-
def select(&block)
|
770
|
-
d = dup
|
771
|
-
d.actions << [:apply_select, block]
|
772
|
-
d.pending = true
|
773
|
-
d
|
774
|
-
end
|
775
|
-
alias find_all select
|
776
|
-
def apply_select blk
|
777
|
-
@items = @items.select(&blk)
|
778
|
-
end
|
779
|
-
private :apply_select
|
780
|
-
def map(&block)
|
781
|
-
d = dup
|
782
|
-
d.actions << [:apply_ary_method, :map!, block]
|
783
|
-
d.pending = true
|
784
|
-
d
|
785
|
-
end
|
786
|
-
alias collect map
|
787
|
-
def sub_ext(ext, new_ext=nil)
|
788
|
-
map { |f| f._rant_sub_ext ext, new_ext }
|
789
|
-
end
|
790
|
-
def ext(ext_str)
|
791
|
-
sub_ext(ext_str)
|
792
|
-
end
|
793
|
-
def arglist
|
794
|
-
Rant::Sys.sp to_ary
|
795
|
-
end
|
796
|
-
alias to_s arglist
|
797
|
-
alias object_inspect inspect
|
798
|
-
def uniq!
|
799
|
-
@actions << [:apply_ary_method, :uniq!]
|
800
|
-
@pending = true
|
801
|
-
self
|
802
|
-
end
|
803
|
-
def sort!
|
804
|
-
@actions << [:apply_ary_method, :sort!]
|
805
|
-
@pending = true
|
806
|
-
self
|
807
|
-
end
|
808
|
-
def map!(&block)
|
809
|
-
@actions << [:apply_ary_method, :map!, block]
|
810
|
-
@pending = true
|
811
|
-
self
|
812
|
-
end
|
813
|
-
def reject!(&block)
|
814
|
-
@actions << [:apply_ary_method, :reject!, block]
|
815
|
-
@pending = true
|
816
|
-
self
|
817
|
-
end
|
818
|
-
private
|
819
|
-
def apply_ary_method(meth, block=nil)
|
820
|
-
@items.send meth, &block
|
821
|
-
end
|
822
|
-
def apply_ary_method_1(meth, arg1, block=nil)
|
823
|
-
@items.send meth, arg1, &block
|
824
|
-
end
|
825
|
-
end # class FileList
|
826
|
-
end # module Rant
|
827
|
-
|
828
|
-
if RUBY_VERSION == "1.8.3"
|
829
|
-
module FileUtils
|
830
|
-
METHODS = singleton_methods - %w(private_module_function
|
831
|
-
commands options have_option? options_of collect_method)
|
832
|
-
module Verbose
|
833
|
-
class << self
|
834
|
-
public(*::FileUtils::METHODS)
|
835
|
-
end
|
836
|
-
public(*::FileUtils::METHODS)
|
837
|
-
end
|
838
|
-
end
|
839
|
-
end
|
840
|
-
|
841
|
-
if RUBY_VERSION < "1.8.1"
|
842
|
-
module FileUtils
|
843
|
-
undef_method :fu_list
|
844
|
-
def fu_list(arg)
|
845
|
-
arg.respond_to?(:to_ary) ? arg.to_ary : [arg]
|
846
|
-
end
|
847
|
-
end
|
848
|
-
end
|
849
|
-
|
850
|
-
module Rant
|
851
|
-
class RacFileList < FileList
|
852
|
-
|
853
|
-
attr_reader :subdir
|
854
|
-
attr_reader :basedir
|
855
|
-
|
856
|
-
def initialize(rac, store = [])
|
857
|
-
super(store)
|
858
|
-
@rac = rac
|
859
|
-
@subdir = @rac.current_subdir
|
860
|
-
@basedir = Dir.pwd
|
861
|
-
@ignore_hash = nil
|
862
|
-
@add_ignore_args = []
|
863
|
-
update_ignore_rx
|
864
|
-
end
|
865
|
-
def dup
|
866
|
-
c = super
|
867
|
-
c.instance_variable_set(
|
868
|
-
:@add_ignore_args, @add_ignore_args.dup)
|
869
|
-
c
|
870
|
-
end
|
871
|
-
def copy
|
872
|
-
c = super
|
873
|
-
c.instance_variable_set(
|
874
|
-
:@add_ignore_args, @add_ignore_args.map { |e| e.dup })
|
875
|
-
c
|
876
|
-
end
|
877
|
-
alias filelist_ignore ignore
|
878
|
-
def ignore(*patterns)
|
879
|
-
@add_ignore_args.concat patterns
|
880
|
-
self
|
881
|
-
end
|
882
|
-
def ignore_rx
|
883
|
-
update_ignore_rx
|
884
|
-
@ignore_rx
|
885
|
-
end
|
886
|
-
alias filelist_resolve resolve
|
887
|
-
def resolve
|
888
|
-
Sys.cd(@basedir) { filelist_resolve }
|
889
|
-
end
|
890
|
-
def each_cd(&block)
|
891
|
-
old_pwd = Dir.pwd
|
892
|
-
Sys.cd(@basedir)
|
893
|
-
filelist_resolve if @pending
|
894
|
-
@items.each(&block)
|
895
|
-
ensure
|
896
|
-
Sys.cd(old_pwd)
|
897
|
-
end
|
898
|
-
private
|
899
|
-
def update_ignore_rx
|
900
|
-
ri = @rac.var[:ignore]
|
901
|
-
ri = ri ? (ri + @add_ignore_args) : @add_ignore_args
|
902
|
-
rh = ri.hash
|
903
|
-
unless rh == @ignore_hash
|
904
|
-
@ignore_rx = nil
|
905
|
-
filelist_ignore(*ri)
|
906
|
-
@ignore_hash = rh
|
907
|
-
end
|
908
|
-
end
|
909
|
-
end # class RacFileList
|
910
|
-
|
911
|
-
class MultiFileList
|
912
|
-
|
913
|
-
attr_reader :cur_list
|
914
|
-
|
915
|
-
def initialize(rac)
|
916
|
-
@rac = rac
|
917
|
-
@cur_list = RacFileList.new(@rac)
|
918
|
-
@lists = [@cur_list]
|
919
|
-
end
|
920
|
-
|
921
|
-
def each_entry(&block)
|
922
|
-
@lists.each { |list|
|
923
|
-
list.each_cd(&block)
|
924
|
-
}
|
925
|
-
end
|
926
|
-
|
927
|
-
def add(filelist)
|
928
|
-
@cur_list = filelist
|
929
|
-
@lists << filelist
|
930
|
-
self
|
931
|
-
end
|
932
|
-
|
933
|
-
def method_missing(sym, *args, &block)
|
934
|
-
if @cur_list && @cur_list.respond_to?(sym)
|
935
|
-
if @cur_list.subdir == @rac.current_subdir
|
936
|
-
@cur_list.send(sym, *args, &block)
|
937
|
-
else
|
938
|
-
add(RacFileList.new(@rac))
|
939
|
-
@cur_list.send(sym, *args, &block)
|
940
|
-
end
|
941
|
-
else
|
942
|
-
super
|
943
|
-
end
|
944
|
-
end
|
945
|
-
end # class MultiFileList
|
946
|
-
|
947
|
-
class CommandError < StandardError
|
948
|
-
attr_reader :cmd
|
949
|
-
attr_reader :status
|
950
|
-
def initialize(cmd, status=nil, msg=nil)
|
951
|
-
@msg = msg
|
952
|
-
@cmd = cmd
|
953
|
-
@status = status
|
954
|
-
end
|
955
|
-
def message
|
956
|
-
if !@msg && cmd
|
957
|
-
if status
|
958
|
-
"Command failed with status #{status.exitstatus}:\n" +
|
959
|
-
"[#{cmd}]"
|
960
|
-
else
|
961
|
-
"Command failed:\n[#{cmd}]"
|
962
|
-
end
|
963
|
-
else
|
964
|
-
@msg
|
965
|
-
end
|
966
|
-
end
|
967
|
-
end
|
968
|
-
|
969
|
-
module Sys
|
970
|
-
include ::FileUtils::Verbose
|
971
|
-
|
972
|
-
@symlink_supported = true
|
973
|
-
class << self
|
974
|
-
attr_accessor :symlink_supported
|
975
|
-
end
|
976
|
-
|
977
|
-
def fu_output_message(msg) #:nodoc:
|
978
|
-
end
|
979
|
-
private :fu_output_message
|
980
|
-
|
981
|
-
def fu_each_src_dest(src, *rest)
|
982
|
-
src = src.to_ary if src.respond_to? :to_ary
|
983
|
-
super(src, *rest)
|
984
|
-
end
|
985
|
-
private :fu_each_src_dest
|
986
|
-
|
987
|
-
def sh(*cmd_args, &block)
|
988
|
-
cmd_args.flatten!
|
989
|
-
cmd = cmd_args.join(" ")
|
990
|
-
fu_output_message cmd
|
991
|
-
success = system(*cmd_args)
|
992
|
-
if block_given?
|
993
|
-
block[$?]
|
994
|
-
elsif !success
|
995
|
-
raise CommandError.new(cmd, $?)
|
996
|
-
end
|
997
|
-
end
|
998
|
-
|
999
|
-
def ruby(*args, &block)
|
1000
|
-
if args.empty?
|
1001
|
-
sh(Env::RUBY_EXE, '', &block)
|
1002
|
-
else
|
1003
|
-
sh(args.unshift(Env::RUBY_EXE), &block)
|
1004
|
-
end
|
1005
|
-
end
|
1006
|
-
def cd(dir, &block)
|
1007
|
-
fu_output_message "cd #{dir}"
|
1008
|
-
orig_pwd = Dir.pwd
|
1009
|
-
Dir.chdir dir
|
1010
|
-
if block
|
1011
|
-
begin
|
1012
|
-
block.arity == 0 ? block.call : block.call(Dir.pwd)
|
1013
|
-
ensure
|
1014
|
-
fu_output_message "cd -"
|
1015
|
-
Dir.chdir orig_pwd
|
1016
|
-
end
|
1017
|
-
else
|
1018
|
-
self
|
1019
|
-
end
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
def safe_ln(src, dest)
|
1023
|
-
dest = dest.to_str
|
1024
|
-
src = src.respond_to?(:to_ary) ? src.to_ary : src.to_str
|
1025
|
-
unless Sys.symlink_supported
|
1026
|
-
cp(src, dest)
|
1027
|
-
else
|
1028
|
-
begin
|
1029
|
-
ln(src, dest)
|
1030
|
-
rescue Exception # SystemCallError # Errno::EOPNOTSUPP
|
1031
|
-
Sys.symlink_supported = false
|
1032
|
-
cp(src, dest)
|
1033
|
-
end
|
1034
|
-
end
|
1035
|
-
end
|
1036
|
-
|
1037
|
-
def ln_f(src, dest)
|
1038
|
-
ln(src, dest, :force => true)
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
def split_path(str)
|
1042
|
-
str.split(Env.on_windows? ? ";" : ":")
|
1043
|
-
end
|
1044
|
-
|
1045
|
-
if Env.on_windows?
|
1046
|
-
def root_dir?(path)
|
1047
|
-
path == "/" || path == "\\" ||
|
1048
|
-
path =~ %r{\A[a-zA-Z]+:(\\|/)\Z}
|
1049
|
-
end
|
1050
|
-
def absolute_path?(path)
|
1051
|
-
path =~ %r{\A([a-zA-Z]+:)?(/|\\)}
|
1052
|
-
end
|
1053
|
-
else
|
1054
|
-
def root_dir?(path)
|
1055
|
-
path == "/"
|
1056
|
-
end
|
1057
|
-
def absolute_path?(path)
|
1058
|
-
path =~ %r{\A/}
|
1059
|
-
end
|
1060
|
-
end
|
1061
|
-
|
1062
|
-
extend self
|
1063
|
-
|
1064
|
-
if RUBY_VERSION >= "1.8.4" # needed by 1.9.0, too
|
1065
|
-
class << self
|
1066
|
-
public(*::FileUtils::METHODS)
|
1067
|
-
end
|
1068
|
-
public(*::FileUtils::METHODS)
|
1069
|
-
end
|
1070
|
-
|
1071
|
-
end # module Sys
|
1072
|
-
|
1073
|
-
class SysObject
|
1074
|
-
include Sys
|
1075
|
-
def initialize(rant)
|
1076
|
-
@rant = rant or
|
1077
|
-
raise ArgumentError, "rant application required"
|
1078
|
-
end
|
1079
|
-
def ignore(*patterns)
|
1080
|
-
@rant.var[:ignore].concat(patterns)
|
1081
|
-
nil
|
1082
|
-
end
|
1083
|
-
def filelist(arg = Rant.__rant_no_value__)
|
1084
|
-
if Rant.__rant_no_value__.equal?(arg)
|
1085
|
-
RacFileList.new(@rant)
|
1086
|
-
elsif arg.respond_to?(:to_rant_filelist)
|
1087
|
-
arg.to_rant_filelist
|
1088
|
-
elsif arg.respond_to?(:to_ary)
|
1089
|
-
RacFileList.new(@rant, arg.to_ary)
|
1090
|
-
else
|
1091
|
-
raise TypeError,
|
1092
|
-
"cannot convert #{arg.class} into Rant::FileList"
|
1093
|
-
end
|
1094
|
-
end
|
1095
|
-
def [](*patterns)
|
1096
|
-
RacFileList.new(@rant).hide_dotfiles.include(*patterns)
|
1097
|
-
end
|
1098
|
-
def glob(*patterns, &block)
|
1099
|
-
fl = RacFileList.new(@rant).hide_dotfiles.include(*patterns)
|
1100
|
-
fl.ignore(".", "..")
|
1101
|
-
if block_given? then yield fl else fl end
|
1102
|
-
end
|
1103
|
-
def glob_all(*patterns, &block)
|
1104
|
-
fl = RacFileList.new(@rant).include(*patterns)
|
1105
|
-
fl.ignore(".", "..") # use case: "*.*" as pattern
|
1106
|
-
if block_given? then yield fl else fl end
|
1107
|
-
end
|
1108
|
-
def expand_path(path)
|
1109
|
-
File.expand_path(@rant.project_to_fs_path(path))
|
1110
|
-
end
|
1111
|
-
private
|
1112
|
-
def fu_output_message(cmd)
|
1113
|
-
@rant.cmd_msg cmd
|
1114
|
-
end
|
1115
|
-
end
|
1116
|
-
|
1117
|
-
|
1118
|
-
class TaskFail < StandardError
|
1119
|
-
def initialize(task, orig, msg)
|
1120
|
-
@task = task
|
1121
|
-
@orig = orig
|
1122
|
-
@msg = msg
|
1123
|
-
end
|
1124
|
-
def exception
|
1125
|
-
self
|
1126
|
-
end
|
1127
|
-
def task
|
1128
|
-
@task
|
1129
|
-
end
|
1130
|
-
def tname
|
1131
|
-
@task ? @task.name : nil
|
1132
|
-
end
|
1133
|
-
def orig
|
1134
|
-
@orig
|
1135
|
-
end
|
1136
|
-
def msg
|
1137
|
-
@msg
|
1138
|
-
end
|
1139
|
-
end
|
1140
|
-
|
1141
|
-
class Rantfile
|
1142
|
-
attr_reader :tasks, :path
|
1143
|
-
attr_accessor :project_subdir
|
1144
|
-
def initialize(path)
|
1145
|
-
@path = path or raise ArgumentError, "path required"
|
1146
|
-
@tasks = []
|
1147
|
-
@project_subdir = nil
|
1148
|
-
end
|
1149
|
-
alias to_s path
|
1150
|
-
alias to_str path
|
1151
|
-
end # class Rantfile
|
1152
|
-
|
1153
|
-
module Node
|
1154
|
-
|
1155
|
-
INVOKE_OPT = {}.freeze
|
1156
|
-
|
1157
|
-
T0 = Time.at(0).freeze
|
1158
|
-
|
1159
|
-
attr_reader :name
|
1160
|
-
attr_reader :rac
|
1161
|
-
attr_accessor :description
|
1162
|
-
attr_accessor :rantfile
|
1163
|
-
attr_accessor :line_number
|
1164
|
-
attr_accessor :project_subdir
|
1165
|
-
|
1166
|
-
def initialize
|
1167
|
-
@description = nil
|
1168
|
-
@rantfile = nil
|
1169
|
-
@line_number = nil
|
1170
|
-
@run = false
|
1171
|
-
@project_subdir = ""
|
1172
|
-
@success = nil
|
1173
|
-
end
|
1174
|
-
|
1175
|
-
def reference_name
|
1176
|
-
sd = rac.current_subdir
|
1177
|
-
case sd
|
1178
|
-
when "": full_name
|
1179
|
-
when project_subdir: name
|
1180
|
-
else "@#{full_name}".sub(/^@#{Regexp.escape sd}\//, '')
|
1181
|
-
end
|
1182
|
-
end
|
1183
|
-
|
1184
|
-
alias to_s reference_name
|
1185
|
-
alias to_rant_target name
|
1186
|
-
|
1187
|
-
def full_name
|
1188
|
-
sd = project_subdir
|
1189
|
-
sd.empty? ? name : File.join(sd, name)
|
1190
|
-
end
|
1191
|
-
|
1192
|
-
def ch
|
1193
|
-
{:file => rantfile.to_str, :ln => line_number}
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
def goto_task_home
|
1197
|
-
@rac.goto_project_dir project_subdir
|
1198
|
-
end
|
1199
|
-
|
1200
|
-
def file_target?
|
1201
|
-
false
|
1202
|
-
end
|
1203
|
-
|
1204
|
-
def done?
|
1205
|
-
@success
|
1206
|
-
end
|
1207
|
-
|
1208
|
-
def needed?
|
1209
|
-
invoke(:needed? => true)
|
1210
|
-
end
|
1211
|
-
|
1212
|
-
def run?
|
1213
|
-
@run
|
1214
|
-
end
|
1215
|
-
|
1216
|
-
def invoke(opt = INVOKE_OPT)
|
1217
|
-
return circular_dep if run?
|
1218
|
-
@run = true
|
1219
|
-
begin
|
1220
|
-
return !done? if opt[:needed?]
|
1221
|
-
self.run if !done?
|
1222
|
-
@success = true
|
1223
|
-
ensure
|
1224
|
-
@run = false
|
1225
|
-
end
|
1226
|
-
end
|
1227
|
-
|
1228
|
-
def fail msg = nil, orig = nil
|
1229
|
-
raise TaskFail.new(self, orig, msg)
|
1230
|
-
end
|
1231
|
-
|
1232
|
-
def each_target
|
1233
|
-
end
|
1234
|
-
|
1235
|
-
def has_actions?
|
1236
|
-
defined? @block and @block
|
1237
|
-
end
|
1238
|
-
|
1239
|
-
def dry_run
|
1240
|
-
text = "Executing #{name.dump}"
|
1241
|
-
text << " [NOOP]" unless has_actions?
|
1242
|
-
@rac.cmd_msg text
|
1243
|
-
action_descs.each { |ad|
|
1244
|
-
@rac.cmd_print " - "
|
1245
|
-
@rac.cmd_msg ad.sub(/\n$/, '').gsub(/\n/, "\n ")
|
1246
|
-
}
|
1247
|
-
end
|
1248
|
-
|
1249
|
-
private
|
1250
|
-
def run
|
1251
|
-
goto_task_home
|
1252
|
-
return if @rac.running_task(self)
|
1253
|
-
return unless has_actions?
|
1254
|
-
@receiver.pre_run(self) if defined? @receiver and @receiver
|
1255
|
-
@block.arity == 0 ? @block.call : @block[self] if @block
|
1256
|
-
end
|
1257
|
-
|
1258
|
-
def action_descs
|
1259
|
-
descs = []
|
1260
|
-
if defined? @receiver and @receiver
|
1261
|
-
descs.concat(@receiver.pre_action_descs)
|
1262
|
-
end
|
1263
|
-
@block ? descs << action_block_desc : descs
|
1264
|
-
end
|
1265
|
-
|
1266
|
-
def action_block_desc
|
1267
|
-
@block.inspect =~ /^#<Proc:[\da-z]+@(.+):(\d+)>$/i
|
1268
|
-
fn, ln = $1, $2
|
1269
|
-
"Ruby Proc at #{fn.sub(/^#{Regexp.escape @rac.rootdir}\//, '')}:#{ln}"
|
1270
|
-
end
|
1271
|
-
|
1272
|
-
def circular_dep
|
1273
|
-
rac.warn_msg "Circular dependency on task `#{full_name}'."
|
1274
|
-
false
|
1275
|
-
end
|
1276
|
-
end # module Node
|
1277
|
-
|
1278
|
-
|
1279
|
-
def self.init_import_nodes__default(rac, *rest)
|
1280
|
-
rac.node_factory = DefaultNodeFactory.new
|
1281
|
-
end
|
1282
|
-
|
1283
|
-
class DefaultNodeFactory
|
1284
|
-
def new_task(rac, name, pre, blk)
|
1285
|
-
Task.new(rac, name, pre, &blk)
|
1286
|
-
end
|
1287
|
-
def new_file(rac, name, pre, blk)
|
1288
|
-
FileTask.new(rac, name, pre, &blk)
|
1289
|
-
end
|
1290
|
-
def new_dir(rac, name, pre, blk)
|
1291
|
-
DirTask.new(rac, name, pre, &blk)
|
1292
|
-
end
|
1293
|
-
def new_source(rac, name, pre, blk)
|
1294
|
-
SourceNode.new(rac, name, pre, &blk)
|
1295
|
-
end
|
1296
|
-
def new_custom(rac, name, pre, blk)
|
1297
|
-
UserTask.new(rac, name, pre, &blk)
|
1298
|
-
end
|
1299
|
-
def new_auto_subfile(rac, name, pre, blk)
|
1300
|
-
AutoSubFileTask.new(rac, name, pre, &blk)
|
1301
|
-
end
|
1302
|
-
end
|
1303
|
-
|
1304
|
-
class Task
|
1305
|
-
include Node
|
1306
|
-
|
1307
|
-
attr_accessor :receiver
|
1308
|
-
|
1309
|
-
def initialize(rac, name, prerequisites = [], &block)
|
1310
|
-
super()
|
1311
|
-
@rac = rac or raise ArgumentError, "rac not given"
|
1312
|
-
@name = name or raise ArgumentError, "name not given"
|
1313
|
-
@pre = prerequisites || []
|
1314
|
-
@pre_resolved = false
|
1315
|
-
@block = block
|
1316
|
-
@run = false
|
1317
|
-
@receiver = nil
|
1318
|
-
end
|
1319
|
-
|
1320
|
-
def prerequisites
|
1321
|
-
@pre.collect { |pre| pre.to_s }
|
1322
|
-
end
|
1323
|
-
alias deps prerequisites
|
1324
|
-
|
1325
|
-
def source
|
1326
|
-
@pre.first.to_s
|
1327
|
-
end
|
1328
|
-
|
1329
|
-
def has_actions?
|
1330
|
-
@block or @receiver && @receiver.has_pre_action?
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
def <<(pre)
|
1334
|
-
@pre_resolved = false
|
1335
|
-
@pre << pre
|
1336
|
-
end
|
1337
|
-
|
1338
|
-
def invoked?
|
1339
|
-
!@success.nil?
|
1340
|
-
end
|
1341
|
-
|
1342
|
-
def fail?
|
1343
|
-
@success == false
|
1344
|
-
end
|
1345
|
-
|
1346
|
-
def enhance(deps = nil, &blk)
|
1347
|
-
if deps
|
1348
|
-
@pre_resolved = false
|
1349
|
-
@pre.concat deps
|
1350
|
-
end
|
1351
|
-
if @block
|
1352
|
-
if blk
|
1353
|
-
first_block = @block
|
1354
|
-
@block = lambda { |t|
|
1355
|
-
first_block[t]
|
1356
|
-
blk[t]
|
1357
|
-
}
|
1358
|
-
end
|
1359
|
-
else
|
1360
|
-
@block = blk
|
1361
|
-
end
|
1362
|
-
end
|
1363
|
-
|
1364
|
-
def invoke(opt = INVOKE_OPT)
|
1365
|
-
return circular_dep if @run
|
1366
|
-
@run = true
|
1367
|
-
begin
|
1368
|
-
return if done?
|
1369
|
-
internal_invoke opt
|
1370
|
-
ensure
|
1371
|
-
@run = false
|
1372
|
-
end
|
1373
|
-
end
|
1374
|
-
|
1375
|
-
def internal_invoke(opt, ud_init = true)
|
1376
|
-
goto_task_home
|
1377
|
-
update = ud_init || opt[:force]
|
1378
|
-
dep = nil
|
1379
|
-
uf = false
|
1380
|
-
each_dep { |dep|
|
1381
|
-
if dep.respond_to? :timestamp
|
1382
|
-
handle_timestamped(dep, opt) && update = true
|
1383
|
-
elsif Node === dep
|
1384
|
-
handle_node(dep, opt) && update = true
|
1385
|
-
else
|
1386
|
-
dep, uf = handle_non_node(dep, opt)
|
1387
|
-
uf && update = true
|
1388
|
-
dep
|
1389
|
-
end
|
1390
|
-
}
|
1391
|
-
if @receiver
|
1392
|
-
goto_task_home
|
1393
|
-
update = true if @receiver.update?(self)
|
1394
|
-
end
|
1395
|
-
return update if opt[:needed?]
|
1396
|
-
run if update
|
1397
|
-
@success = true
|
1398
|
-
update
|
1399
|
-
rescue StandardError => e
|
1400
|
-
@success = false
|
1401
|
-
self.fail(nil, e)
|
1402
|
-
end
|
1403
|
-
private :internal_invoke
|
1404
|
-
|
1405
|
-
def handle_node(dep, opt)
|
1406
|
-
dep.invoke opt
|
1407
|
-
end
|
1408
|
-
|
1409
|
-
def handle_timestamped(dep, opt)
|
1410
|
-
dep.invoke opt
|
1411
|
-
end
|
1412
|
-
|
1413
|
-
def handle_non_node(dep, opt)
|
1414
|
-
@rac.err_msg "Unknown task `#{dep}',",
|
1415
|
-
"referenced in `#{rantfile.path}', line #{@line_number}!"
|
1416
|
-
self.fail
|
1417
|
-
end
|
1418
|
-
|
1419
|
-
def each_dep
|
1420
|
-
t = nil
|
1421
|
-
if @pre_resolved
|
1422
|
-
return @pre.each { |t| yield(t) }
|
1423
|
-
end
|
1424
|
-
my_full_name = full_name
|
1425
|
-
my_project_subdir = project_subdir
|
1426
|
-
@pre.map! { |t|
|
1427
|
-
if Node === t
|
1428
|
-
if t.full_name == my_full_name
|
1429
|
-
nil
|
1430
|
-
else
|
1431
|
-
yield(t)
|
1432
|
-
t
|
1433
|
-
end
|
1434
|
-
else
|
1435
|
-
t = t.to_s if Symbol === t
|
1436
|
-
if t == my_full_name #TODO
|
1437
|
-
nil
|
1438
|
-
else
|
1439
|
-
selection = @rac.resolve t,
|
1440
|
-
my_project_subdir
|
1441
|
-
if selection.empty?
|
1442
|
-
yield(t)
|
1443
|
-
else
|
1444
|
-
selection.each { |st| yield(st) }
|
1445
|
-
selection
|
1446
|
-
end
|
1447
|
-
end
|
1448
|
-
end
|
1449
|
-
}
|
1450
|
-
if @pre.kind_of? Rant::FileList
|
1451
|
-
@pre.resolve
|
1452
|
-
else
|
1453
|
-
@pre.flatten!
|
1454
|
-
@pre.compact!
|
1455
|
-
end
|
1456
|
-
@pre_resolved = true
|
1457
|
-
end
|
1458
|
-
end # class Task
|
1459
|
-
|
1460
|
-
class UserTask < Task
|
1461
|
-
|
1462
|
-
def initialize(*args)
|
1463
|
-
super
|
1464
|
-
@block = nil
|
1465
|
-
@needed = nil
|
1466
|
-
@target_files = nil
|
1467
|
-
yield self if block_given?
|
1468
|
-
end
|
1469
|
-
|
1470
|
-
def act(&block)
|
1471
|
-
@block = block
|
1472
|
-
end
|
1473
|
-
|
1474
|
-
def needed(&block)
|
1475
|
-
@needed = block
|
1476
|
-
end
|
1477
|
-
|
1478
|
-
def file_target?
|
1479
|
-
@target_files and @target_files.include? @name
|
1480
|
-
end
|
1481
|
-
|
1482
|
-
def each_target(&block)
|
1483
|
-
goto_task_home
|
1484
|
-
@target_files.each(&block) if @target_files
|
1485
|
-
end
|
1486
|
-
|
1487
|
-
def file_target(*args)
|
1488
|
-
args.flatten!
|
1489
|
-
args << @name if args.empty?
|
1490
|
-
if @target_files
|
1491
|
-
@target_files.concat(args)
|
1492
|
-
else
|
1493
|
-
@target_files = args
|
1494
|
-
end
|
1495
|
-
end
|
1496
|
-
|
1497
|
-
def invoke(opt = INVOKE_OPT)
|
1498
|
-
return circular_dep if @run
|
1499
|
-
@run = true
|
1500
|
-
begin
|
1501
|
-
return if done?
|
1502
|
-
internal_invoke(opt, ud_init_by_needed)
|
1503
|
-
ensure
|
1504
|
-
@run = false
|
1505
|
-
end
|
1506
|
-
end
|
1507
|
-
|
1508
|
-
private
|
1509
|
-
def ud_init_by_needed
|
1510
|
-
if @needed
|
1511
|
-
goto_task_home
|
1512
|
-
@needed.arity == 0 ? @needed.call : @needed[self]
|
1513
|
-
end
|
1514
|
-
end
|
1515
|
-
end # class UserTask
|
1516
|
-
|
1517
|
-
class FileTask < Task
|
1518
|
-
|
1519
|
-
def initialize(*args)
|
1520
|
-
super
|
1521
|
-
@ts = T0
|
1522
|
-
end
|
1523
|
-
|
1524
|
-
def file_target?
|
1525
|
-
true
|
1526
|
-
end
|
1527
|
-
|
1528
|
-
def invoke(opt = INVOKE_OPT)
|
1529
|
-
return circular_dep if @run
|
1530
|
-
@run = true
|
1531
|
-
begin
|
1532
|
-
return if done?
|
1533
|
-
goto_task_home
|
1534
|
-
if File.exist? @name
|
1535
|
-
@ts = File.mtime @name
|
1536
|
-
internal_invoke opt, false
|
1537
|
-
else
|
1538
|
-
@ts = T0
|
1539
|
-
internal_invoke opt, true
|
1540
|
-
end
|
1541
|
-
ensure
|
1542
|
-
@run = false
|
1543
|
-
end
|
1544
|
-
end
|
1545
|
-
|
1546
|
-
def timestamp(opt = INVOKE_OPT)
|
1547
|
-
File.exist?(@name) ? File.mtime(@name) : T0
|
1548
|
-
end
|
1549
|
-
|
1550
|
-
def handle_node(dep, opt)
|
1551
|
-
return true if dep.file_target? && dep.invoke(opt)
|
1552
|
-
if File.exist? dep.name
|
1553
|
-
File.mtime(dep.name) > @ts
|
1554
|
-
elsif !dep.file_target?
|
1555
|
-
@rac.err_msg @rac.pos_text(rantfile.path, line_number),
|
1556
|
-
"in prerequisites: no such file: `#{dep.full_name}'"
|
1557
|
-
self.fail
|
1558
|
-
end
|
1559
|
-
end
|
1560
|
-
|
1561
|
-
def handle_timestamped(dep, opt)
|
1562
|
-
return true if dep.invoke opt
|
1563
|
-
dep.timestamp(opt) > @ts
|
1564
|
-
end
|
1565
|
-
|
1566
|
-
def handle_non_node(dep, opt)
|
1567
|
-
goto_task_home # !!??
|
1568
|
-
unless File.exist? dep
|
1569
|
-
@rac.err_msg @rac.pos_text(rantfile.path, line_number),
|
1570
|
-
"in prerequisites: no such file or task: `#{dep}'"
|
1571
|
-
self.fail
|
1572
|
-
end
|
1573
|
-
[dep, File.mtime(dep) > @ts]
|
1574
|
-
end
|
1575
|
-
|
1576
|
-
def each_target
|
1577
|
-
goto_task_home
|
1578
|
-
yield name
|
1579
|
-
end
|
1580
|
-
end # class FileTask
|
1581
|
-
|
1582
|
-
module AutoInvokeDirNode
|
1583
|
-
private
|
1584
|
-
def run
|
1585
|
-
goto_task_home
|
1586
|
-
return if @rac.running_task(self)
|
1587
|
-
dir = File.dirname(name)
|
1588
|
-
@rac.build dir unless dir == "." || dir == "/"
|
1589
|
-
return unless @block
|
1590
|
-
@block.arity == 0 ? @block.call : @block[self]
|
1591
|
-
end
|
1592
|
-
end
|
1593
|
-
|
1594
|
-
class AutoSubFileTask < FileTask
|
1595
|
-
include AutoInvokeDirNode
|
1596
|
-
end
|
1597
|
-
|
1598
|
-
class DirTask < Task
|
1599
|
-
|
1600
|
-
def initialize(*args)
|
1601
|
-
super
|
1602
|
-
@ts = T0
|
1603
|
-
@isdir = nil
|
1604
|
-
end
|
1605
|
-
|
1606
|
-
def invoke(opt = INVOKE_OPT)
|
1607
|
-
return circular_dep if @run
|
1608
|
-
@run = true
|
1609
|
-
begin
|
1610
|
-
return if done?
|
1611
|
-
goto_task_home
|
1612
|
-
@isdir = test(?d, @name)
|
1613
|
-
if @isdir
|
1614
|
-
@ts = @block ? test(?M, @name) : Time.now
|
1615
|
-
internal_invoke opt, false
|
1616
|
-
else
|
1617
|
-
@ts = T0
|
1618
|
-
internal_invoke opt, true
|
1619
|
-
end
|
1620
|
-
ensure
|
1621
|
-
@run = false
|
1622
|
-
end
|
1623
|
-
end
|
1624
|
-
|
1625
|
-
def file_target?
|
1626
|
-
true
|
1627
|
-
end
|
1628
|
-
|
1629
|
-
def handle_node(dep, opt)
|
1630
|
-
return true if dep.file_target? && dep.invoke(opt)
|
1631
|
-
if File.exist? dep.name
|
1632
|
-
File.mtime(dep.name) > @ts
|
1633
|
-
elsif !dep.file_target?
|
1634
|
-
@rac.err_msg @rac.pos_text(rantfile.path, line_number),
|
1635
|
-
"in prerequisites: no such file: `#{dep.full_name}'"
|
1636
|
-
self.fail
|
1637
|
-
end
|
1638
|
-
end
|
1639
|
-
|
1640
|
-
def handle_timestamped(dep, opt)
|
1641
|
-
return @block if dep.invoke opt
|
1642
|
-
@block && dep.timestamp(opt) > @ts
|
1643
|
-
end
|
1644
|
-
|
1645
|
-
def handle_non_node(dep, opt)
|
1646
|
-
goto_task_home
|
1647
|
-
unless File.exist? dep
|
1648
|
-
@rac.err_msg @rac.pos_text(rantfile.path, line_number),
|
1649
|
-
"in prerequisites: no such file or task: `#{dep}'"
|
1650
|
-
self.fail
|
1651
|
-
end
|
1652
|
-
[dep, @block && File.mtime(dep) > @ts]
|
1653
|
-
end
|
1654
|
-
|
1655
|
-
def run
|
1656
|
-
return if @rac.running_task(self)
|
1657
|
-
@rac.sys.mkdir @name unless @isdir
|
1658
|
-
if @block
|
1659
|
-
@block.arity == 0 ? @block.call : @block[self]
|
1660
|
-
goto_task_home
|
1661
|
-
@rac.sys.touch @name
|
1662
|
-
end
|
1663
|
-
end
|
1664
|
-
|
1665
|
-
def each_target
|
1666
|
-
goto_task_home
|
1667
|
-
yield name
|
1668
|
-
end
|
1669
|
-
end # class DirTask
|
1670
|
-
|
1671
|
-
class SourceNode
|
1672
|
-
include Node
|
1673
|
-
def initialize(rac, name, prerequisites = [])
|
1674
|
-
super()
|
1675
|
-
@rac = rac
|
1676
|
-
@name = name or raise ArgumentError, "name not given"
|
1677
|
-
@pre = prerequisites
|
1678
|
-
@run = false
|
1679
|
-
@ts = nil
|
1680
|
-
end
|
1681
|
-
def prerequisites
|
1682
|
-
@pre
|
1683
|
-
end
|
1684
|
-
def timestamp(opt = INVOKE_OPT)
|
1685
|
-
return @ts if @ts
|
1686
|
-
goto_task_home
|
1687
|
-
if File.exist?(@name)
|
1688
|
-
@ts = File.mtime @name
|
1689
|
-
else
|
1690
|
-
rac.abort_at(ch, "SourceNode: no such file -- #@name")
|
1691
|
-
end
|
1692
|
-
sd = project_subdir
|
1693
|
-
@pre.each { |f|
|
1694
|
-
nodes = rac.resolve f, sd
|
1695
|
-
if nodes.empty?
|
1696
|
-
if File.exist? f
|
1697
|
-
mtime = File.mtime f
|
1698
|
-
@ts = mtime if mtime > @ts
|
1699
|
-
else
|
1700
|
-
rac.abort_at(ch,
|
1701
|
-
"SourceNode: no such file -- #{f}")
|
1702
|
-
end
|
1703
|
-
else
|
1704
|
-
nodes.each { |node|
|
1705
|
-
node.invoke(opt)
|
1706
|
-
if node.respond_to? :timestamp
|
1707
|
-
node_ts = node.timestamp(opt)
|
1708
|
-
goto_task_home
|
1709
|
-
@ts = node_ts if node_ts > @ts
|
1710
|
-
else
|
1711
|
-
rac.abort_at(ch,
|
1712
|
-
"SourceNode can't depend on #{node.name}")
|
1713
|
-
end
|
1714
|
-
}
|
1715
|
-
end
|
1716
|
-
}
|
1717
|
-
@ts
|
1718
|
-
end
|
1719
|
-
def invoke(opt = INVOKE_OPT)
|
1720
|
-
false
|
1721
|
-
end
|
1722
|
-
def related_sources
|
1723
|
-
@pre
|
1724
|
-
end
|
1725
|
-
end # class SourceNode
|
1726
|
-
|
1727
|
-
module Generators
|
1728
|
-
class Task
|
1729
|
-
def self.rant_gen(rac, ch, args, &block)
|
1730
|
-
unless args.size == 1
|
1731
|
-
rac.abort("Task takes only one argument " +
|
1732
|
-
"which has to be like one given to the " +
|
1733
|
-
"`task' function")
|
1734
|
-
end
|
1735
|
-
rac.prepare_task(args.first, nil, ch) { |name,pre,blk|
|
1736
|
-
rac.node_factory.new_custom(rac, name, pre, block)
|
1737
|
-
}
|
1738
|
-
end
|
1739
|
-
end
|
1740
|
-
class Directory
|
1741
|
-
def self.rant_gen(rac, ch, args, &block)
|
1742
|
-
case args.size
|
1743
|
-
when 1
|
1744
|
-
name, pre = rac.normalize_task_arg(args.first, ch)
|
1745
|
-
self.task(rac, ch, name, pre, &block)
|
1746
|
-
when 2
|
1747
|
-
basedir = args.shift
|
1748
|
-
if basedir.respond_to? :to_str
|
1749
|
-
basedir = basedir.to_str
|
1750
|
-
else
|
1751
|
-
rac.abort_at(ch,
|
1752
|
-
"Directory: basedir argument has to be a string.")
|
1753
|
-
end
|
1754
|
-
name, pre = rac.normalize_task_arg(args.first, ch)
|
1755
|
-
self.task(rac, ch, name, pre, basedir, &block)
|
1756
|
-
else
|
1757
|
-
rac.abort_at(ch, "Directory takes one argument, " +
|
1758
|
-
"which should be like one given to the `task' command.")
|
1759
|
-
end
|
1760
|
-
end
|
1761
|
-
|
1762
|
-
def self.task(rac, ch, name, prerequisites=[], basedir=nil, &block)
|
1763
|
-
dirs = ::Rant::Sys.split_all(name)
|
1764
|
-
if dirs.empty?
|
1765
|
-
rac.abort_at(ch,
|
1766
|
-
"Not a valid directory name: `#{name}'")
|
1767
|
-
end
|
1768
|
-
path = basedir
|
1769
|
-
last_task = nil
|
1770
|
-
task_block = nil
|
1771
|
-
desc_for_last = rac.pop_desc
|
1772
|
-
dirs.each { |dir|
|
1773
|
-
pre = [path]
|
1774
|
-
pre.compact!
|
1775
|
-
if dir.equal?(dirs.last)
|
1776
|
-
rac.cx.desc desc_for_last
|
1777
|
-
|
1778
|
-
dp = prerequisites.dup
|
1779
|
-
pre.each { |elem| dp << elem }
|
1780
|
-
pre = dp
|
1781
|
-
|
1782
|
-
task_block = block
|
1783
|
-
end
|
1784
|
-
path = path.nil? ? dir : File.join(path, dir)
|
1785
|
-
last_task = rac.prepare_task({:__caller__ => ch,
|
1786
|
-
path => pre}, task_block) { |name,pre,blk|
|
1787
|
-
rac.node_factory.new_dir(rac, name, pre, blk)
|
1788
|
-
}
|
1789
|
-
}
|
1790
|
-
last_task
|
1791
|
-
end
|
1792
|
-
end # class Directory
|
1793
|
-
class SourceNode
|
1794
|
-
def self.rant_gen(rac, ch, args)
|
1795
|
-
unless args.size == 1
|
1796
|
-
rac.abort_at(ch, "SourceNode takes one argument.")
|
1797
|
-
end
|
1798
|
-
if block_given?
|
1799
|
-
rac.abort_at(ch, "SourceNode doesn't take a block.")
|
1800
|
-
end
|
1801
|
-
rac.prepare_task(args.first, nil, ch) { |name, pre, blk|
|
1802
|
-
rac.node_factory.new_source(rac, name, pre, blk)
|
1803
|
-
}
|
1804
|
-
end
|
1805
|
-
end
|
1806
|
-
class Rule
|
1807
|
-
def self.rant_gen(rac, ch, args, &block)
|
1808
|
-
unless args.size == 1
|
1809
|
-
rac.abort_at(ch, "Rule takes only one argument.")
|
1810
|
-
end
|
1811
|
-
rac.abort_at(ch, "Rule: block required.") unless block
|
1812
|
-
arg = args.first
|
1813
|
-
target = nil
|
1814
|
-
src_arg = nil
|
1815
|
-
if Symbol === arg
|
1816
|
-
target = ".#{arg}"
|
1817
|
-
elsif arg.respond_to? :to_str
|
1818
|
-
target = arg.to_str
|
1819
|
-
elsif Regexp === arg
|
1820
|
-
target = arg
|
1821
|
-
elsif Hash === arg && arg.size == 1
|
1822
|
-
arg.each_pair { |target, src_arg| }
|
1823
|
-
src_arg = src_arg.to_str if src_arg.respond_to? :to_str
|
1824
|
-
target = target.to_str if target.respond_to? :to_str
|
1825
|
-
src_arg = ".#{src_arg}" if Symbol === src_arg
|
1826
|
-
target = ".#{target}" if Symbol === target
|
1827
|
-
else
|
1828
|
-
rac.abort_at(ch, "Rule argument " +
|
1829
|
-
"has to be a hash with one key-value pair.")
|
1830
|
-
end
|
1831
|
-
esc_target = nil
|
1832
|
-
target_rx = case target
|
1833
|
-
when String
|
1834
|
-
esc_target = Regexp.escape(target)
|
1835
|
-
/#{esc_target}$/
|
1836
|
-
when Regexp
|
1837
|
-
target
|
1838
|
-
else
|
1839
|
-
rac.abort_at(ch, "rule target has " +
|
1840
|
-
"to be a string or regular expression")
|
1841
|
-
end
|
1842
|
-
src_proc = case src_arg
|
1843
|
-
when String, Array
|
1844
|
-
unless String === target
|
1845
|
-
rac.abort(ch, "rule target has to be " +
|
1846
|
-
"a string if source is a string")
|
1847
|
-
end
|
1848
|
-
if src_arg.kind_of? String
|
1849
|
-
lambda { |name|
|
1850
|
-
name.sub(/#{esc_target}$/, src_arg)
|
1851
|
-
}
|
1852
|
-
else
|
1853
|
-
lambda { |name|
|
1854
|
-
src_arg.collect { |s_src|
|
1855
|
-
s_src = ".#{s_src}" if Symbol === s_src
|
1856
|
-
name.sub(/#{esc_target}$/, s_src)
|
1857
|
-
}
|
1858
|
-
}
|
1859
|
-
end
|
1860
|
-
when Proc: src_arg
|
1861
|
-
when nil: lambda { |name| [] }
|
1862
|
-
else
|
1863
|
-
rac.abort_at(ch, "rule source has to be a " +
|
1864
|
-
"String, Array or Proc")
|
1865
|
-
end
|
1866
|
-
rac.resolve_hooks <<
|
1867
|
-
(block.arity == 2 ? Hook : FileHook).new(
|
1868
|
-
rac, ch, target_rx, src_proc, block)
|
1869
|
-
nil
|
1870
|
-
end
|
1871
|
-
class Hook
|
1872
|
-
attr_accessor :target_rx
|
1873
|
-
def initialize(rant, ch, target_rx, src_proc, block)
|
1874
|
-
@rant = rant
|
1875
|
-
@ch = ch
|
1876
|
-
@target_rx = target_rx
|
1877
|
-
@src_proc = src_proc
|
1878
|
-
@block = block
|
1879
|
-
end
|
1880
|
-
def call(target, rel_project_dir)
|
1881
|
-
if @target_rx =~ target
|
1882
|
-
have_src = true
|
1883
|
-
src = @src_proc[target]
|
1884
|
-
if src.respond_to? :to_ary
|
1885
|
-
have_src = src.to_ary.all? { |s|
|
1886
|
-
have_src?(rel_project_dir, s)
|
1887
|
-
}
|
1888
|
-
else
|
1889
|
-
have_src = have_src?(rel_project_dir, src)
|
1890
|
-
end
|
1891
|
-
if have_src
|
1892
|
-
create_nodes(rel_project_dir, target, src)
|
1893
|
-
end
|
1894
|
-
end
|
1895
|
-
end
|
1896
|
-
alias [] call
|
1897
|
-
private
|
1898
|
-
def have_src?(rel_project_dir, name)
|
1899
|
-
return true unless
|
1900
|
-
@rant.rec_save_resolve(name, self, rel_project_dir).empty?
|
1901
|
-
test(?e, @rant.abs_path(rel_project_dir, name))
|
1902
|
-
end
|
1903
|
-
def create_nodes(rel_project_dir, target, deps)
|
1904
|
-
@rant.goto_project_dir rel_project_dir
|
1905
|
-
case nodes = @block[target, deps]
|
1906
|
-
when Array: nodes
|
1907
|
-
when Node: [nodes]
|
1908
|
-
else
|
1909
|
-
@rant.abort_at(@ch, "Block has to " +
|
1910
|
-
"return Node or array of Nodes.")
|
1911
|
-
end
|
1912
|
-
end
|
1913
|
-
end
|
1914
|
-
class FileHook < Hook
|
1915
|
-
private
|
1916
|
-
def have_src?(rel_project_dir, name)
|
1917
|
-
test(?e, @rant.abs_path(rel_project_dir, name)) or
|
1918
|
-
@rant.rec_save_resolve(name, self, rel_project_dir
|
1919
|
-
).any? { |t| t.file_target? }
|
1920
|
-
end
|
1921
|
-
def create_nodes(rel_project_dir, target, deps)
|
1922
|
-
@rant.goto_project_dir rel_project_dir
|
1923
|
-
t = @rant.file(:__caller__ => @ch,
|
1924
|
-
target => deps, &@block)
|
1925
|
-
[t]
|
1926
|
-
end
|
1927
|
-
end
|
1928
|
-
end # class Rule
|
1929
|
-
class Action
|
1930
|
-
def self.rant_gen(rac, ch, args, &block)
|
1931
|
-
case args.size
|
1932
|
-
when 0:
|
1933
|
-
unless (rac[:tasks] || rac[:stop_after_load])
|
1934
|
-
yield
|
1935
|
-
end
|
1936
|
-
when 1:
|
1937
|
-
rx = args.first
|
1938
|
-
unless rx.kind_of? Regexp
|
1939
|
-
rac.abort_at(ch, "Action: argument has " +
|
1940
|
-
"to be a regular expression.")
|
1941
|
-
end
|
1942
|
-
rac.resolve_hooks << self.new(rac, block, rx)
|
1943
|
-
nil
|
1944
|
-
else
|
1945
|
-
rac.abort_at(ch, "Action: too many arguments.")
|
1946
|
-
end
|
1947
|
-
end
|
1948
|
-
def initialize(rant, block, rx)
|
1949
|
-
@rant = rant
|
1950
|
-
@subdir = @rant.current_subdir
|
1951
|
-
@block = block
|
1952
|
-
@rx = rx
|
1953
|
-
end
|
1954
|
-
def call(target, rel_project_dir)
|
1955
|
-
if target =~ @rx
|
1956
|
-
@rant.resolve_hooks.delete(self)
|
1957
|
-
@rant.goto_project_dir @subdir
|
1958
|
-
@block.call
|
1959
|
-
@rant.resolve(target, rel_project_dir)
|
1960
|
-
end
|
1961
|
-
end
|
1962
|
-
alias [] call
|
1963
|
-
end
|
1964
|
-
end # module Generators
|
1965
|
-
end # module Rant
|
1966
|
-
|
1967
|
-
Rant::MAIN_OBJECT = self
|
1968
|
-
|
1969
|
-
class String
|
1970
|
-
alias sub_ext _rant_sub_ext
|
1971
|
-
def to_rant_target
|
1972
|
-
self
|
1973
|
-
end
|
1974
|
-
end
|
1975
|
-
|
1976
|
-
module Rant::Lib
|
1977
|
-
def parse_caller_elem(elem)
|
1978
|
-
return { :file => "", :ln => 0 } unless elem
|
1979
|
-
if elem =~ /^(.+):(\d+)(?::|$)/
|
1980
|
-
{ :file => $1, :ln => $2.to_i }
|
1981
|
-
else
|
1982
|
-
$stderr.puts "parse_caller_elem: #{elem.inspect}"
|
1983
|
-
{ :file => elem, :ln => 0 }
|
1984
|
-
end
|
1985
|
-
|
1986
|
-
end
|
1987
|
-
module_function :parse_caller_elem
|
1988
|
-
end # module Lib
|
1989
|
-
|
1990
|
-
module Rant::Console
|
1991
|
-
RANT_PREFIX = "rant: "
|
1992
|
-
ERROR_PREFIX = "[ERROR] "
|
1993
|
-
WARN_PREFIX = "[WARNING] "
|
1994
|
-
def msg_prefix
|
1995
|
-
if defined? @msg_prefix and @msg_prefix
|
1996
|
-
@msg_prefix
|
1997
|
-
else
|
1998
|
-
RANT_PREFIX
|
1999
|
-
end
|
2000
|
-
end
|
2001
|
-
def msg(*text)
|
2002
|
-
pre = msg_prefix
|
2003
|
-
$stderr.puts "#{pre}#{text.join("\n" + ' ' * pre.length)}"
|
2004
|
-
end
|
2005
|
-
def vmsg(importance, *text)
|
2006
|
-
msg(*text) if verbose >= importance
|
2007
|
-
end
|
2008
|
-
def err_msg(*text)
|
2009
|
-
pre = msg_prefix + ERROR_PREFIX
|
2010
|
-
$stderr.puts "#{pre}#{text.join("\n" + ' ' * pre.length)}"
|
2011
|
-
end
|
2012
|
-
def warn_msg(*text)
|
2013
|
-
pre = msg_prefix + WARN_PREFIX
|
2014
|
-
$stderr.puts "#{pre}#{text.join("\n" + ' ' * pre.length)}"
|
2015
|
-
end
|
2016
|
-
def ask_yes_no text
|
2017
|
-
$stderr.print msg_prefix + text + " [y|n] "
|
2018
|
-
case $stdin.readline
|
2019
|
-
when /y|yes/i: true
|
2020
|
-
when /n|no/i: false
|
2021
|
-
else
|
2022
|
-
$stderr.puts(' ' * msg_prefix.length +
|
2023
|
-
"Please answer with `yes' or `no'")
|
2024
|
-
ask_yes_no text
|
2025
|
-
end
|
2026
|
-
end
|
2027
|
-
def prompt text
|
2028
|
-
$stderr.print msg_prefix + text
|
2029
|
-
input = $stdin.readline
|
2030
|
-
input ? input.chomp : input
|
2031
|
-
end
|
2032
|
-
def option_listing opts
|
2033
|
-
rs = ""
|
2034
|
-
opts.each { |lopt, *opt_a|
|
2035
|
-
if opt_a.size == 2
|
2036
|
-
mode, desc = opt_a
|
2037
|
-
else
|
2038
|
-
sopt, mode, desc = opt_a
|
2039
|
-
end
|
2040
|
-
next unless desc # "private" option
|
2041
|
-
optstr = ""
|
2042
|
-
arg = nil
|
2043
|
-
if mode != GetoptLong::NO_ARGUMENT
|
2044
|
-
if desc =~ /(\b[A-Z_]{2,}\b)/
|
2045
|
-
arg = $1
|
2046
|
-
end
|
2047
|
-
end
|
2048
|
-
if lopt
|
2049
|
-
optstr << lopt
|
2050
|
-
if arg
|
2051
|
-
optstr << " " << arg
|
2052
|
-
end
|
2053
|
-
optstr = optstr.ljust(30)
|
2054
|
-
end
|
2055
|
-
if sopt
|
2056
|
-
optstr << " " unless optstr.empty?
|
2057
|
-
optstr << sopt
|
2058
|
-
if arg
|
2059
|
-
optstr << " " << arg
|
2060
|
-
end
|
2061
|
-
end
|
2062
|
-
rs << " #{optstr}\n"
|
2063
|
-
rs << " #{desc.split("\n").join("\n ")}\n"
|
2064
|
-
}
|
2065
|
-
rs
|
2066
|
-
end
|
2067
|
-
extend self
|
2068
|
-
end # module Rant::Console
|
2069
|
-
|
2070
|
-
module RantContext
|
2071
|
-
include Rant::Generators
|
2072
|
-
|
2073
|
-
Env = Rant::Env
|
2074
|
-
FileList = Rant::FileList
|
2075
|
-
|
2076
|
-
def task(targ, &block)
|
2077
|
-
rant.task(targ, &block)
|
2078
|
-
end
|
2079
|
-
|
2080
|
-
def file(targ, &block)
|
2081
|
-
rant.file(targ, &block)
|
2082
|
-
end
|
2083
|
-
|
2084
|
-
def enhance(targ, &block)
|
2085
|
-
rant.enhance(targ, &block)
|
2086
|
-
end
|
2087
|
-
|
2088
|
-
def desc(*args)
|
2089
|
-
rant.desc(*args)
|
2090
|
-
end
|
2091
|
-
|
2092
|
-
def gen(*args, &block)
|
2093
|
-
rant.gen(*args, &block)
|
2094
|
-
end
|
2095
|
-
|
2096
|
-
def import(*args, &block)
|
2097
|
-
rant.import(*args, &block)
|
2098
|
-
end
|
2099
|
-
|
2100
|
-
def plugin(*args, &block)
|
2101
|
-
rant.plugin(*args, &block)
|
2102
|
-
end
|
2103
|
-
|
2104
|
-
def subdirs(*args)
|
2105
|
-
rant.subdirs(*args)
|
2106
|
-
end
|
2107
|
-
|
2108
|
-
def source(opt, rantfile = nil)
|
2109
|
-
rant.source(opt, rantfile)
|
2110
|
-
end
|
2111
|
-
|
2112
|
-
def sys(*args, &block)
|
2113
|
-
rant.sys(*args, &block)
|
2114
|
-
end
|
2115
|
-
|
2116
|
-
def var(*args, &block)
|
2117
|
-
rant.var(*args, &block)
|
2118
|
-
end
|
2119
|
-
|
2120
|
-
def make(*args, &block)
|
2121
|
-
rant.make(*args, &block)
|
2122
|
-
end
|
2123
|
-
|
2124
|
-
end # module RantContext
|
2125
|
-
|
2126
|
-
class RantAppContext
|
2127
|
-
include RantContext
|
2128
|
-
|
2129
|
-
def initialize(app)
|
2130
|
-
@__rant__ = app
|
2131
|
-
end
|
2132
|
-
|
2133
|
-
def rant
|
2134
|
-
@__rant__
|
2135
|
-
end
|
2136
|
-
|
2137
|
-
def method_missing(sym, *args)
|
2138
|
-
Rant::MAIN_OBJECT.send(sym, *args)
|
2139
|
-
rescue NoMethodError
|
2140
|
-
raise NameError, "NameError: undefined local " +
|
2141
|
-
"variable or method `#{sym}' for main:Object", caller
|
2142
|
-
end
|
2143
|
-
end
|
2144
|
-
|
2145
|
-
module Rant
|
2146
|
-
|
2147
|
-
@__rant__ = nil
|
2148
|
-
class << self
|
2149
|
-
|
2150
|
-
def run(first_arg=nil, *other_args)
|
2151
|
-
other_args = other_args.flatten
|
2152
|
-
args = first_arg.nil? ? ARGV.dup : ([first_arg] + other_args)
|
2153
|
-
if rant && !rant.run?
|
2154
|
-
rant.run(args.flatten)
|
2155
|
-
else
|
2156
|
-
@__rant__ = Rant::RantApp.new
|
2157
|
-
rant.run(args)
|
2158
|
-
end
|
2159
|
-
end
|
2160
|
-
|
2161
|
-
def rant
|
2162
|
-
@__rant__
|
2163
|
-
end
|
2164
|
-
end
|
2165
|
-
|
2166
|
-
end # module Rant
|
2167
|
-
|
2168
|
-
class Rant::RantApp
|
2169
|
-
include Rant::Console
|
2170
|
-
|
2171
|
-
class AutoLoadNodeFactory
|
2172
|
-
def initialize(rant)
|
2173
|
-
@rant = rant
|
2174
|
-
end
|
2175
|
-
def method_missing(sym, *args, &block)
|
2176
|
-
@rant.import "nodes/default"
|
2177
|
-
@rant.node_factory.send(sym, *args, &block)
|
2178
|
-
end
|
2179
|
-
end
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
OPTIONS = [
|
2184
|
-
[ "--help", "-h", GetoptLong::NO_ARGUMENT,
|
2185
|
-
"Print this help and exit." ],
|
2186
|
-
[ "--version", "-V", GetoptLong::NO_ARGUMENT,
|
2187
|
-
"Print version of Rant and exit." ],
|
2188
|
-
[ "--verbose", "-v", GetoptLong::NO_ARGUMENT,
|
2189
|
-
"Print more messages to stderr." ],
|
2190
|
-
[ "--quiet", "-q", GetoptLong::NO_ARGUMENT,
|
2191
|
-
"Don't print commands." ],
|
2192
|
-
[ "--err-commands", GetoptLong::NO_ARGUMENT,
|
2193
|
-
"Print failed commands and their exit status." ],
|
2194
|
-
[ "--directory","-C", GetoptLong::REQUIRED_ARGUMENT,
|
2195
|
-
"Run rant in DIRECTORY." ],
|
2196
|
-
[ "--cd-parent","-c", GetoptLong::NO_ARGUMENT,
|
2197
|
-
"Run rant in parent directory with Rantfile." ],
|
2198
|
-
[ "--look-up", "-u", GetoptLong::NO_ARGUMENT,
|
2199
|
-
"Look in parent directories for root Rantfile." ],
|
2200
|
-
[ "--rantfile", "-f", GetoptLong::REQUIRED_ARGUMENT,
|
2201
|
-
"Process RANTFILE instead of standard rantfiles.\n" +
|
2202
|
-
"Multiple files may be specified with this option." ],
|
2203
|
-
[ "--force-run","-a", GetoptLong::REQUIRED_ARGUMENT,
|
2204
|
-
"Force rebuild of TARGET and all dependencies." ],
|
2205
|
-
[ "--dry-run", "-n", GetoptLong::NO_ARGUMENT,
|
2206
|
-
"Print info instead of actually executing actions." ],
|
2207
|
-
[ "--tasks", "-T", GetoptLong::NO_ARGUMENT,
|
2208
|
-
"Show a list of all described tasks and exit." ],
|
2209
|
-
|
2210
|
-
|
2211
|
-
[ "--import", "-i", GetoptLong::REQUIRED_ARGUMENT, nil ],
|
2212
|
-
[ "--stop-after-load", GetoptLong::NO_ARGUMENT, nil ],
|
2213
|
-
[ "--trace-abort", GetoptLong::NO_ARGUMENT, nil ],
|
2214
|
-
]
|
2215
|
-
|
2216
|
-
ROOT_DIR_ID = "@"
|
2217
|
-
ESCAPE_ID = "\\"
|
2218
|
-
|
2219
|
-
attr_reader :args
|
2220
|
-
attr_reader :rantfiles
|
2221
|
-
attr_reader :force_targets
|
2222
|
-
attr_reader :plugins
|
2223
|
-
attr_reader :context
|
2224
|
-
alias cx context
|
2225
|
-
attr_reader :tasks
|
2226
|
-
attr_reader :imports
|
2227
|
-
attr_reader :current_subdir
|
2228
|
-
attr_reader :resolve_hooks
|
2229
|
-
attr_reader :rootdir
|
2230
|
-
|
2231
|
-
attr_accessor :node_factory
|
2232
|
-
|
2233
|
-
def initialize
|
2234
|
-
@args = []
|
2235
|
-
@context = RantAppContext.new(self)
|
2236
|
-
@sys = ::Rant::SysObject.new(self)
|
2237
|
-
@rantfiles = []
|
2238
|
-
@tasks = {}
|
2239
|
-
@opts = {
|
2240
|
-
:verbose => 0,
|
2241
|
-
:quiet => false,
|
2242
|
-
}
|
2243
|
-
@rootdir = Dir.pwd # root directory of project
|
2244
|
-
@arg_rantfiles = [] # rantfiles given in args
|
2245
|
-
@arg_targets = [] # targets given in args
|
2246
|
-
@force_targets = [] # targets given with -a option
|
2247
|
-
@run = false # run method was called at least once
|
2248
|
-
@done = false # run method was successful
|
2249
|
-
@plugins = []
|
2250
|
-
@var = Rant::RantVar::Space.new
|
2251
|
-
@var.query :ignore, :AutoList, []
|
2252
|
-
@imports = []
|
2253
|
-
|
2254
|
-
@task_desc = nil
|
2255
|
-
@last_build_subdir = ""
|
2256
|
-
|
2257
|
-
@current_subdir = ""
|
2258
|
-
@resolve_hooks = []
|
2259
|
-
|
2260
|
-
@node_factory = AutoLoadNodeFactory.new(self)
|
2261
|
-
end
|
2262
|
-
|
2263
|
-
def [](opt)
|
2264
|
-
@opts[opt]
|
2265
|
-
end
|
2266
|
-
|
2267
|
-
def []=(opt, val)
|
2268
|
-
@opts[opt] = val
|
2269
|
-
end
|
2270
|
-
|
2271
|
-
def expand_path(subdir, path)
|
2272
|
-
case path
|
2273
|
-
when nil: subdir.dup
|
2274
|
-
when "": subdir.dup
|
2275
|
-
when /^@/: path.sub(/^@/, '')
|
2276
|
-
else
|
2277
|
-
path = path.sub(/^\\(?=@)/, '')
|
2278
|
-
if subdir.empty?
|
2279
|
-
path
|
2280
|
-
else
|
2281
|
-
File.join(subdir, path)
|
2282
|
-
end
|
2283
|
-
end
|
2284
|
-
end
|
2285
|
-
def resolve_root_ref(path)
|
2286
|
-
return File.join(@rootdir, path[1..-1]) if path =~ /^@/
|
2287
|
-
path.sub(/^\\(?=@)/, '')
|
2288
|
-
end
|
2289
|
-
def project_to_fs_path(path)
|
2290
|
-
sub = expand_path(@current_subdir, path)
|
2291
|
-
sub.empty? ? @rootdir : File.join(@rootdir, sub)
|
2292
|
-
end
|
2293
|
-
def abs_path(subdir, fn)
|
2294
|
-
return fn if Rant::Sys.absolute_path?(fn)
|
2295
|
-
path = File.join(@rootdir, subdir, fn)
|
2296
|
-
path.gsub!(%r{/+}, "/")
|
2297
|
-
path.sub!(%r{/$}, "") if path.length > 1
|
2298
|
-
path
|
2299
|
-
end
|
2300
|
-
def goto(dir)
|
2301
|
-
goto_project_dir(expand_path(@current_subdir, dir))
|
2302
|
-
end
|
2303
|
-
def goto_project_dir(dir='')
|
2304
|
-
@current_subdir = dir
|
2305
|
-
abs_path = @current_subdir.empty? ?
|
2306
|
-
@rootdir : File.join(@rootdir, @current_subdir)
|
2307
|
-
unless Dir.pwd == abs_path
|
2308
|
-
Dir.chdir abs_path
|
2309
|
-
vmsg 1, "in #{abs_path}"
|
2310
|
-
end
|
2311
|
-
end
|
2312
|
-
|
2313
|
-
def run?
|
2314
|
-
@run
|
2315
|
-
end
|
2316
|
-
|
2317
|
-
def done?
|
2318
|
-
@done
|
2319
|
-
end
|
2320
|
-
|
2321
|
-
def run(*args)
|
2322
|
-
@run = true
|
2323
|
-
@args.concat(args.flatten)
|
2324
|
-
orig_pwd = @rootdir = Dir.pwd
|
2325
|
-
process_args
|
2326
|
-
Dir.chdir(@rootdir) rescue abort $!.message
|
2327
|
-
load_rantfiles
|
2328
|
-
|
2329
|
-
raise Rant::RantDoneException if @opts[:stop_after_load]
|
2330
|
-
|
2331
|
-
@plugins.each { |plugin| plugin.rant_start }
|
2332
|
-
if @opts[:tasks]
|
2333
|
-
show_descriptions
|
2334
|
-
raise Rant::RantDoneException
|
2335
|
-
end
|
2336
|
-
run_tasks
|
2337
|
-
raise Rant::RantDoneException
|
2338
|
-
rescue Rant::RantDoneException
|
2339
|
-
@done = true
|
2340
|
-
@plugins.each { |plugin| plugin.rant_done }
|
2341
|
-
return 0
|
2342
|
-
rescue Rant::RantAbortException
|
2343
|
-
$stderr.puts "rant aborted!"
|
2344
|
-
return 1
|
2345
|
-
rescue Exception => e
|
2346
|
-
ch = get_ch_from_backtrace(e.backtrace)
|
2347
|
-
if ch && !@opts[:trace_abort]
|
2348
|
-
err_msg(pos_text(ch[:file], ch[:ln]), e.message)
|
2349
|
-
else
|
2350
|
-
err_msg e.message, e.backtrace[0..4]
|
2351
|
-
end
|
2352
|
-
$stderr.puts "rant aborted!"
|
2353
|
-
return 1
|
2354
|
-
ensure
|
2355
|
-
Dir.chdir @rootdir if test ?d, @rootdir
|
2356
|
-
hooks = var._get("__at_return__")
|
2357
|
-
hooks.each { |hook| hook.call } if hooks
|
2358
|
-
@plugins.each { |plugin| plugin.rant_plugin_stop }
|
2359
|
-
@plugins.each { |plugin| plugin.rant_quit }
|
2360
|
-
Dir.chdir orig_pwd
|
2361
|
-
end
|
2362
|
-
|
2363
|
-
|
2364
|
-
def desc(*args)
|
2365
|
-
if args.empty? || (args.size == 1 && args.first.nil?)
|
2366
|
-
@task_desc = nil
|
2367
|
-
else
|
2368
|
-
@task_desc = args.join("\n")
|
2369
|
-
end
|
2370
|
-
end
|
2371
|
-
|
2372
|
-
def task(targ, &block)
|
2373
|
-
prepare_task(targ, block) { |name,pre,blk|
|
2374
|
-
@node_factory.new_task(self, name, pre, blk)
|
2375
|
-
}
|
2376
|
-
end
|
2377
|
-
|
2378
|
-
def file(targ, &block)
|
2379
|
-
prepare_task(targ, block) { |name,pre,blk|
|
2380
|
-
@node_factory.new_file(self, name, pre, blk)
|
2381
|
-
}
|
2382
|
-
end
|
2383
|
-
|
2384
|
-
def gen(*args, &block)
|
2385
|
-
ch = Rant::Lib::parse_caller_elem(caller[1])
|
2386
|
-
generator = args.shift
|
2387
|
-
unless generator.respond_to? :rant_gen
|
2388
|
-
abort_at(ch,
|
2389
|
-
"gen: First argument has to be a task-generator.")
|
2390
|
-
end
|
2391
|
-
generator.rant_gen(self, ch, args, &block)
|
2392
|
-
end
|
2393
|
-
|
2394
|
-
def import(*args, &block)
|
2395
|
-
ch = Rant::Lib::parse_caller_elem(caller[1])
|
2396
|
-
if block
|
2397
|
-
warn_msg pos_text(ch[:file], ch[:ln]),
|
2398
|
-
"import: ignoring block"
|
2399
|
-
end
|
2400
|
-
args.flatten.each { |arg|
|
2401
|
-
unless String === arg
|
2402
|
-
abort_at(ch, "import: only strings allowed as arguments")
|
2403
|
-
end
|
2404
|
-
unless @imports.include? arg
|
2405
|
-
unless Rant::CODE_IMPORTS.include? arg
|
2406
|
-
begin
|
2407
|
-
vmsg 2, "import #{arg}"
|
2408
|
-
require "rant/import/#{arg}"
|
2409
|
-
rescue LoadError => e
|
2410
|
-
abort_at(ch, "No such import - #{arg}")
|
2411
|
-
end
|
2412
|
-
Rant::CODE_IMPORTS << arg.dup
|
2413
|
-
end
|
2414
|
-
init_msg = "init_import_#{arg.gsub(/[^\w]/, '__')}"
|
2415
|
-
Rant.send init_msg, self if Rant.respond_to? init_msg
|
2416
|
-
@imports << arg.dup
|
2417
|
-
end
|
2418
|
-
}
|
2419
|
-
end
|
2420
|
-
|
2421
|
-
def plugin(*args, &block)
|
2422
|
-
clr = caller[1]
|
2423
|
-
ch = Rant::Lib::parse_caller_elem(clr)
|
2424
|
-
name = nil
|
2425
|
-
pre = []
|
2426
|
-
ln = ch[:ln] || 0
|
2427
|
-
file = ch[:file]
|
2428
|
-
|
2429
|
-
pl_name = args.shift
|
2430
|
-
pl_name = pl_name.to_str if pl_name.respond_to? :to_str
|
2431
|
-
pl_name = pl_name.to_s if pl_name.is_a? Symbol
|
2432
|
-
unless pl_name.is_a? String
|
2433
|
-
abort(pos_text(file, ln),
|
2434
|
-
"Plugin name has to be a string or symbol.")
|
2435
|
-
end
|
2436
|
-
lc_pl_name = pl_name.downcase
|
2437
|
-
import_name = "plugin/#{lc_pl_name}"
|
2438
|
-
unless Rant::CODE_IMPORTS.include? import_name
|
2439
|
-
begin
|
2440
|
-
require "rant/plugin/#{lc_pl_name}"
|
2441
|
-
Rant::CODE_IMPORTS << import_name
|
2442
|
-
rescue LoadError
|
2443
|
-
abort(pos_text(file, ln),
|
2444
|
-
"no such plugin library -- #{lc_pl_name}")
|
2445
|
-
end
|
2446
|
-
end
|
2447
|
-
pl_class = nil
|
2448
|
-
begin
|
2449
|
-
pl_class = ::Rant::Plugin.const_get(pl_name)
|
2450
|
-
rescue NameError, ArgumentError
|
2451
|
-
abort(pos_text(file, ln),
|
2452
|
-
"no such plugin -- #{pl_name}")
|
2453
|
-
end
|
2454
|
-
|
2455
|
-
plugin = pl_class.rant_plugin_new(self, ch, *args, &block)
|
2456
|
-
@plugins << plugin
|
2457
|
-
vmsg 2, "Plugin `#{plugin.rant_plugin_name}' registered."
|
2458
|
-
plugin.rant_plugin_init
|
2459
|
-
plugin
|
2460
|
-
end
|
2461
|
-
|
2462
|
-
def enhance(targ, &block)
|
2463
|
-
prepare_task(targ, block) { |name,pre,blk|
|
2464
|
-
t = resolve(name).last
|
2465
|
-
if t
|
2466
|
-
unless t.respond_to? :enhance
|
2467
|
-
abort("Can't enhance task `#{name}'")
|
2468
|
-
end
|
2469
|
-
t.enhance(pre, &blk)
|
2470
|
-
return t
|
2471
|
-
end
|
2472
|
-
warn_msg "enhance \"#{name}\": no such task",
|
2473
|
-
"Generating a new file task with the given name."
|
2474
|
-
@node_factory.new_file(self, name, pre, blk)
|
2475
|
-
}
|
2476
|
-
end
|
2477
|
-
|
2478
|
-
def source(opt, rantfile = nil)
|
2479
|
-
unless rantfile
|
2480
|
-
rantfile = opt
|
2481
|
-
opt = nil
|
2482
|
-
end
|
2483
|
-
make_rf = opt != :n && opt != :now
|
2484
|
-
rf, is_new = rantfile_for_path(rantfile)
|
2485
|
-
return false unless is_new
|
2486
|
-
make rantfile if make_rf
|
2487
|
-
unless File.exist? rf.path
|
2488
|
-
abort("source: No such file -- #{rantfile}")
|
2489
|
-
end
|
2490
|
-
|
2491
|
-
load_file rf
|
2492
|
-
end
|
2493
|
-
|
2494
|
-
def subdirs(*args)
|
2495
|
-
args.flatten!
|
2496
|
-
ch = Rant::Lib::parse_caller_elem(caller[1])
|
2497
|
-
args.each { |arg|
|
2498
|
-
if arg.respond_to? :to_str
|
2499
|
-
arg = arg.to_str
|
2500
|
-
else
|
2501
|
-
abort_at(ch, "subdirs: arguments must be strings")
|
2502
|
-
end
|
2503
|
-
loaded = false
|
2504
|
-
prev_subdir = @current_subdir
|
2505
|
-
begin
|
2506
|
-
goto arg
|
2507
|
-
if test(?f, Rant::SUB_RANTFILE)
|
2508
|
-
path = Rant::SUB_RANTFILE
|
2509
|
-
else
|
2510
|
-
path = rantfile_in_dir
|
2511
|
-
end
|
2512
|
-
if path
|
2513
|
-
if defined? @initial_subdir and
|
2514
|
-
@initial_subdir == @current_subdir
|
2515
|
-
rf, is_new = rantfile_for_path(path, false)
|
2516
|
-
@rantfiles.unshift rf if is_new
|
2517
|
-
else
|
2518
|
-
rf, is_new = rantfile_for_path(path)
|
2519
|
-
end
|
2520
|
-
load_file rf if is_new
|
2521
|
-
elsif !@opts[:no_warn_subdir]
|
2522
|
-
warn_msg(pos_text(ch[:file], ch[:ln]),
|
2523
|
-
"subdirs: No Rantfile in subdir `#{arg}'.")
|
2524
|
-
end
|
2525
|
-
ensure
|
2526
|
-
goto_project_dir prev_subdir
|
2527
|
-
end
|
2528
|
-
}
|
2529
|
-
rescue SystemCallError => e
|
2530
|
-
abort_at(ch, "subdirs: " + e.message)
|
2531
|
-
end
|
2532
|
-
|
2533
|
-
def sys(*args, &block)
|
2534
|
-
args.empty? ? @sys : @sys.sh(*args, &block)
|
2535
|
-
end
|
2536
|
-
|
2537
|
-
def var(*args, &block)
|
2538
|
-
args.empty? ? @var : @var.query(*args, &block)
|
2539
|
-
end
|
2540
|
-
|
2541
|
-
def pop_desc
|
2542
|
-
td = @task_desc
|
2543
|
-
@task_desc = nil
|
2544
|
-
td
|
2545
|
-
end
|
2546
|
-
|
2547
|
-
def abort(*msg)
|
2548
|
-
err_msg(msg) unless msg.empty?
|
2549
|
-
$stderr.puts caller if @opts[:trace_abort]
|
2550
|
-
raise Rant::RantAbortException
|
2551
|
-
end
|
2552
|
-
|
2553
|
-
def abort_at(ch, *msg)
|
2554
|
-
err_msg(pos_text(ch[:file], ch[:ln]), msg)
|
2555
|
-
$stderr.puts caller if @opts[:trace_abort]
|
2556
|
-
raise Rant::RantAbortException
|
2557
|
-
end
|
2558
|
-
|
2559
|
-
def show_help
|
2560
|
-
puts "rant [-f Rantfile] [Options] [targets]"
|
2561
|
-
puts
|
2562
|
-
puts "Options are:"
|
2563
|
-
print option_listing(OPTIONS)
|
2564
|
-
end
|
2565
|
-
|
2566
|
-
def show_descriptions
|
2567
|
-
tlist = select_tasks { |t| t.description }
|
2568
|
-
def_target = target_list.first
|
2569
|
-
if tlist.empty?
|
2570
|
-
puts "rant # => " + list_task_names(
|
2571
|
-
resolve(def_target)).join(', ')
|
2572
|
-
msg "No described tasks."
|
2573
|
-
return
|
2574
|
-
end
|
2575
|
-
prefix = "./build.rb "
|
2576
|
-
infix = " # "
|
2577
|
-
name_length = (tlist.map{ |t| t.to_s.length } << 7).max
|
2578
|
-
cmd_length = prefix.length + name_length
|
2579
|
-
unless tlist.first.to_s == def_target
|
2580
|
-
defaults = list_task_names(
|
2581
|
-
resolve(def_target)).join(', ')
|
2582
|
-
puts "#{prefix}#{' ' * name_length}#{infix}=> #{defaults}"
|
2583
|
-
end
|
2584
|
-
tlist.each { |t|
|
2585
|
-
print(prefix + t.to_s.ljust(name_length) + infix)
|
2586
|
-
dt = t.description.sub(/\s+$/, "")
|
2587
|
-
puts dt.gsub(/\n/, "\n" + ' ' * cmd_length + infix + " ")
|
2588
|
-
}
|
2589
|
-
true
|
2590
|
-
end
|
2591
|
-
|
2592
|
-
def list_task_names(*tasks)
|
2593
|
-
rsl = []
|
2594
|
-
tasks.flatten.each { |t|
|
2595
|
-
if t.respond_to?(:has_actions?) && t.has_actions?
|
2596
|
-
rsl << t
|
2597
|
-
elsif t.respond_to? :prerequisites
|
2598
|
-
if t.prerequisites.empty?
|
2599
|
-
rsl << t
|
2600
|
-
else
|
2601
|
-
t.prerequisites.each { |pre|
|
2602
|
-
rsl.concat(list_task_names(
|
2603
|
-
resolve(pre, t.project_subdir)))
|
2604
|
-
}
|
2605
|
-
end
|
2606
|
-
else
|
2607
|
-
rsl << t
|
2608
|
-
end
|
2609
|
-
}
|
2610
|
-
rsl
|
2611
|
-
end
|
2612
|
-
private :list_task_names
|
2613
|
-
|
2614
|
-
def verbose
|
2615
|
-
@opts[:verbose]
|
2616
|
-
end
|
2617
|
-
|
2618
|
-
def quiet?
|
2619
|
-
@opts[:quiet]
|
2620
|
-
end
|
2621
|
-
|
2622
|
-
def pos_text(file, ln)
|
2623
|
-
t = "in file `#{file}'"
|
2624
|
-
t << ", line #{ln}" if ln && ln > 0
|
2625
|
-
t << ": "
|
2626
|
-
end
|
2627
|
-
|
2628
|
-
def cmd_msg(cmd)
|
2629
|
-
puts cmd unless quiet?
|
2630
|
-
end
|
2631
|
-
|
2632
|
-
def cmd_print(text)
|
2633
|
-
print text unless quiet?
|
2634
|
-
$stdout.flush
|
2635
|
-
end
|
2636
|
-
|
2637
|
-
def cmd_targets
|
2638
|
-
@force_targets + @arg_targets
|
2639
|
-
end
|
2640
|
-
|
2641
|
-
def running_task(task)
|
2642
|
-
if @current_subdir != @last_build_subdir
|
2643
|
-
cmd_msg "(in #{@current_subdir.empty? ?
|
2644
|
-
@rootdir : @current_subdir})"
|
2645
|
-
@last_build_subdir = @current_subdir
|
2646
|
-
end
|
2647
|
-
if @opts[:dry_run]
|
2648
|
-
task.dry_run
|
2649
|
-
true
|
2650
|
-
end
|
2651
|
-
end
|
2652
|
-
|
2653
|
-
private
|
2654
|
-
def have_any_task?
|
2655
|
-
!@tasks.empty?
|
2656
|
-
end
|
2657
|
-
|
2658
|
-
def target_list
|
2659
|
-
if !have_any_task? && @resolve_hooks.empty?
|
2660
|
-
abort("No tasks defined for this rant application!")
|
2661
|
-
end
|
2662
|
-
|
2663
|
-
target_list = @force_targets + @arg_targets
|
2664
|
-
if target_list.empty?
|
2665
|
-
def_tasks = resolve "default"
|
2666
|
-
unless def_tasks.empty?
|
2667
|
-
target_list << "default"
|
2668
|
-
else
|
2669
|
-
@rantfiles.each { |f|
|
2670
|
-
first = f.tasks.first
|
2671
|
-
if first
|
2672
|
-
target_list << first.reference_name
|
2673
|
-
break
|
2674
|
-
end
|
2675
|
-
}
|
2676
|
-
end
|
2677
|
-
end
|
2678
|
-
target_list
|
2679
|
-
end
|
2680
|
-
|
2681
|
-
def run_tasks
|
2682
|
-
target_list.each { |target|
|
2683
|
-
if build(target) == 0
|
2684
|
-
abort("Don't know how to make `#{target}'.")
|
2685
|
-
end
|
2686
|
-
}
|
2687
|
-
end
|
2688
|
-
|
2689
|
-
def make(target, *args, &block)
|
2690
|
-
ch = nil
|
2691
|
-
if target.respond_to? :to_hash
|
2692
|
-
targ = target.to_hash
|
2693
|
-
ch = Rant::Lib.parse_caller_elem(caller[1])
|
2694
|
-
abort_at(ch, "make: too many arguments") unless args.empty?
|
2695
|
-
tn = nil
|
2696
|
-
prepare_task(targ, block, ch) { |name,pre,blk|
|
2697
|
-
tn = name
|
2698
|
-
@node_factory.new_file(self, name, pre, blk)
|
2699
|
-
}
|
2700
|
-
build(tn)
|
2701
|
-
elsif target.respond_to? :to_rant_target
|
2702
|
-
rt = target.to_rant_target
|
2703
|
-
opt = args.shift
|
2704
|
-
unless args.empty?
|
2705
|
-
ch ||= Rant::Lib.parse_caller_elem(caller[1])
|
2706
|
-
abort_at(ch, "make: too many arguments")
|
2707
|
-
end
|
2708
|
-
if block
|
2709
|
-
ch ||= Rant::Lib.parse_caller_elem(caller[1])
|
2710
|
-
prepare_task(rt, block, ch) { |name,pre,blk|
|
2711
|
-
@node_factory.new_file(self, name, pre, blk)
|
2712
|
-
}
|
2713
|
-
build(rt)
|
2714
|
-
else
|
2715
|
-
build(rt, opt||{})
|
2716
|
-
end
|
2717
|
-
elsif target.respond_to? :rant_gen
|
2718
|
-
ch = Rant::Lib.parse_caller_elem(caller[1])
|
2719
|
-
rv = target.rant_gen(self, ch, args, &block)
|
2720
|
-
unless rv.respond_to? :to_rant_target
|
2721
|
-
abort_at(ch, "make: invalid generator return value")
|
2722
|
-
end
|
2723
|
-
build(rv.to_rant_target)
|
2724
|
-
rv
|
2725
|
-
else
|
2726
|
-
ch = Rant::Lib.parse_caller_elem(caller[1])
|
2727
|
-
abort_at(ch,
|
2728
|
-
"make: generator or target as first argument required.")
|
2729
|
-
end
|
2730
|
-
end
|
2731
|
-
public :make
|
2732
|
-
|
2733
|
-
def build(target, opt = {})
|
2734
|
-
opt[:force] = true if @force_targets.delete(target)
|
2735
|
-
opt[:dry_run] = @opts[:dry_run]
|
2736
|
-
matching_tasks = 0
|
2737
|
-
old_subdir = @current_subdir
|
2738
|
-
old_pwd = Dir.pwd
|
2739
|
-
resolve(target).each { |t|
|
2740
|
-
unless opt[:type] == :file && !t.file_target?
|
2741
|
-
matching_tasks += 1
|
2742
|
-
begin
|
2743
|
-
t.invoke(opt)
|
2744
|
-
rescue Rant::TaskFail => e
|
2745
|
-
err_task_fail(e)
|
2746
|
-
abort
|
2747
|
-
end
|
2748
|
-
end
|
2749
|
-
}
|
2750
|
-
@current_subdir = old_subdir
|
2751
|
-
Dir.chdir old_pwd
|
2752
|
-
matching_tasks
|
2753
|
-
end
|
2754
|
-
public :build
|
2755
|
-
|
2756
|
-
def resolve(task_name, rel_project_dir = @current_subdir)
|
2757
|
-
s = @tasks[expand_path(rel_project_dir, task_name)]
|
2758
|
-
case s
|
2759
|
-
when nil
|
2760
|
-
@resolve_hooks.each { |s|
|
2761
|
-
s = s[task_name, rel_project_dir]
|
2762
|
-
return s if s
|
2763
|
-
}
|
2764
|
-
[]
|
2765
|
-
when Rant::Node: [s]
|
2766
|
-
else # assuming list of tasks
|
2767
|
-
s
|
2768
|
-
end
|
2769
|
-
end
|
2770
|
-
public :resolve
|
2771
|
-
|
2772
|
-
def rec_save_resolve(task_name, excl_hook, rel_project_dir = @current_subdir)
|
2773
|
-
s = @tasks[expand_path(rel_project_dir, task_name)]
|
2774
|
-
case s
|
2775
|
-
when nil
|
2776
|
-
@resolve_hooks.each { |s|
|
2777
|
-
next if s == excl_hook
|
2778
|
-
s = s[task_name, rel_project_dir]
|
2779
|
-
return s if s
|
2780
|
-
}
|
2781
|
-
[]
|
2782
|
-
when Rant::Node: [s]
|
2783
|
-
else
|
2784
|
-
s
|
2785
|
-
end
|
2786
|
-
end
|
2787
|
-
public :rec_save_resolve
|
2788
|
-
|
2789
|
-
def at_resolve(&block)
|
2790
|
-
@resolve_hooks << block if block
|
2791
|
-
end
|
2792
|
-
public :at_resolve
|
2793
|
-
|
2794
|
-
def at_return(&block)
|
2795
|
-
hooks = var._get("__at_return__")
|
2796
|
-
if hooks
|
2797
|
-
hooks << block
|
2798
|
-
else
|
2799
|
-
var._set("__at_return__", [block])
|
2800
|
-
end
|
2801
|
-
end
|
2802
|
-
public :at_return
|
2803
|
-
|
2804
|
-
def select_tasks
|
2805
|
-
selection = []
|
2806
|
-
@rantfiles.each { |rf|
|
2807
|
-
rf.tasks.each { |t|
|
2808
|
-
selection << t if yield t
|
2809
|
-
}
|
2810
|
-
}
|
2811
|
-
selection
|
2812
|
-
end
|
2813
|
-
public :select_tasks
|
2814
|
-
|
2815
|
-
def load_rantfiles
|
2816
|
-
unless @arg_rantfiles.empty?
|
2817
|
-
@arg_rantfiles.each { |fn|
|
2818
|
-
if test(?f, fn)
|
2819
|
-
rf, is_new = rantfile_for_path(fn)
|
2820
|
-
load_file rf if is_new
|
2821
|
-
else
|
2822
|
-
abort "No such file -- #{fn}"
|
2823
|
-
end
|
2824
|
-
}
|
2825
|
-
return
|
2826
|
-
end
|
2827
|
-
return if have_any_task?
|
2828
|
-
fn = rantfile_in_dir
|
2829
|
-
if @opts[:cd_parent]
|
2830
|
-
old_root = @rootdir
|
2831
|
-
until fn or @rootdir == "/"
|
2832
|
-
@rootdir = File.dirname(@rootdir)
|
2833
|
-
fn = rantfile_in_dir(@rootdir)
|
2834
|
-
end
|
2835
|
-
if @rootdir != old_root and fn
|
2836
|
-
Dir.chdir @rootdir
|
2837
|
-
cmd_msg "(in #@rootdir)"
|
2838
|
-
end
|
2839
|
-
end
|
2840
|
-
if fn
|
2841
|
-
rf, is_new = rantfile_for_path(fn)
|
2842
|
-
load_file rf if is_new
|
2843
|
-
return
|
2844
|
-
end
|
2845
|
-
have_sub_rantfile = test(?f, Rant::SUB_RANTFILE)
|
2846
|
-
if have_sub_rantfile || @opts[:look_up]
|
2847
|
-
cur_dir = Dir.pwd
|
2848
|
-
until cur_dir == "/"
|
2849
|
-
cur_dir = File.dirname(cur_dir)
|
2850
|
-
Dir.chdir cur_dir
|
2851
|
-
fn = rantfile_in_dir
|
2852
|
-
if fn
|
2853
|
-
@initial_subdir = @rootdir.sub(
|
2854
|
-
/^#{Regexp.escape cur_dir}\//, '')
|
2855
|
-
@rootdir = cur_dir
|
2856
|
-
cmd_msg "(root is #@rootdir, in #@initial_subdir)"
|
2857
|
-
@last_build_subdir = @initial_subdir
|
2858
|
-
rf, is_new = rantfile_for_path(fn)
|
2859
|
-
load_file rf if is_new
|
2860
|
-
goto_project_dir @initial_subdir
|
2861
|
-
if have_sub_rantfile
|
2862
|
-
rf, is_new = rantfile_for_path(
|
2863
|
-
Rant::SUB_RANTFILE, false)
|
2864
|
-
if is_new
|
2865
|
-
@rantfiles.unshift rf
|
2866
|
-
load_file rf
|
2867
|
-
end
|
2868
|
-
end
|
2869
|
-
break
|
2870
|
-
end
|
2871
|
-
end
|
2872
|
-
end
|
2873
|
-
if @rantfiles.empty?
|
2874
|
-
abort("No Rantfile found, looking for:",
|
2875
|
-
Rant::RANTFILES.join(", "))
|
2876
|
-
end
|
2877
|
-
end
|
2878
|
-
|
2879
|
-
def load_file(rantfile)
|
2880
|
-
vmsg 1, "source #{rantfile}"
|
2881
|
-
@context.instance_eval(File.read(rantfile), rantfile)
|
2882
|
-
end
|
2883
|
-
private :load_file
|
2884
|
-
|
2885
|
-
def rantfile_in_dir(dir=nil)
|
2886
|
-
::Rant::RANTFILES.each { |rfn|
|
2887
|
-
path = dir ? File.join(dir, rfn) : rfn
|
2888
|
-
return path if test ?f, path
|
2889
|
-
}
|
2890
|
-
nil
|
2891
|
-
end
|
2892
|
-
|
2893
|
-
def process_args
|
2894
|
-
old_argv = ARGV.dup
|
2895
|
-
ARGV.replace(@args.dup)
|
2896
|
-
cmd_opts = GetoptLong.new(*OPTIONS.collect { |lst| lst[0..-2] })
|
2897
|
-
cmd_opts.quiet = true
|
2898
|
-
cmd_opts.each { |opt, value|
|
2899
|
-
case opt
|
2900
|
-
when "--verbose": @opts[:verbose] += 1
|
2901
|
-
when "--version"
|
2902
|
-
puts "rant #{Rant::VERSION}"
|
2903
|
-
raise Rant::RantDoneException
|
2904
|
-
when "--help"
|
2905
|
-
show_help
|
2906
|
-
raise Rant::RantDoneException
|
2907
|
-
when "--directory"
|
2908
|
-
@rootdir = File.expand_path(value)
|
2909
|
-
when "--rantfile"
|
2910
|
-
@arg_rantfiles << value
|
2911
|
-
when "--force-run"
|
2912
|
-
@force_targets << value
|
2913
|
-
when "--import"
|
2914
|
-
import value
|
2915
|
-
else
|
2916
|
-
@opts[opt.sub(/^--/, '').tr('-', "_").to_sym] = true
|
2917
|
-
end
|
2918
|
-
}
|
2919
|
-
rescue GetoptLong::Error => e
|
2920
|
-
abort(e.message)
|
2921
|
-
ensure
|
2922
|
-
rem_args = ARGV.dup
|
2923
|
-
ARGV.replace(old_argv)
|
2924
|
-
rem_args.each { |ra|
|
2925
|
-
if ra =~ /(^[^=]+)=([^=]+)$/
|
2926
|
-
vmsg 2, "var: #$1=#$2"
|
2927
|
-
@var[$1] = $2
|
2928
|
-
else
|
2929
|
-
@arg_targets << ra
|
2930
|
-
end
|
2931
|
-
}
|
2932
|
-
end
|
2933
|
-
|
2934
|
-
def prepare_task(targ, block, clr = caller[2])
|
2935
|
-
|
2936
|
-
if targ.is_a? Hash
|
2937
|
-
targ.reject! { |k, v| clr = v if k == :__caller__ }
|
2938
|
-
end
|
2939
|
-
ch = Hash === clr ? clr : Rant::Lib::parse_caller_elem(clr)
|
2940
|
-
|
2941
|
-
name, pre = normalize_task_arg(targ, ch)
|
2942
|
-
|
2943
|
-
file, is_new = rantfile_for_path(ch[:file])
|
2944
|
-
nt = yield(name, pre, block)
|
2945
|
-
nt.rantfile = file
|
2946
|
-
nt.project_subdir = @current_subdir
|
2947
|
-
nt.line_number = ch[:ln]
|
2948
|
-
nt.description = @task_desc
|
2949
|
-
@task_desc = nil
|
2950
|
-
file.tasks << nt
|
2951
|
-
hash_task nt
|
2952
|
-
nt
|
2953
|
-
end
|
2954
|
-
public :prepare_task
|
2955
|
-
|
2956
|
-
def hash_task(task)
|
2957
|
-
n = task.full_name
|
2958
|
-
et = @tasks[n]
|
2959
|
-
case et
|
2960
|
-
when nil
|
2961
|
-
@tasks[n] = task
|
2962
|
-
when Rant::Node
|
2963
|
-
mt = [et, task]
|
2964
|
-
@tasks[n] = mt
|
2965
|
-
else # assuming list of tasks
|
2966
|
-
et << task
|
2967
|
-
end
|
2968
|
-
end
|
2969
|
-
|
2970
|
-
def normalize_task_arg(targ, ch)
|
2971
|
-
name = nil
|
2972
|
-
pre = []
|
2973
|
-
|
2974
|
-
if targ.is_a? Hash
|
2975
|
-
if targ.empty?
|
2976
|
-
abort_at(ch, "Empty hash as task argument, " +
|
2977
|
-
"task name required.")
|
2978
|
-
end
|
2979
|
-
if targ.size > 1
|
2980
|
-
abort_at(ch, "Too many hash elements, " +
|
2981
|
-
"should only be one.")
|
2982
|
-
end
|
2983
|
-
targ.each_pair { |k,v|
|
2984
|
-
name = normalize_task_name(k, ch)
|
2985
|
-
pre = v
|
2986
|
-
}
|
2987
|
-
unless ::Rant::FileList === pre
|
2988
|
-
if pre.respond_to? :to_ary
|
2989
|
-
pre = pre.to_ary.dup
|
2990
|
-
pre.map! { |elem|
|
2991
|
-
normalize_task_name(elem, ch)
|
2992
|
-
}
|
2993
|
-
else
|
2994
|
-
pre = [normalize_task_name(pre, ch)]
|
2995
|
-
end
|
2996
|
-
end
|
2997
|
-
else
|
2998
|
-
name = normalize_task_name(targ, ch)
|
2999
|
-
end
|
3000
|
-
|
3001
|
-
[name, pre]
|
3002
|
-
end
|
3003
|
-
public :normalize_task_arg
|
3004
|
-
|
3005
|
-
def normalize_task_name(arg, ch)
|
3006
|
-
return arg if arg.is_a? String
|
3007
|
-
if Symbol === arg
|
3008
|
-
arg.to_s
|
3009
|
-
elsif arg.respond_to? :to_str
|
3010
|
-
arg.to_str
|
3011
|
-
else
|
3012
|
-
abort_at(ch, "Task name has to be a string or symbol.")
|
3013
|
-
end
|
3014
|
-
end
|
3015
|
-
|
3016
|
-
def rantfile_for_path(path, register=true)
|
3017
|
-
abs_path = File.expand_path(path)
|
3018
|
-
file = @rantfiles.find { |rf| rf.path == abs_path }
|
3019
|
-
if file
|
3020
|
-
[file, false]
|
3021
|
-
else
|
3022
|
-
file = Rant::Rantfile.new abs_path
|
3023
|
-
file.project_subdir = @current_subdir
|
3024
|
-
@rantfiles << file if register
|
3025
|
-
[file, true]
|
3026
|
-
end
|
3027
|
-
end
|
3028
|
-
|
3029
|
-
def get_ch_from_backtrace(backtrace)
|
3030
|
-
backtrace.each { |clr|
|
3031
|
-
ch = ::Rant::Lib.parse_caller_elem(clr)
|
3032
|
-
if ::Rant::Env.on_windows?
|
3033
|
-
return ch if @rantfiles.any? { |rf|
|
3034
|
-
rf.path.tr("\\", "/").sub(/^\w\:/, '') ==
|
3035
|
-
ch[:file].tr("\\", "/").sub(/^\w\:/, '')
|
3036
|
-
}
|
3037
|
-
else
|
3038
|
-
return ch if @rantfiles.any? { |rf|
|
3039
|
-
rf.path == ch[:file]
|
3040
|
-
}
|
3041
|
-
end
|
3042
|
-
}
|
3043
|
-
nil
|
3044
|
-
end
|
3045
|
-
|
3046
|
-
def err_task_fail(e)
|
3047
|
-
msg = []
|
3048
|
-
t_msg = ["Task `#{e.tname}' fail."]
|
3049
|
-
orig = e
|
3050
|
-
loop { orig = orig.orig; break unless Rant::TaskFail === orig }
|
3051
|
-
if orig && orig != e && !(Rant::RantAbortException === orig)
|
3052
|
-
ch = get_ch_from_backtrace(orig.backtrace)
|
3053
|
-
msg << pos_text(ch[:file], ch[:ln]) if ch
|
3054
|
-
unless Rant::CommandError === orig && !@opts[:err_commands]
|
3055
|
-
msg << orig.message
|
3056
|
-
msg << orig.backtrace[0..4] unless ch
|
3057
|
-
end
|
3058
|
-
end
|
3059
|
-
if e.msg && !e.msg.empty?
|
3060
|
-
ch = get_ch_from_backtrace(e.backtrace)
|
3061
|
-
t_msg.unshift(e.msg)
|
3062
|
-
t_msg.unshift(pos_text(ch[:file], ch[:ln])) if ch
|
3063
|
-
end
|
3064
|
-
err_msg msg unless msg.empty?
|
3065
|
-
err_msg t_msg
|
3066
|
-
end
|
3067
|
-
end # class Rant::RantApp
|
3068
|
-
|
3069
|
-
|
3070
|
-
|
3071
|
-
|
3072
|
-
module Rant end
|
3073
|
-
module Rant::C
|
3074
|
-
module Include
|
3075
|
-
def parse_includes(src)
|
3076
|
-
if src.respond_to? :to_str
|
3077
|
-
src = src.to_str
|
3078
|
-
else
|
3079
|
-
raise ArgumentError, "src has to be a string"
|
3080
|
-
end
|
3081
|
-
s_includes = []
|
3082
|
-
l_includes = []
|
3083
|
-
in_block_comment = false
|
3084
|
-
prev_line = nil
|
3085
|
-
src.each { |line|
|
3086
|
-
line.chomp!
|
3087
|
-
if block_start_i = line.index("/*")
|
3088
|
-
c_start_i = line.index("//")
|
3089
|
-
if !c_start_i || block_start_i < c_start_i
|
3090
|
-
if block_end_i = line.index("*/")
|
3091
|
-
if block_end_i > block_start_i
|
3092
|
-
line[block_start_i..block_end_i+1] = ""
|
3093
|
-
end
|
3094
|
-
end
|
3095
|
-
end
|
3096
|
-
end
|
3097
|
-
if prev_line
|
3098
|
-
line = prev_line << line
|
3099
|
-
prev_line = nil
|
3100
|
-
end
|
3101
|
-
if line =~ /\\$/
|
3102
|
-
prev_line = line.chomp[0...line.length-1]
|
3103
|
-
end
|
3104
|
-
if in_block_comment
|
3105
|
-
in_block_comment = false if line =~ %r|\*/|
|
3106
|
-
next
|
3107
|
-
end
|
3108
|
-
case line
|
3109
|
-
when /\s*#\s*include\s+"([^"]+)"/
|
3110
|
-
l_includes << $1
|
3111
|
-
when /\s*#\s*include\s+<([^>]+)>/
|
3112
|
-
s_includes << $1
|
3113
|
-
when %r|(?!//)[^/]*/\*|
|
3114
|
-
in_block_comment = true
|
3115
|
-
end
|
3116
|
-
}
|
3117
|
-
[s_includes, l_includes]
|
3118
|
-
end
|
3119
|
-
module_function :parse_includes
|
3120
|
-
end # module Include
|
3121
|
-
end # module Rant::C
|
3122
|
-
|
3123
|
-
module Rant::Generators::C end
|
3124
|
-
class Rant::Generators::C::Dependencies
|
3125
|
-
def self.rant_gen(rac, ch, args, &block)
|
3126
|
-
c_files, out_fn, include_pathes, opts = nil
|
3127
|
-
if block
|
3128
|
-
rac.warn_msg "C::Dependencies: ignoring block"
|
3129
|
-
end
|
3130
|
-
case args.size
|
3131
|
-
when 0 # noop
|
3132
|
-
when 1
|
3133
|
-
farg = args.first
|
3134
|
-
Hash === farg ? (opts = farg) : (out_fn = farg)
|
3135
|
-
when 2
|
3136
|
-
out_fn = args.first
|
3137
|
-
opts = args[1]
|
3138
|
-
else
|
3139
|
-
rac.abort_at(ch,
|
3140
|
-
"C::Dependencies takes one or two arguments.")
|
3141
|
-
end
|
3142
|
-
correct_case = false
|
3143
|
-
if opts
|
3144
|
-
if opts.respond_to? :to_hash
|
3145
|
-
opts = opts.to_hash
|
3146
|
-
else
|
3147
|
-
rac.abort_at(ch,
|
3148
|
-
"C::Dependencies: second argument has to be a hash.")
|
3149
|
-
end
|
3150
|
-
opts.each { |k, v|
|
3151
|
-
case k
|
3152
|
-
when :sources
|
3153
|
-
c_files = v
|
3154
|
-
when :search, :search_pathes, :include_pathes
|
3155
|
-
include_pathes =
|
3156
|
-
if v.respond_to? :to_str
|
3157
|
-
[v.to_str]
|
3158
|
-
else
|
3159
|
-
v
|
3160
|
-
end
|
3161
|
-
when :correct_case
|
3162
|
-
correct_case = !!v
|
3163
|
-
else
|
3164
|
-
rac.abort_at(ch,
|
3165
|
-
"C::Dependencies: no such option -- #{k}")
|
3166
|
-
end
|
3167
|
-
}
|
3168
|
-
end
|
3169
|
-
out_fn ||= "c_dependencies"
|
3170
|
-
c_files ||= rac.cx.sys["**/*.{c,cpp,cc,h,hpp}"]
|
3171
|
-
include_pathes ||= ["."]
|
3172
|
-
if out_fn.respond_to? :to_str
|
3173
|
-
out_fn = out_fn.to_str
|
3174
|
-
else
|
3175
|
-
rac.abort_at(ch, "filename has to be a string")
|
3176
|
-
end
|
3177
|
-
unless ::Rant::FileList === c_files
|
3178
|
-
if c_files.respond_to? :to_ary
|
3179
|
-
c_files = c_files.to_ary
|
3180
|
-
else
|
3181
|
-
rac.abort_at(ch, "sources has to be a list of files")
|
3182
|
-
end
|
3183
|
-
end
|
3184
|
-
unless ::Rant::FileList === include_pathes
|
3185
|
-
if include_pathes.respond_to? :to_ary
|
3186
|
-
include_pathes = include_pathes.to_ary
|
3187
|
-
else
|
3188
|
-
rac.abort_at(ch,
|
3189
|
-
"search has to be a list of directories")
|
3190
|
-
end
|
3191
|
-
end
|
3192
|
-
rac.cx.file({:__caller__ => ch, out_fn => c_files}) do |t|
|
3193
|
-
tmp_rac = ::Rant::RantApp.new
|
3194
|
-
depfile_ts = Time.at(0)
|
3195
|
-
if File.exist? t.name
|
3196
|
-
tmp_rac.source(t.name)
|
3197
|
-
depfile_ts = File.mtime(t.name)
|
3198
|
-
end
|
3199
|
-
rf_str = ""
|
3200
|
-
c_files.each { |cf|
|
3201
|
-
f_task = nil
|
3202
|
-
unless test(?f, cf)
|
3203
|
-
rac.warn_msg "#{t.name}: no such file -- #{cf}"
|
3204
|
-
next
|
3205
|
-
end
|
3206
|
-
f_task = tmp_rac.tasks[cf.to_str]
|
3207
|
-
deps = f_task ? f_task.prerequisites : nil
|
3208
|
-
if !deps or File.mtime(cf) > depfile_ts
|
3209
|
-
rac.cmd_msg "scanning #{cf}"
|
3210
|
-
std_includes, local_includes =
|
3211
|
-
::Rant::C::Include.parse_includes(File.read(cf))
|
3212
|
-
deps = []
|
3213
|
-
(std_includes + local_includes).each { |fn|
|
3214
|
-
path = existing_file(
|
3215
|
-
include_pathes, fn, correct_case)
|
3216
|
-
deps << path if path
|
3217
|
-
}
|
3218
|
-
end
|
3219
|
-
rf_str << file_deps(cf, deps) << "\n"
|
3220
|
-
}
|
3221
|
-
rac.vmsg 1, "writing C source dependencies to #{t.name}"
|
3222
|
-
open(t.name, "w") { |f|
|
3223
|
-
f.puts
|
3224
|
-
f.puts "# #{t.name}"
|
3225
|
-
f.puts "# C source dependencies generated by Rant #{Rant::VERSION}"
|
3226
|
-
f.puts "# WARNING: Modifications to this file will get lost!"
|
3227
|
-
f.puts
|
3228
|
-
f.write rf_str
|
3229
|
-
}
|
3230
|
-
end
|
3231
|
-
end
|
3232
|
-
def self.existing_file(dirs, fn, correct_case)
|
3233
|
-
dirs.each { |dir|
|
3234
|
-
path = dir == "." ? fn : File.join(dir, fn)
|
3235
|
-
if test ?f, path
|
3236
|
-
return path unless correct_case
|
3237
|
-
found_file = File.basename(fn)
|
3238
|
-
found_in_dir = File.dirname(File.join(dir, fn))
|
3239
|
-
Dir.entries(found_in_dir).each { |dentry|
|
3240
|
-
return File.join(found_in_dir, dentry) if dentry.downcase == found_file.downcase
|
3241
|
-
}
|
3242
|
-
end
|
3243
|
-
}
|
3244
|
-
nil
|
3245
|
-
end
|
3246
|
-
def self.file_deps(target, deps)
|
3247
|
-
s = "gen SourceNode, #{target.to_str.dump} => "
|
3248
|
-
s << "[#{ deps.map{ |fn| fn.to_str.dump }.join(', ')}]"
|
3249
|
-
end
|
3250
|
-
end # class Rant::Generators::C::Dependencies
|
3251
|
-
|
3252
|
-
|
3253
|
-
|
3254
|
-
class Rant::Generators::DirectedRule
|
3255
|
-
def self.rant_gen(rac, ch, args, &block)
|
3256
|
-
unless args.size == 1
|
3257
|
-
rac.abort_at(ch, "DirectedRule takes one arguments.")
|
3258
|
-
end
|
3259
|
-
h = args.first
|
3260
|
-
if h.respond_to? :to_hash
|
3261
|
-
h = h.to_hash
|
3262
|
-
else
|
3263
|
-
rac.abort_at(ch, "Argument has to be a hash.")
|
3264
|
-
end
|
3265
|
-
ts_h, dir_h = nil, nil
|
3266
|
-
h.each { |k, v| v.respond_to?(:to_ary) ?
|
3267
|
-
dir_h = { k => v } :
|
3268
|
-
ts_h = { k => v }
|
3269
|
-
}
|
3270
|
-
unless dir_h
|
3271
|
-
rac.abort_at(ch,
|
3272
|
-
"Source directory argument has to be a list.")
|
3273
|
-
end
|
3274
|
-
target, source = nil, nil
|
3275
|
-
ts_h.each { |target, source| }
|
3276
|
-
target_dir, source_dirs = nil, nil
|
3277
|
-
dir_h.each { |target_dir, source_dirs| }
|
3278
|
-
if target_dir.respond_to? :to_str
|
3279
|
-
target_dir = target_dir.to_str
|
3280
|
-
else
|
3281
|
-
rac.abort_at(ch, "String required as target directory.")
|
3282
|
-
end
|
3283
|
-
if source_dirs.respond_to? :to_ary
|
3284
|
-
source_dirs = source_dirs.to_ary
|
3285
|
-
elsif source_dirs.respond_to? :to_str
|
3286
|
-
source_dirs = [source_dirs.to_str]
|
3287
|
-
else
|
3288
|
-
rac.abort_at(ch,
|
3289
|
-
"List of strings or string required for source directories.")
|
3290
|
-
end
|
3291
|
-
target = ".#{target}" if Symbol === target
|
3292
|
-
source = ".#{source}" if Symbol === source
|
3293
|
-
if target.respond_to? :to_str
|
3294
|
-
target = target.to_str
|
3295
|
-
else
|
3296
|
-
rac.abort_at(ch, "target has to be a string")
|
3297
|
-
end
|
3298
|
-
if source.respond_to? :to_str
|
3299
|
-
source = source.to_str
|
3300
|
-
else
|
3301
|
-
rac.abort_at(ch, "source has to be a string or symbol")
|
3302
|
-
end
|
3303
|
-
blk = self.new(rac, ch, target_dir, source_dirs,
|
3304
|
-
target, source, &block)
|
3305
|
-
blk.define_hook
|
3306
|
-
blk
|
3307
|
-
end
|
3308
|
-
def initialize(rac, ch, target_dir, source_dirs,
|
3309
|
-
target, source, &block)
|
3310
|
-
@rac = rac
|
3311
|
-
@ch = ch
|
3312
|
-
@source_dirs = source_dirs
|
3313
|
-
@target_dir = target_dir
|
3314
|
-
@target = target.sub(/^\./, '')
|
3315
|
-
@target_rx = /#{Regexp.escape(target)}$/
|
3316
|
-
@source = source.sub(/^\./, '')
|
3317
|
-
@esc_target_dir = Regexp.escape(target_dir)
|
3318
|
-
@block = block
|
3319
|
-
end
|
3320
|
-
def [](name, rel_project_dir)
|
3321
|
-
if name =~ /^#@esc_target_dir\// && name =~ @target_rx
|
3322
|
-
fn = File.basename(name)
|
3323
|
-
src_fn = fn.sub_ext(@source)
|
3324
|
-
src = nil
|
3325
|
-
@source_dirs.each { |d|
|
3326
|
-
path = File.join(d, src_fn)
|
3327
|
-
(src = path) && break if test(?e, path)
|
3328
|
-
}
|
3329
|
-
if src
|
3330
|
-
[@rac.prepare_task({name => src}, @block, @ch) { |name,pre,blk|
|
3331
|
-
@rac.node_factory.new_auto_subfile(@rac, name, pre, blk)
|
3332
|
-
}]
|
3333
|
-
else
|
3334
|
-
nil
|
3335
|
-
end
|
3336
|
-
else
|
3337
|
-
nil
|
3338
|
-
end
|
3339
|
-
end
|
3340
|
-
def define_hook
|
3341
|
-
@rac.resolve_hooks << self
|
3342
|
-
end
|
3343
|
-
def each_target(&block)
|
3344
|
-
@rac.cx.sys["#@target_dir/*"].each { |entry|
|
3345
|
-
yield entry if entry =~ @target_rx
|
3346
|
-
}
|
3347
|
-
end
|
3348
|
-
def candidates
|
3349
|
-
sources.map { |src|
|
3350
|
-
File.join(@target_dir, File.basename(src).sub_ext(@target))
|
3351
|
-
}
|
3352
|
-
end
|
3353
|
-
def sources
|
3354
|
-
cl = []
|
3355
|
-
@source_dirs.each { |dir|
|
3356
|
-
cl.concat(@rac.cx.sys["#{dir}/*.#@source"])
|
3357
|
-
}
|
3358
|
-
cl
|
3359
|
-
end
|
3360
|
-
end # class Rant::Generators::DirectedRule
|
3361
|
-
|
3362
|
-
|
3363
|
-
|
3364
|
-
class Rant::Generators::Clean
|
3365
|
-
def self.rant_gen(rac, ch, args, &block)
|
3366
|
-
if args.size > 1
|
3367
|
-
rac.abort_at(ch, "Clean doesn't take more than one argument.")
|
3368
|
-
end
|
3369
|
-
tname = args.first || "clean"
|
3370
|
-
|
3371
|
-
case rac.var[tname]
|
3372
|
-
when nil
|
3373
|
-
rac.var[tname] = Rant::MultiFileList.new(rac)
|
3374
|
-
when Rant::RacFileList
|
3375
|
-
ml = Rant::MultiFileList.new(rac)
|
3376
|
-
rac.var[tname] = ml.add(rac.var[tname])
|
3377
|
-
when Rant::MultiFileList
|
3378
|
-
else
|
3379
|
-
rac.abort_at(ch,
|
3380
|
-
"var `#{tname}' already exists.",
|
3381
|
-
"Clean uses var with the same name as the task name.")
|
3382
|
-
end
|
3383
|
-
|
3384
|
-
rac.task :__caller__ => ch, tname => [] do |t|
|
3385
|
-
rac.var[tname].each_entry { |entry|
|
3386
|
-
if test ?e, entry
|
3387
|
-
if test ?f, entry
|
3388
|
-
rac.cx.sys.rm_f entry
|
3389
|
-
else
|
3390
|
-
rac.cx.sys.rm_rf entry
|
3391
|
-
end
|
3392
|
-
end
|
3393
|
-
}
|
3394
|
-
end
|
3395
|
-
end
|
3396
|
-
end # class Rant::Generators::Clean
|
3397
|
-
|
3398
|
-
|
3399
|
-
|
3400
|
-
|
3401
|
-
module Rant; end
|
3402
|
-
module Rant::Archive; end
|
3403
|
-
module Rant::Archive::Minitar; end
|
3404
|
-
|
3405
|
-
class Rant::Archive::Minitar::PosixHeader
|
3406
|
-
FIELDS = %w(name mode uid gid size mtime checksum typeflag linkname) +
|
3407
|
-
%w(magic version uname gname devmajor devminor prefix)
|
3408
|
-
|
3409
|
-
FIELDS.each { |field| attr_reader field.intern }
|
3410
|
-
|
3411
|
-
HEADER_PACK_FORMAT = "a100a8a8a8a12a12a7aaa100a6a2a32a32a8a8a155"
|
3412
|
-
HEADER_UNPACK_FORMAT = "Z100A8A8A8A12A12A8aZ100A6A2Z32Z32A8A8Z155"
|
3413
|
-
|
3414
|
-
def self.new_from_stream(stream)
|
3415
|
-
data = stream.read(512)
|
3416
|
-
fields = data.unpack(HEADER_UNPACK_FORMAT)
|
3417
|
-
name = fields.shift
|
3418
|
-
mode = fields.shift.oct
|
3419
|
-
uid = fields.shift.oct
|
3420
|
-
gid = fields.shift.oct
|
3421
|
-
size = fields.shift.oct
|
3422
|
-
mtime = fields.shift.oct
|
3423
|
-
checksum = fields.shift.oct
|
3424
|
-
typeflag = fields.shift
|
3425
|
-
linkname = fields.shift
|
3426
|
-
magic = fields.shift
|
3427
|
-
version = fields.shift.oct
|
3428
|
-
uname = fields.shift
|
3429
|
-
gname = fields.shift
|
3430
|
-
devmajor = fields.shift.oct
|
3431
|
-
devminor = fields.shift.oct
|
3432
|
-
prefix = fields.shift
|
3433
|
-
|
3434
|
-
empty = (data == "\0" * 512)
|
3435
|
-
|
3436
|
-
new(:name => name, :mode => mode, :uid => uid, :gid => gid,
|
3437
|
-
:size => size, :mtime => mtime, :checksum => checksum,
|
3438
|
-
:typeflag => typeflag, :magic => magic, :version => version,
|
3439
|
-
:uname => uname, :gname => gname, :devmajor => devmajor,
|
3440
|
-
:devminor => devminor, :prefix => prefix, :empty => empty)
|
3441
|
-
end
|
3442
|
-
|
3443
|
-
def initialize(vals)
|
3444
|
-
unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode]
|
3445
|
-
raise ArgumentError
|
3446
|
-
end
|
3447
|
-
|
3448
|
-
vals[:mtime] ||= 0
|
3449
|
-
vals[:checksum] ||= ""
|
3450
|
-
vals[:typeflag] ||= "0"
|
3451
|
-
vals[:magic] ||= "ustar"
|
3452
|
-
vals[:version] ||= "00"
|
3453
|
-
|
3454
|
-
FIELDS.each do |field|
|
3455
|
-
instance_variable_set("@#{field}", vals[field.intern])
|
3456
|
-
end
|
3457
|
-
@empty = vals[:empty]
|
3458
|
-
end
|
3459
|
-
|
3460
|
-
def empty?
|
3461
|
-
@empty
|
3462
|
-
end
|
3463
|
-
|
3464
|
-
def to_s
|
3465
|
-
update_checksum
|
3466
|
-
header(@checksum)
|
3467
|
-
end
|
3468
|
-
|
3469
|
-
def update_checksum
|
3470
|
-
hh = header(" " * 8)
|
3471
|
-
@checksum = oct(calculate_checksum(hh), 6)
|
3472
|
-
end
|
3473
|
-
|
3474
|
-
private
|
3475
|
-
def oct(num, len)
|
3476
|
-
if num.nil?
|
3477
|
-
"\0" * (len + 1)
|
3478
|
-
else
|
3479
|
-
"%0#{len}o" % num
|
3480
|
-
end
|
3481
|
-
end
|
3482
|
-
|
3483
|
-
def calculate_checksum(hdr)
|
3484
|
-
hdr.unpack("C*").inject { |aa, bb| aa + bb }
|
3485
|
-
end
|
3486
|
-
|
3487
|
-
def header(chksum)
|
3488
|
-
arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),
|
3489
|
-
oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version,
|
3490
|
-
uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
|
3491
|
-
str = arr.pack(HEADER_PACK_FORMAT)
|
3492
|
-
str + "\0" * ((512 - str.size) % 512)
|
3493
|
-
end
|
3494
|
-
end
|
3495
|
-
|
3496
|
-
require 'fileutils'
|
3497
|
-
require 'find'
|
3498
|
-
|
3499
|
-
module Rant::Archive::Minitar
|
3500
|
-
VERSION = "0.5.1"
|
3501
|
-
|
3502
|
-
class NonSeekableStream < StandardError; end
|
3503
|
-
class BlockRequired < ArgumentError; end
|
3504
|
-
class ClosedStream < StandardError; end
|
3505
|
-
class FileNameTooLong < StandardError; end
|
3506
|
-
class UnexpectedEOF < StandardError; end
|
3507
|
-
|
3508
|
-
class Writer
|
3509
|
-
class RestrictedStream
|
3510
|
-
def initialize(anIO)
|
3511
|
-
@io = anIO
|
3512
|
-
end
|
3513
|
-
|
3514
|
-
def write(data)
|
3515
|
-
@io.write(data)
|
3516
|
-
end
|
3517
|
-
end
|
3518
|
-
|
3519
|
-
class BoundedStream < Rant::Archive::Minitar::Writer::RestrictedStream
|
3520
|
-
class FileOverflow < RuntimeError; end
|
3521
|
-
|
3522
|
-
attr_reader :limit
|
3523
|
-
attr_reader :written
|
3524
|
-
|
3525
|
-
def initialize(io, limit)
|
3526
|
-
@io = io
|
3527
|
-
@limit = limit
|
3528
|
-
@written = 0
|
3529
|
-
end
|
3530
|
-
|
3531
|
-
def write(data)
|
3532
|
-
raise FileOverflow if (data.size + @written) > @limit
|
3533
|
-
@io.write(data)
|
3534
|
-
@written += data.size
|
3535
|
-
data.size
|
3536
|
-
end
|
3537
|
-
end
|
3538
|
-
|
3539
|
-
def self.open(anIO)
|
3540
|
-
writer = Writer.new(anIO)
|
3541
|
-
|
3542
|
-
return writer unless block_given?
|
3543
|
-
|
3544
|
-
begin
|
3545
|
-
res = yield writer
|
3546
|
-
ensure
|
3547
|
-
writer.close
|
3548
|
-
end
|
3549
|
-
|
3550
|
-
res
|
3551
|
-
end
|
3552
|
-
|
3553
|
-
def initialize(anIO)
|
3554
|
-
@io = anIO
|
3555
|
-
@closed = false
|
3556
|
-
end
|
3557
|
-
|
3558
|
-
def add_file_simple(name, opts = {}) # :yields BoundedStream:
|
3559
|
-
raise Rant::Archive::Minitar::BlockRequired unless block_given?
|
3560
|
-
raise Rant::Archive::Minitar::ClosedStream if @closed
|
3561
|
-
|
3562
|
-
name, prefix = split_name(name)
|
3563
|
-
|
3564
|
-
header = { :name => name, :mode => opts[:mode], :mtime => opts[:mtime],
|
3565
|
-
:size => opts[:size], :gid => opts[:gid], :uid => opts[:uid],
|
3566
|
-
:prefix => prefix }
|
3567
|
-
header = Rant::Archive::Minitar::PosixHeader.new(header).to_s
|
3568
|
-
@io.write(header)
|
3569
|
-
|
3570
|
-
os = BoundedStream.new(@io, opts[:size])
|
3571
|
-
yield os
|
3572
|
-
|
3573
|
-
min_padding = opts[:size] - os.written
|
3574
|
-
@io.write("\0" * min_padding)
|
3575
|
-
remainder = (512 - (opts[:size] % 512)) % 512
|
3576
|
-
@io.write("\0" * remainder)
|
3577
|
-
end
|
3578
|
-
|
3579
|
-
def add_file(name, opts = {}) # :yields RestrictedStream, +opts+:
|
3580
|
-
raise Rant::Archive::Minitar::BlockRequired unless block_given?
|
3581
|
-
raise Rant::Archive::Minitar::ClosedStream if @closed
|
3582
|
-
raise Rant::Archive::Minitar::NonSeekableStream unless @io.respond_to?(:pos=)
|
3583
|
-
|
3584
|
-
name, prefix = split_name(name)
|
3585
|
-
init_pos = @io.pos
|
3586
|
-
@io.write("\0" * 512) # placeholder for the header
|
3587
|
-
|
3588
|
-
yield RestrictedStream.new(@io), opts
|
3589
|
-
|
3590
|
-
size = @io.pos - (init_pos + 512)
|
3591
|
-
remainder = (512 - (size % 512)) % 512
|
3592
|
-
@io.write("\0" * remainder)
|
3593
|
-
|
3594
|
-
final_pos = @io.pos
|
3595
|
-
@io.pos = init_pos
|
3596
|
-
|
3597
|
-
header = { :name => name, :mode => opts[:mode], :mtime => opts[:mtime],
|
3598
|
-
:size => size, :gid => opts[:gid], :uid => opts[:uid],
|
3599
|
-
:prefix => prefix }
|
3600
|
-
header = Rant::Archive::Minitar::PosixHeader.new(header).to_s
|
3601
|
-
@io.write(header)
|
3602
|
-
@io.pos = final_pos
|
3603
|
-
end
|
3604
|
-
|
3605
|
-
def mkdir(name, opts = {})
|
3606
|
-
raise ClosedStream if @closed
|
3607
|
-
name, prefix = split_name(name)
|
3608
|
-
header = { :name => name, :mode => opts[:mode], :typeflag => "5",
|
3609
|
-
:size => 0, :gid => opts[:gid], :uid => opts[:uid],
|
3610
|
-
:mtime => opts[:mtime], :prefix => prefix }
|
3611
|
-
header = Rant::Archive::Minitar::PosixHeader.new(header).to_s
|
3612
|
-
@io.write(header)
|
3613
|
-
nil
|
3614
|
-
end
|
3615
|
-
|
3616
|
-
def flush
|
3617
|
-
raise ClosedStream if @closed
|
3618
|
-
@io.flush if @io.respond_to?(:flush)
|
3619
|
-
end
|
3620
|
-
|
3621
|
-
def close
|
3622
|
-
return if @closed
|
3623
|
-
@io.write("\0" * 1024)
|
3624
|
-
@closed = true
|
3625
|
-
end
|
3626
|
-
|
3627
|
-
private
|
3628
|
-
def split_name(name)
|
3629
|
-
raise FileNameTooLong if name.size > 256
|
3630
|
-
if name.size <= 100
|
3631
|
-
prefix = ""
|
3632
|
-
else
|
3633
|
-
parts = name.split(/\//)
|
3634
|
-
newname = parts.pop
|
3635
|
-
|
3636
|
-
nxt = ""
|
3637
|
-
|
3638
|
-
loop do
|
3639
|
-
nxt = parts.pop
|
3640
|
-
break if newname.size + 1 + nxt.size > 100
|
3641
|
-
newname = "#{nxt}/#{newname}"
|
3642
|
-
end
|
3643
|
-
|
3644
|
-
prefix = (parts + [nxt]).join("/")
|
3645
|
-
|
3646
|
-
name = newname
|
3647
|
-
|
3648
|
-
raise FileNameTooLong if name.size > 100 || prefix.size > 155
|
3649
|
-
end
|
3650
|
-
return name, prefix
|
3651
|
-
end
|
3652
|
-
end
|
3653
|
-
|
3654
|
-
class Reader
|
3655
|
-
module InvalidEntryStream
|
3656
|
-
def read(len = nil); raise ClosedStream; end
|
3657
|
-
def getc; raise ClosedStream; end
|
3658
|
-
def rewind; raise ClosedStream; end
|
3659
|
-
end
|
3660
|
-
|
3661
|
-
class EntryStream
|
3662
|
-
Rant::Archive::Minitar::PosixHeader::FIELDS.each do |field|
|
3663
|
-
attr_reader field.intern
|
3664
|
-
end
|
3665
|
-
|
3666
|
-
def initialize(header, anIO)
|
3667
|
-
@io = anIO
|
3668
|
-
@name = header.name
|
3669
|
-
@mode = header.mode
|
3670
|
-
@uid = header.uid
|
3671
|
-
@gid = header.gid
|
3672
|
-
@size = header.size
|
3673
|
-
@mtime = header.mtime
|
3674
|
-
@checksum = header.checksum
|
3675
|
-
@typeflag = header.typeflag
|
3676
|
-
@linkname = header.linkname
|
3677
|
-
@magic = header.magic
|
3678
|
-
@version = header.version
|
3679
|
-
@uname = header.uname
|
3680
|
-
@gname = header.gname
|
3681
|
-
@devmajor = header.devmajor
|
3682
|
-
@devminor = header.devminor
|
3683
|
-
@prefix = header.prefix
|
3684
|
-
@read = 0
|
3685
|
-
@orig_pos = @io.pos
|
3686
|
-
end
|
3687
|
-
|
3688
|
-
def read(len = nil)
|
3689
|
-
return nil if @read >= @size
|
3690
|
-
len ||= @size - @read
|
3691
|
-
max_read = [len, @size - @read].min
|
3692
|
-
ret = @io.read(max_read)
|
3693
|
-
@read += ret.size
|
3694
|
-
ret
|
3695
|
-
end
|
3696
|
-
|
3697
|
-
def getc
|
3698
|
-
return nil if @read >= @size
|
3699
|
-
ret = @io.getc
|
3700
|
-
@read += 1 if ret
|
3701
|
-
ret
|
3702
|
-
end
|
3703
|
-
|
3704
|
-
def directory?
|
3705
|
-
@typeflag == "5"
|
3706
|
-
end
|
3707
|
-
alias_method :directory, :directory?
|
3708
|
-
|
3709
|
-
def file?
|
3710
|
-
@typeflag == "0"
|
3711
|
-
end
|
3712
|
-
alias_method :file, :file?
|
3713
|
-
|
3714
|
-
def eof?
|
3715
|
-
@read >= @size
|
3716
|
-
end
|
3717
|
-
|
3718
|
-
def pos
|
3719
|
-
@read
|
3720
|
-
end
|
3721
|
-
|
3722
|
-
def rewind
|
3723
|
-
raise NonSeekableStream unless @io.respond_to?(:pos=)
|
3724
|
-
@io.pos = @orig_pos
|
3725
|
-
@read = 0
|
3726
|
-
end
|
3727
|
-
|
3728
|
-
def bytes_read
|
3729
|
-
@read
|
3730
|
-
end
|
3731
|
-
|
3732
|
-
def full_name
|
3733
|
-
if @prefix != ""
|
3734
|
-
File.join(@prefix, @name)
|
3735
|
-
else
|
3736
|
-
@name
|
3737
|
-
end
|
3738
|
-
end
|
3739
|
-
|
3740
|
-
def close
|
3741
|
-
invalidate
|
3742
|
-
end
|
3743
|
-
|
3744
|
-
private
|
3745
|
-
def invalidate
|
3746
|
-
extend InvalidEntryStream
|
3747
|
-
end
|
3748
|
-
end
|
3749
|
-
|
3750
|
-
def self.open(anIO)
|
3751
|
-
reader = Reader.new(anIO)
|
3752
|
-
|
3753
|
-
return reader unless block_given?
|
3754
|
-
|
3755
|
-
begin
|
3756
|
-
res = yield reader
|
3757
|
-
ensure
|
3758
|
-
reader.close
|
3759
|
-
end
|
3760
|
-
|
3761
|
-
res
|
3762
|
-
end
|
3763
|
-
|
3764
|
-
def initialize(anIO)
|
3765
|
-
@io = anIO
|
3766
|
-
@init_pos = anIO.pos
|
3767
|
-
end
|
3768
|
-
|
3769
|
-
def each(&block)
|
3770
|
-
each_entry(&block)
|
3771
|
-
end
|
3772
|
-
|
3773
|
-
def rewind
|
3774
|
-
if @init_pos == 0
|
3775
|
-
raise NonSeekableStream unless @io.respond_to?(:rewind)
|
3776
|
-
@io.rewind
|
3777
|
-
else
|
3778
|
-
raise NonSeekableStream unless @io.respond_to?(:pos=)
|
3779
|
-
@io.pos = @init_pos
|
3780
|
-
end
|
3781
|
-
end
|
3782
|
-
|
3783
|
-
def each_entry
|
3784
|
-
loop do
|
3785
|
-
return if @io.eof?
|
3786
|
-
|
3787
|
-
header = Rant::Archive::Minitar::PosixHeader.new_from_stream(@io)
|
3788
|
-
return if header.empty?
|
3789
|
-
|
3790
|
-
entry = EntryStream.new(header, @io)
|
3791
|
-
size = entry.size
|
3792
|
-
|
3793
|
-
yield entry
|
3794
|
-
|
3795
|
-
skip = (512 - (size % 512)) % 512
|
3796
|
-
|
3797
|
-
if @io.respond_to?(:seek)
|
3798
|
-
@io.seek(size - entry.bytes_read, IO::SEEK_CUR)
|
3799
|
-
else
|
3800
|
-
pending = size - entry.bytes_read
|
3801
|
-
while pending > 0
|
3802
|
-
bread = @io.read([pending, 4096].min).size
|
3803
|
-
raise UnexpectedEOF if @io.eof?
|
3804
|
-
pending -= bread
|
3805
|
-
end
|
3806
|
-
end
|
3807
|
-
@io.read(skip) # discard trailing zeros
|
3808
|
-
entry.close
|
3809
|
-
end
|
3810
|
-
end
|
3811
|
-
|
3812
|
-
def close
|
3813
|
-
end
|
3814
|
-
end
|
3815
|
-
|
3816
|
-
class Input
|
3817
|
-
include Enumerable
|
3818
|
-
|
3819
|
-
def self.open(input)
|
3820
|
-
stream = Input.new(input)
|
3821
|
-
return stream unless block_given?
|
3822
|
-
|
3823
|
-
begin
|
3824
|
-
res = yield stream
|
3825
|
-
ensure
|
3826
|
-
stream.close
|
3827
|
-
end
|
3828
|
-
|
3829
|
-
res
|
3830
|
-
end
|
3831
|
-
|
3832
|
-
def initialize(input)
|
3833
|
-
if input.respond_to?(:read)
|
3834
|
-
@io = input
|
3835
|
-
else
|
3836
|
-
@io = open(input, "rb")
|
3837
|
-
end
|
3838
|
-
@tarreader = Rant::Archive::Minitar::Reader.new(@io)
|
3839
|
-
end
|
3840
|
-
|
3841
|
-
def each(&block)
|
3842
|
-
@tarreader.each { |entry| yield entry }
|
3843
|
-
ensure
|
3844
|
-
@tarreader.rewind
|
3845
|
-
end
|
3846
|
-
|
3847
|
-
def extract_entry(destdir, entry) # :yields action, name, stats:
|
3848
|
-
stats = {
|
3849
|
-
:current => 0,
|
3850
|
-
:currinc => 0,
|
3851
|
-
:entry => entry
|
3852
|
-
}
|
3853
|
-
|
3854
|
-
if entry.directory?
|
3855
|
-
dest = File.join(destdir, entry.full_name)
|
3856
|
-
|
3857
|
-
yield :dir, entry.full_name, stats if block_given?
|
3858
|
-
|
3859
|
-
if Rant::Archive::Minitar.dir?(dest)
|
3860
|
-
begin
|
3861
|
-
FileUtils.chmod(entry.mode, dest)
|
3862
|
-
rescue Exception
|
3863
|
-
nil
|
3864
|
-
end
|
3865
|
-
else
|
3866
|
-
FileUtils.mkdir_p(dest, :mode => entry.mode)
|
3867
|
-
FileUtils.chmod(entry.mode, dest)
|
3868
|
-
end
|
3869
|
-
|
3870
|
-
fsync_dir(dest)
|
3871
|
-
fsync_dir(File.join(dest, ".."))
|
3872
|
-
return
|
3873
|
-
else # it's a file
|
3874
|
-
destdir = File.join(destdir, File.dirname(entry.full_name))
|
3875
|
-
FileUtils.mkdir_p(destdir, :mode => 0755)
|
3876
|
-
|
3877
|
-
destfile = File.join(destdir, File.basename(entry.full_name))
|
3878
|
-
FileUtils.chmod(0600, destfile) rescue nil # Errno::ENOENT
|
3879
|
-
|
3880
|
-
yield :file_start, entry.full_name, stats if block_given?
|
3881
|
-
|
3882
|
-
File.open(destfile, "wb", entry.mode) do |os|
|
3883
|
-
loop do
|
3884
|
-
data = entry.read(4096)
|
3885
|
-
break unless data
|
3886
|
-
|
3887
|
-
stats[:currinc] = os.write(data)
|
3888
|
-
stats[:current] += stats[:currinc]
|
3889
|
-
|
3890
|
-
yield :file_progress, entry.full_name, stats if block_given?
|
3891
|
-
end
|
3892
|
-
os.fsync
|
3893
|
-
end
|
3894
|
-
|
3895
|
-
FileUtils.chmod(entry.mode, destfile)
|
3896
|
-
fsync_dir(File.dirname(destfile))
|
3897
|
-
fsync_dir(File.join(File.dirname(destfile), ".."))
|
3898
|
-
|
3899
|
-
yield :file_done, entry.full_name, stats if block_given?
|
3900
|
-
end
|
3901
|
-
end
|
3902
|
-
|
3903
|
-
def tar
|
3904
|
-
@tarreader
|
3905
|
-
end
|
3906
|
-
|
3907
|
-
def close
|
3908
|
-
@io.close
|
3909
|
-
@tarreader.close
|
3910
|
-
end
|
3911
|
-
|
3912
|
-
private
|
3913
|
-
def fsync_dir(dirname)
|
3914
|
-
dir = open(dirname, 'rb')
|
3915
|
-
dir.fsync
|
3916
|
-
rescue # ignore IOError if it's an unpatched (old) Ruby
|
3917
|
-
nil
|
3918
|
-
ensure
|
3919
|
-
dir.close if dir rescue nil
|
3920
|
-
end
|
3921
|
-
end
|
3922
|
-
|
3923
|
-
class Output
|
3924
|
-
def self.open(output)
|
3925
|
-
stream = Output.new(output)
|
3926
|
-
return stream unless block_given?
|
3927
|
-
|
3928
|
-
begin
|
3929
|
-
res = yield stream
|
3930
|
-
ensure
|
3931
|
-
stream.close
|
3932
|
-
end
|
3933
|
-
|
3934
|
-
res
|
3935
|
-
end
|
3936
|
-
|
3937
|
-
def initialize(output)
|
3938
|
-
if output.respond_to?(:write)
|
3939
|
-
@io = output
|
3940
|
-
else
|
3941
|
-
@io = ::File.open(output, "wb")
|
3942
|
-
end
|
3943
|
-
@tarwriter = Rant::Archive::Minitar::Writer.new(@io)
|
3944
|
-
end
|
3945
|
-
|
3946
|
-
def tar
|
3947
|
-
@tarwriter
|
3948
|
-
end
|
3949
|
-
|
3950
|
-
def close
|
3951
|
-
@tarwriter.close
|
3952
|
-
@io.close
|
3953
|
-
end
|
3954
|
-
end
|
3955
|
-
|
3956
|
-
class << self
|
3957
|
-
def dir?(path)
|
3958
|
-
File.directory?((path[-1] == ?/) ? path : "#{path}/")
|
3959
|
-
end
|
3960
|
-
|
3961
|
-
def open(dest, mode = "r", &block)
|
3962
|
-
case mode
|
3963
|
-
when "r"
|
3964
|
-
Input.open(dest, &block)
|
3965
|
-
when "w"
|
3966
|
-
Output.open(dest, &block)
|
3967
|
-
else
|
3968
|
-
raise "Unknown open mode for Rant::Archive::Minitar.open."
|
3969
|
-
end
|
3970
|
-
end
|
3971
|
-
|
3972
|
-
def pack_file(entry, outputter) #:yields action, name, stats:
|
3973
|
-
outputter = outputter.tar if outputter.kind_of?(Rant::Archive::Minitar::Output)
|
3974
|
-
|
3975
|
-
stats = {}
|
3976
|
-
|
3977
|
-
if entry.kind_of?(Hash)
|
3978
|
-
name = entry[:name]
|
3979
|
-
|
3980
|
-
entry.each { |kk, vv| stats[kk] = vv unless vv.nil? }
|
3981
|
-
else
|
3982
|
-
name = entry
|
3983
|
-
end
|
3984
|
-
|
3985
|
-
name = name.sub(%r{\./}, '')
|
3986
|
-
stat = File.stat(name)
|
3987
|
-
stats[:mode] ||= stat.mode
|
3988
|
-
stats[:mtime] ||= stat.mtime
|
3989
|
-
stats[:size] = stat.size
|
3990
|
-
|
3991
|
-
if RUBY_PLATFORM =~ /win32/
|
3992
|
-
stats[:uid] = nil
|
3993
|
-
stats[:gid] = nil
|
3994
|
-
else
|
3995
|
-
stats[:uid] ||= stat.uid
|
3996
|
-
stats[:gid] ||= stat.gid
|
3997
|
-
end
|
3998
|
-
|
3999
|
-
case
|
4000
|
-
when File.file?(name)
|
4001
|
-
outputter.add_file_simple(name, stats) do |os|
|
4002
|
-
stats[:current] = 0
|
4003
|
-
yield :file_start, name, stats if block_given?
|
4004
|
-
File.open(name, "rb") do |ff|
|
4005
|
-
until ff.eof?
|
4006
|
-
stats[:currinc] = os.write(ff.read(4096))
|
4007
|
-
stats[:current] += stats[:currinc]
|
4008
|
-
yield :file_progress, name, stats if block_given?
|
4009
|
-
end
|
4010
|
-
end
|
4011
|
-
yield :file_done, name, stats if block_given?
|
4012
|
-
end
|
4013
|
-
when dir?(name)
|
4014
|
-
yield :dir, name, stats if block_given?
|
4015
|
-
outputter.mkdir(name, stats)
|
4016
|
-
else
|
4017
|
-
raise "Don't yet know how to pack this type of file."
|
4018
|
-
end
|
4019
|
-
end
|
4020
|
-
|
4021
|
-
def pack(src, dest, recurse_dirs = true, &block)
|
4022
|
-
Output.open(dest) do |outp|
|
4023
|
-
if src.kind_of?(Array)
|
4024
|
-
src.each do |entry|
|
4025
|
-
pack_file(entry, outp, &block)
|
4026
|
-
if dir?(entry) and recurse_dirs
|
4027
|
-
Dir["#{entry}/**/**"].each do |ee|
|
4028
|
-
pack_file(ee, outp, &block)
|
4029
|
-
end
|
4030
|
-
end
|
4031
|
-
end
|
4032
|
-
else
|
4033
|
-
Find.find(src) do |entry|
|
4034
|
-
pack_file(entry, outp, &block)
|
4035
|
-
end
|
4036
|
-
end
|
4037
|
-
end
|
4038
|
-
end
|
4039
|
-
|
4040
|
-
def unpack(src, dest, files = [], &block)
|
4041
|
-
Input.open(src) do |inp|
|
4042
|
-
if File.exist?(dest) and (not dir?(dest))
|
4043
|
-
raise "Can't unpack to a non-directory."
|
4044
|
-
elsif not File.exist?(dest)
|
4045
|
-
FileUtils.mkdir_p(dest)
|
4046
|
-
end
|
4047
|
-
|
4048
|
-
inp.each do |entry|
|
4049
|
-
if files.empty? or files.include?(entry.full_name)
|
4050
|
-
inp.extract_entry(dest, entry, &block)
|
4051
|
-
end
|
4052
|
-
end
|
4053
|
-
end
|
4054
|
-
end
|
4055
|
-
end
|
4056
|
-
end
|
4057
|
-
|
4058
|
-
module Rant
|
4059
|
-
module Sys
|
4060
|
-
def unpack_tgz(archive, opts={})
|
4061
|
-
output_dir = opts[:to] || opts[:in] || "."
|
4062
|
-
mkpath output_dir unless test ?d, output_dir
|
4063
|
-
if Env.have_tar?
|
4064
|
-
sh "tar", "-xzf", archive, "-C", output_dir
|
4065
|
-
else
|
4066
|
-
minitar_unpack(archive, output_dir)
|
4067
|
-
end
|
4068
|
-
nil
|
4069
|
-
end
|
4070
|
-
private
|
4071
|
-
def minitar_tgz(fn, files, opts)
|
4072
|
-
require 'zlib'
|
4073
|
-
fu_output_message "minitar #{fn}"
|
4074
|
-
files = files.to_ary if files.respond_to? :to_ary
|
4075
|
-
tgz = Zlib::GzipWriter.new(File.open(fn, 'wb'))
|
4076
|
-
Rant::Archive::Minitar.pack(files, tgz, opts[:recurse])
|
4077
|
-
nil
|
4078
|
-
end
|
4079
|
-
def minitar_unpack(archive, output_dir)
|
4080
|
-
fu_output_message "unpacking #{archive} in #{output_dir}"
|
4081
|
-
require 'zlib'
|
4082
|
-
tgz = Zlib::GzipReader.new(File.open(archive, 'rb'))
|
4083
|
-
Archive::Minitar.unpack(tgz, output_dir)
|
4084
|
-
end
|
4085
|
-
end # module Sys
|
4086
|
-
end # module Rant
|
4087
|
-
|
4088
|
-
$".concat(['rant/rantlib.rb', 'rant/init.rb', 'rant/rantvar.rb', 'rant/rantsys.rb', 'rant/import/filelist/core.rb', 'rant/node.rb', 'rant/import/nodes/default.rb', 'rant/coregen.rb', 'rant/import/c/dependencies.rb', 'rant/c/include.rb', 'rant/import/directedrule.rb', 'rant/import/clean.rb', 'rant/import/sys/tgz.rb', 'rant/archive/minitar.rb'])
|
4089
|
-
Rant::CODE_IMPORTS.concat %w(c/dependencies directedrule nodes/default clean sys/tgz
|
4090
|
-
)
|
4091
|
-
|
4092
|
-
# Catch a `require "rant"', sad...
|
4093
|
-
alias require_backup_by_rant require
|
4094
|
-
def require libf
|
4095
|
-
if libf == "rant"
|
4096
|
-
# TODO: needs rework! look at lib/rant.rb
|
4097
|
-
self.class.instance_eval { include Rant }
|
4098
|
-
else
|
4099
|
-
begin
|
4100
|
-
require_backup_by_rant libf
|
4101
|
-
rescue
|
4102
|
-
raise $!, caller
|
4103
|
-
end
|
4104
|
-
end
|
4105
|
-
end
|
4106
|
-
|
4107
|
-
exit Rant.run
|