rant 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +504 -0
- data/README +203 -0
- data/Rantfile +104 -0
- data/TODO +19 -0
- data/bin/rant +12 -0
- data/bin/rant-import +12 -0
- data/devel-notes +50 -0
- data/doc/configure.rdoc +40 -0
- data/doc/csharp.rdoc +74 -0
- data/doc/rant-import.rdoc +32 -0
- data/doc/rant.rdoc +24 -0
- data/doc/rantfile.rdoc +227 -0
- data/doc/rubyproject.rdoc +210 -0
- data/lib/rant.rb +9 -0
- data/lib/rant/cs_compiler.rb +334 -0
- data/lib/rant/import.rb +291 -0
- data/lib/rant/import/rubydoc.rb +125 -0
- data/lib/rant/import/rubypackage.rb +417 -0
- data/lib/rant/import/rubytest.rb +97 -0
- data/lib/rant/plugin/README +50 -0
- data/lib/rant/plugin/configure.rb +345 -0
- data/lib/rant/plugin/csharp.rb +275 -0
- data/lib/rant/plugin_methods.rb +41 -0
- data/lib/rant/rantenv.rb +217 -0
- data/lib/rant/rantfile.rb +664 -0
- data/lib/rant/rantlib.rb +1118 -0
- data/lib/rant/rantsys.rb +258 -0
- data/lib/rant/rantvar.rb +82 -0
- data/rantmethods.rb +79 -0
- data/run_import +7 -0
- data/run_rant +7 -0
- data/setup.rb +1360 -0
- data/test/Rantfile +2 -0
- data/test/plugin/configure/Rantfile +47 -0
- data/test/plugin/configure/test_configure.rb +58 -0
- data/test/plugin/csharp/Hello.cs +10 -0
- data/test/plugin/csharp/Rantfile +30 -0
- data/test/plugin/csharp/src/A.cs +8 -0
- data/test/plugin/csharp/src/B.cs +8 -0
- data/test/plugin/csharp/test_csharp.rb +99 -0
- data/test/project1/Rantfile +127 -0
- data/test/project1/test_project.rb +203 -0
- data/test/project2/buildfile +14 -0
- data/test/project2/rantfile.rb +20 -0
- data/test/project2/sub1/Rantfile +12 -0
- data/test/project2/test_project.rb +87 -0
- data/test/project_rb1/README +14 -0
- data/test/project_rb1/bin/wgrep +5 -0
- data/test/project_rb1/lib/wgrep.rb +56 -0
- data/test/project_rb1/rantfile.rb +30 -0
- data/test/project_rb1/test/tc_wgrep.rb +21 -0
- data/test/project_rb1/test/text +3 -0
- data/test/project_rb1/test_project_rb1.rb +153 -0
- data/test/test_env.rb +47 -0
- data/test/test_filetask.rb +57 -0
- data/test/test_lighttask.rb +49 -0
- data/test/test_metatask.rb +29 -0
- data/test/test_rant_interface.rb +65 -0
- data/test/test_sys.rb +61 -0
- data/test/test_task.rb +115 -0
- data/test/toplevel.rf +11 -0
- data/test/ts_all.rb +4 -0
- data/test/tutil.rb +95 -0
- metadata +133 -0
@@ -0,0 +1,664 @@
|
|
1
|
+
|
2
|
+
require 'rant/rantenv'
|
3
|
+
|
4
|
+
module Rant
|
5
|
+
class TaskFail < StandardError
|
6
|
+
def initialize(*args)
|
7
|
+
@task = args.shift
|
8
|
+
super(args.shift)
|
9
|
+
end
|
10
|
+
def task
|
11
|
+
@task
|
12
|
+
end
|
13
|
+
def tname
|
14
|
+
@task ? @task.name : nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Rantfile < Path
|
19
|
+
|
20
|
+
attr_reader :tasks
|
21
|
+
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
@tasks = []
|
25
|
+
end
|
26
|
+
end # class Rantfile
|
27
|
+
|
28
|
+
module Worker
|
29
|
+
|
30
|
+
INVOKE_OPT = {}.freeze
|
31
|
+
|
32
|
+
# Name of the task, this is always a string.
|
33
|
+
attr_reader :name
|
34
|
+
# A reference to the application this task belongs to.
|
35
|
+
attr_reader :app
|
36
|
+
# Description for this task.
|
37
|
+
attr_accessor :description
|
38
|
+
# The rantfile this task was defined in.
|
39
|
+
# Should be a Rant::Rantfile instance.
|
40
|
+
attr_accessor :rantfile
|
41
|
+
# The linenumber in rantfile where this task was defined.
|
42
|
+
attr_accessor :line_number
|
43
|
+
|
44
|
+
def initialize
|
45
|
+
@description = nil
|
46
|
+
@rantfile = nil
|
47
|
+
@line_number = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the +name+ attribute.
|
51
|
+
def to_s
|
52
|
+
name
|
53
|
+
end
|
54
|
+
|
55
|
+
def done?
|
56
|
+
@done
|
57
|
+
end
|
58
|
+
|
59
|
+
def needed?
|
60
|
+
!done?
|
61
|
+
end
|
62
|
+
|
63
|
+
# +opt+ shouldn't be modified
|
64
|
+
def invoke(opt = INVOKE_OPT)
|
65
|
+
self.run if opt[:force] || self.needed?
|
66
|
+
end
|
67
|
+
|
68
|
+
def fail msg = nil
|
69
|
+
raise TaskFail.new(self), msg, caller
|
70
|
+
end
|
71
|
+
|
72
|
+
def run
|
73
|
+
return unless @block
|
74
|
+
@block.arity == 0 ? @block.call : @block[self]
|
75
|
+
end
|
76
|
+
private :run
|
77
|
+
|
78
|
+
def hash
|
79
|
+
name.hash
|
80
|
+
end
|
81
|
+
|
82
|
+
def eql? other
|
83
|
+
Worker === other and name.eql? other.name
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# A list of tasks with an equal name.
|
88
|
+
class MetaTask < Array
|
89
|
+
include Worker
|
90
|
+
|
91
|
+
class << self
|
92
|
+
def for_task t
|
93
|
+
mt = self.new(t.name)
|
94
|
+
mt << t
|
95
|
+
end
|
96
|
+
def for_tasks *tasks
|
97
|
+
mt = self.new(tasks.first.name)
|
98
|
+
mt.concat tasks
|
99
|
+
mt
|
100
|
+
end
|
101
|
+
def for_task_list tasks
|
102
|
+
mt = self.new(tasks.first.name)
|
103
|
+
mt.concat tasks
|
104
|
+
mt
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def initialize(name)
|
109
|
+
super()
|
110
|
+
@name = name or raise ArgumentError, "no name given"
|
111
|
+
end
|
112
|
+
|
113
|
+
def done?
|
114
|
+
all? { |t| t.done? }
|
115
|
+
end
|
116
|
+
|
117
|
+
def needed?
|
118
|
+
any? { |t| t.needed? }
|
119
|
+
end
|
120
|
+
|
121
|
+
def invoke(opt = INVOKE_OPT)
|
122
|
+
uf = false
|
123
|
+
each { |t| t.invoke(opt) && uf = true }
|
124
|
+
end
|
125
|
+
|
126
|
+
def description
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def description=(val)
|
131
|
+
# spit out a warning?
|
132
|
+
end
|
133
|
+
|
134
|
+
def rantfile
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
|
138
|
+
def rantfile=(val)
|
139
|
+
# spit out a warning?
|
140
|
+
end
|
141
|
+
|
142
|
+
def line_number
|
143
|
+
0
|
144
|
+
end
|
145
|
+
|
146
|
+
def line_number=(val)
|
147
|
+
# spit out a warning?
|
148
|
+
end
|
149
|
+
|
150
|
+
def app
|
151
|
+
empty? ? nil : first.app
|
152
|
+
end
|
153
|
+
end # class MetaTask
|
154
|
+
|
155
|
+
# A very lightweight task for special purposes.
|
156
|
+
class LightTask
|
157
|
+
include Worker
|
158
|
+
|
159
|
+
class << self
|
160
|
+
def rant_generate(app, ch, args, &block)
|
161
|
+
unless args.size == 1
|
162
|
+
app.abort("LightTask takes only one argument " +
|
163
|
+
"which has to be the taskname (string or symbol)")
|
164
|
+
end
|
165
|
+
app.prepare_task({args.first => [], :__caller__ => ch},
|
166
|
+
block) { |name,pre,blk|
|
167
|
+
# TODO: ensure pre is empty
|
168
|
+
# TODO: earlier setting of app?
|
169
|
+
t = self.new(app, name, &blk)
|
170
|
+
t
|
171
|
+
}
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def initialize(app, name)
|
176
|
+
super()
|
177
|
+
@app = app or raise ArgumentError, "no app given"
|
178
|
+
@name = case name
|
179
|
+
when String: name
|
180
|
+
when Symbol: name.to_s
|
181
|
+
else
|
182
|
+
raise ArgumentError,
|
183
|
+
"invalid name argument: #{name.inspect}"
|
184
|
+
end
|
185
|
+
@needed = nil
|
186
|
+
@block = nil
|
187
|
+
@done = false
|
188
|
+
|
189
|
+
yield self if block_given?
|
190
|
+
end
|
191
|
+
|
192
|
+
def app
|
193
|
+
@app || Rant.rantapp
|
194
|
+
end
|
195
|
+
|
196
|
+
def needed &block
|
197
|
+
@needed = block
|
198
|
+
end
|
199
|
+
|
200
|
+
def act &block
|
201
|
+
@block = block
|
202
|
+
end
|
203
|
+
|
204
|
+
# Cause task to fail. Usually called from inside the block
|
205
|
+
# given to +act+.
|
206
|
+
def fail msg = nil
|
207
|
+
raise TaskFail.new(self), msg, caller
|
208
|
+
end
|
209
|
+
|
210
|
+
def needed?
|
211
|
+
return false if done?
|
212
|
+
return true if @needed.nil?
|
213
|
+
if @needed.arity == 0
|
214
|
+
@needed.call
|
215
|
+
else
|
216
|
+
@needed[self]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def invoke(opt = INVOKE_OPT)
|
221
|
+
if opt[:force] && !@done
|
222
|
+
self.run
|
223
|
+
@done = true
|
224
|
+
else
|
225
|
+
if needed?
|
226
|
+
run
|
227
|
+
@done = true
|
228
|
+
else
|
229
|
+
false
|
230
|
+
end
|
231
|
+
end
|
232
|
+
rescue CommandError => e
|
233
|
+
err_msg e.message if app[:err_commands]
|
234
|
+
self.fail
|
235
|
+
rescue SystemCallError => e
|
236
|
+
err_msg e.message
|
237
|
+
self.fail
|
238
|
+
end
|
239
|
+
end # LightTask
|
240
|
+
|
241
|
+
class Task
|
242
|
+
include Worker
|
243
|
+
include Console
|
244
|
+
|
245
|
+
T0 = Time.at(0).freeze
|
246
|
+
|
247
|
+
class << self
|
248
|
+
def rant_generate(app, ch, args, &block)
|
249
|
+
if args.size == 1
|
250
|
+
if Hash === args.first
|
251
|
+
UserTask.rant_generate(app, ch, args, &block)
|
252
|
+
else
|
253
|
+
LightTask.rant_generate(app, ch, args, &block)
|
254
|
+
end
|
255
|
+
else
|
256
|
+
app.abort("Task generator currently takes only one" +
|
257
|
+
" argument. (Generates a LightTask or UserTask)")
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def initialize(app, name, prerequisites = [], &block)
|
263
|
+
super()
|
264
|
+
@app = app || Rant.rantapp
|
265
|
+
@name = name or raise ArgumentError, "name not given"
|
266
|
+
@pre = prerequisites || []
|
267
|
+
@pre_resolved = false
|
268
|
+
@block = block
|
269
|
+
@run = false
|
270
|
+
@fail = false
|
271
|
+
end
|
272
|
+
|
273
|
+
# Get a list of the *names* of all prerequisites. The
|
274
|
+
# underlying list of prerequisites can't be modified by the
|
275
|
+
# value returned by this method.
|
276
|
+
def prerequisites
|
277
|
+
@pre.collect { |pre| pre.to_s }
|
278
|
+
end
|
279
|
+
|
280
|
+
# True if this task has at least one action (block to be
|
281
|
+
# executed) associated.
|
282
|
+
def has_actions?
|
283
|
+
!!@block
|
284
|
+
end
|
285
|
+
|
286
|
+
# Add a prerequisite.
|
287
|
+
def <<(pre)
|
288
|
+
@pre_resolved = false
|
289
|
+
@pre << pre
|
290
|
+
end
|
291
|
+
|
292
|
+
# Was this task ever run? If this is true, it doesn't
|
293
|
+
# necessarily mean that the run was successfull!
|
294
|
+
def run?
|
295
|
+
@run
|
296
|
+
end
|
297
|
+
|
298
|
+
# True if last task run fail.
|
299
|
+
def fail?
|
300
|
+
@fail
|
301
|
+
end
|
302
|
+
|
303
|
+
# Task was run and didn't fail.
|
304
|
+
def done?
|
305
|
+
run? && !fail?
|
306
|
+
end
|
307
|
+
|
308
|
+
# Enhance this task with the given dependencies and blk.
|
309
|
+
def enhance(deps = [], &blk)
|
310
|
+
if deps
|
311
|
+
@pre_resolved = false
|
312
|
+
@pre.concat deps
|
313
|
+
end
|
314
|
+
if blk
|
315
|
+
first_block = @block
|
316
|
+
@block = lambda { |t|
|
317
|
+
first_block[t]
|
318
|
+
blk[t]
|
319
|
+
}
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def needed?
|
324
|
+
invoke(:needed? => true)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Returns a true value if task was acutally run.
|
328
|
+
# Raises Rant::TaskFail to signal task (or prerequiste) failure.
|
329
|
+
def invoke(opt = INVOKE_OPT)
|
330
|
+
return if done?
|
331
|
+
internal_invoke opt
|
332
|
+
end
|
333
|
+
|
334
|
+
def internal_invoke opt, ud_init = true
|
335
|
+
update = ud_init || opt[:force]
|
336
|
+
dep = nil
|
337
|
+
uf = false
|
338
|
+
each_dep { |dep|
|
339
|
+
if FileTask === dep
|
340
|
+
handle_filetask(dep, opt) && update = true
|
341
|
+
elsif Worker === dep
|
342
|
+
handle_worker(dep, opt) && update = true
|
343
|
+
else
|
344
|
+
dep, uf = handle_non_worker(dep, opt)
|
345
|
+
uf && update = true
|
346
|
+
dep
|
347
|
+
end
|
348
|
+
}
|
349
|
+
# Never run a task block for a "needed?" query.
|
350
|
+
return update if opt[:needed?]
|
351
|
+
if update
|
352
|
+
@run = true
|
353
|
+
run
|
354
|
+
end
|
355
|
+
@run
|
356
|
+
rescue StandardError => e
|
357
|
+
@fail = true
|
358
|
+
case e
|
359
|
+
when TaskFail: raise
|
360
|
+
when CommandError
|
361
|
+
err_msg e.message if app[:err_commands]
|
362
|
+
when SystemCallError
|
363
|
+
err_msg e.message
|
364
|
+
else
|
365
|
+
err_msg e.message, e.backtrace
|
366
|
+
end
|
367
|
+
self.fail
|
368
|
+
end
|
369
|
+
private :internal_invoke
|
370
|
+
|
371
|
+
# Called from internal_invoke. +dep+ is a prerequisite which
|
372
|
+
# is_a? Worker, but not a FileTask. +opt+ are opts as given to
|
373
|
+
# Worker#invoke.
|
374
|
+
#
|
375
|
+
# Override this method in subclasses to modify behaviour of
|
376
|
+
# prerequisite handling.
|
377
|
+
#
|
378
|
+
# See also: handle_filetask, handle_non_worker
|
379
|
+
def handle_worker(dep, opt)
|
380
|
+
dep.invoke opt
|
381
|
+
end
|
382
|
+
|
383
|
+
# Called from internal_invoke. +dep+ is a prerequisite which
|
384
|
+
# is_a? FileTask. +opt+ are opts as given to Worker#invoke.
|
385
|
+
#
|
386
|
+
# Override this method in subclasses to modify behaviour of
|
387
|
+
# prerequisite handling.
|
388
|
+
#
|
389
|
+
# See also: handle_worker, handle_non_worker
|
390
|
+
def handle_filetask(dep, opt)
|
391
|
+
dep.invoke opt
|
392
|
+
end
|
393
|
+
|
394
|
+
# Override in subclass if specific task can handle
|
395
|
+
# non-task-prerequisites.
|
396
|
+
#
|
397
|
+
# Notes for overriding:
|
398
|
+
# This method should do one of the two following:
|
399
|
+
# [1] Fail with an exception.
|
400
|
+
# [2] Return two values: replacement_for_dep, update_required
|
401
|
+
#
|
402
|
+
# See also: handle_worker, handle_filetask
|
403
|
+
def handle_non_worker(dep, opt)
|
404
|
+
err_msg "Unknown task `#{dep}',",
|
405
|
+
"referenced in `#{rantfile.path}', line #{@line_number}!"
|
406
|
+
self.fail
|
407
|
+
end
|
408
|
+
|
409
|
+
# For each non-worker prerequiste, the value returned from yield
|
410
|
+
# will replace the original prerequisite (of course only if
|
411
|
+
# @pre_resolved is false).
|
412
|
+
def each_dep
|
413
|
+
t = nil
|
414
|
+
if @pre_resolved
|
415
|
+
return @pre.each { |t| yield(t) }
|
416
|
+
end
|
417
|
+
@pre.map! { |t|
|
418
|
+
if Worker === t
|
419
|
+
# Remove references to self from prerequisites!
|
420
|
+
if t.name == @name
|
421
|
+
nil
|
422
|
+
else
|
423
|
+
yield(t)
|
424
|
+
t
|
425
|
+
end
|
426
|
+
else
|
427
|
+
t = t.to_s if Symbol === t
|
428
|
+
if t == @name
|
429
|
+
nil
|
430
|
+
else
|
431
|
+
# Pre 0.2.6 task selection scheme ###########
|
432
|
+
# Take care: selection is an array of tasks
|
433
|
+
#selection = @app.select_tasks { |st| st.name == t }
|
434
|
+
#############################################
|
435
|
+
|
436
|
+
selection = @app.select_tasks_by_name t
|
437
|
+
if selection.empty?
|
438
|
+
# use return value of yield
|
439
|
+
yield(t)
|
440
|
+
else
|
441
|
+
selection.each { |st| yield(st) }
|
442
|
+
selection
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
}
|
447
|
+
@pre.flatten!
|
448
|
+
@pre.compact!
|
449
|
+
@pre_resolved = true
|
450
|
+
end
|
451
|
+
end # class Task
|
452
|
+
|
453
|
+
# A UserTask is equivalent to a Task, but it additionally takes a
|
454
|
+
# block (see #needed) which is used to determine if it is needed?.
|
455
|
+
class UserTask < Task
|
456
|
+
|
457
|
+
class << self
|
458
|
+
def rant_generate(app, ch, args, &block)
|
459
|
+
unless args.size == 1
|
460
|
+
app.abort("UserTask takes only one argument " +
|
461
|
+
"which has to be like one given to the " +
|
462
|
+
"`task' function")
|
463
|
+
end
|
464
|
+
app.prepare_task(args.first, nil, ch) { |name,pre,blk|
|
465
|
+
self.new(app, name, pre, &block)
|
466
|
+
}
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
def initialize(*args)
|
471
|
+
super
|
472
|
+
# super will set @block to a given block, but the block is
|
473
|
+
# used for initialization, not ment as action
|
474
|
+
@block = nil
|
475
|
+
@needed = nil
|
476
|
+
# allow setting of @block and @needed
|
477
|
+
yield self if block_given?
|
478
|
+
end
|
479
|
+
|
480
|
+
def act &block
|
481
|
+
@block = block
|
482
|
+
end
|
483
|
+
|
484
|
+
def needed &block
|
485
|
+
@needed = block
|
486
|
+
end
|
487
|
+
|
488
|
+
# We simply override this method and call internal_invoke with
|
489
|
+
# the +ud_init+ flag according to the result of a call to the
|
490
|
+
# +needed+ block.
|
491
|
+
def invoke(opt = INVOKE_OPT)
|
492
|
+
return if done?
|
493
|
+
internal_invoke(opt, ud_init_by_needed)
|
494
|
+
end
|
495
|
+
|
496
|
+
private
|
497
|
+
def ud_init_by_needed
|
498
|
+
if @needed
|
499
|
+
@needed.arity == 0 ? @needed.call : @needed[self]
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end # class UserTask
|
503
|
+
|
504
|
+
class FileTask < Task
|
505
|
+
|
506
|
+
def initialize *args
|
507
|
+
super
|
508
|
+
if @name.is_a? Path
|
509
|
+
@path = @name
|
510
|
+
@name = @path.to_s
|
511
|
+
else
|
512
|
+
@path = Path.new @name
|
513
|
+
end
|
514
|
+
@ts = T0
|
515
|
+
end
|
516
|
+
|
517
|
+
def path
|
518
|
+
@path
|
519
|
+
end
|
520
|
+
|
521
|
+
def needed?
|
522
|
+
return false if done?
|
523
|
+
invoke(:needed? => true)
|
524
|
+
end
|
525
|
+
|
526
|
+
def invoke(opt = INVOKE_OPT)
|
527
|
+
return if done?
|
528
|
+
if @path.exist?
|
529
|
+
@ts = @path.mtime
|
530
|
+
internal_invoke opt, false
|
531
|
+
else
|
532
|
+
@ts = T0
|
533
|
+
internal_invoke opt, true
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def handle_filetask(dep, opt)
|
538
|
+
return true if dep.invoke opt
|
539
|
+
# TODO: require dep to exist after invoke?
|
540
|
+
if dep.path.exist?
|
541
|
+
#puts "***`#{dep.name}' requires update" if dep.path.mtime > @ts
|
542
|
+
dep.path.mtime > @ts
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
def handle_non_worker(dep, opt)
|
547
|
+
dep = Path.new(dep) unless Path === dep
|
548
|
+
unless dep.exist?
|
549
|
+
err_msg @app.pos_text(rantfile.path, line_number),
|
550
|
+
"in prerequisites: no such file or task: `#{dep}'"
|
551
|
+
self.fail
|
552
|
+
end
|
553
|
+
[dep, dep.mtime > @ts]
|
554
|
+
end
|
555
|
+
end # class FileTask
|
556
|
+
|
557
|
+
# An instance of this class is a task to create a _single_
|
558
|
+
# directory.
|
559
|
+
class DirTask < Task
|
560
|
+
|
561
|
+
class << self
|
562
|
+
|
563
|
+
# Generate a task for making a directory path.
|
564
|
+
# Prerequisites can be given, which will be added as
|
565
|
+
# prerequistes for the _last_ directory.
|
566
|
+
#
|
567
|
+
# A special feature is used if you provide a block: The
|
568
|
+
# block will be called after complete directory creation.
|
569
|
+
# After the block execution, the modification time of the
|
570
|
+
# directory will be updated.
|
571
|
+
def rant_generate(app, ch, args, &block)
|
572
|
+
if args && args.size == 1
|
573
|
+
name, pre, file, ln = app.normalize_task_arg(args.first, ch)
|
574
|
+
self.task(app, ch, name, pre, &block)
|
575
|
+
else
|
576
|
+
app.abort(app.pos_text(ch[:file], ch[:ln]),
|
577
|
+
"Directory takes one argument, " +
|
578
|
+
"which should be like one given to the `task' command.")
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
# Returns the task which creates the last directory
|
583
|
+
# element (and has all other necessary directories as
|
584
|
+
# prerequisites).
|
585
|
+
def task(app, ch, name, prerequisites = [], &block)
|
586
|
+
dirs = ::Rant::Sys.split_path(name)
|
587
|
+
if dirs.empty?
|
588
|
+
app.abort(app.pos_text(ch[:file], ch[:ln]),
|
589
|
+
"Not a valid directory name: `#{name}'")
|
590
|
+
end
|
591
|
+
ld = nil
|
592
|
+
path = nil
|
593
|
+
last_task = nil
|
594
|
+
task_block = nil
|
595
|
+
dirs.each { |dir|
|
596
|
+
pre = [ld]
|
597
|
+
pre.compact!
|
598
|
+
if dir.equal?(dirs.last)
|
599
|
+
pre.concat prerequisites if prerequisites
|
600
|
+
task_block = block
|
601
|
+
end
|
602
|
+
path = path.nil? ? dir : File.join(path, dir)
|
603
|
+
last_task = app.prepare_task({:__caller__ => ch,
|
604
|
+
path => pre}, task_block) { |name,pre,blk|
|
605
|
+
self.new(app, name, pre, &blk)
|
606
|
+
}
|
607
|
+
ld = dir
|
608
|
+
}
|
609
|
+
last_task
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
def intialize *args
|
614
|
+
super
|
615
|
+
@ts = T0
|
616
|
+
@isdir = nil
|
617
|
+
end
|
618
|
+
|
619
|
+
def needed?
|
620
|
+
invoke(:needed? => true)
|
621
|
+
end
|
622
|
+
|
623
|
+
def invoke(opt = INVOKE_OPT)
|
624
|
+
return if done?
|
625
|
+
@isdir = test(?d, @name)
|
626
|
+
if @isdir
|
627
|
+
@ts = @block ? test(?M, @name) : Time.now
|
628
|
+
internal_invoke opt, false
|
629
|
+
else
|
630
|
+
@ts = T0
|
631
|
+
internal_invoke opt, true
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
def handle_filetask(dep, opt)
|
636
|
+
return true if dep.invoke opt
|
637
|
+
if dep.path.exist?
|
638
|
+
#puts "***`#{dep.name}' requires update" if dep.path.mtime > @ts
|
639
|
+
dep.path.mtime > @ts
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
def handle_non_worker(dep, opt)
|
644
|
+
dep = Path.new(dep) unless Path === dep
|
645
|
+
unless dep.exist?
|
646
|
+
err_msg @app.pos_text(rantfile.path, line_number),
|
647
|
+
"in prerequisites: no such file or task: `#{dep}'"
|
648
|
+
self.fail
|
649
|
+
end
|
650
|
+
[dep, dep.mtime > @ts]
|
651
|
+
end
|
652
|
+
|
653
|
+
def run
|
654
|
+
@app.sys.mkdir @name unless @isdir
|
655
|
+
if @block
|
656
|
+
@block.arity == 0 ? @block.call : @block[self]
|
657
|
+
@app.sys.touch @name
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
661
|
+
module Generators
|
662
|
+
Directory = ::Rant::DirTask
|
663
|
+
end
|
664
|
+
end # module Rant
|