rant 0.3.6 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- data/NEWS +13 -0
- data/README +7 -1
- data/Rantfile +10 -14
- data/TODO +3 -0
- data/devel-notes +5 -0
- data/doc/advanced.rdoc +46 -0
- data/doc/c.rdoc +64 -0
- data/doc/examples/c_dependencies/Rantfile +27 -0
- data/doc/examples/c_dependencies/include/hello.h +7 -0
- data/doc/examples/c_dependencies/include/util.h +7 -0
- data/doc/examples/c_dependencies/src/main.c +9 -0
- data/doc/examples/c_dependencies/src/util.c +9 -0
- data/doc/examples/directedrule/Rantfile +0 -1
- data/doc/rantfile.rdoc +12 -9
- data/doc/rubyproject.rdoc +26 -0
- data/lib/rant/c/include.rb +51 -0
- data/lib/rant/import/autoclean.rb +16 -9
- data/lib/rant/import/c/dependencies.rb +127 -0
- data/lib/rant/import/directedrule.rb +8 -4
- data/lib/rant/import/rubypackage.rb +2 -1
- data/lib/rant/import/subfile.rb +41 -0
- data/lib/rant/import/truth.rb +6 -1
- data/lib/rant/import/win32/rubycmdwrapper.rb +37 -0
- data/lib/rant/import.rb +26 -3
- data/lib/rant/rantenv.rb +0 -32
- data/lib/rant/rantfile.rb +207 -194
- data/lib/rant/rantlib.rb +83 -150
- data/lib/rant/rantsys.rb +7 -10
- data/lib/rant/rantvar.rb +4 -6
- data/lib/rant.rb +57 -0
- data/rantmethods.rb +1 -47
- data/setup.rb +2 -2
- data/test/Rantfile +6 -1
- data/test/c/source.c +23 -0
- data/test/c/test_parse_includes.rb +41 -0
- data/test/import/c/dependencies/Rantfile +34 -0
- data/test/import/c/dependencies/bar.h +2 -0
- data/test/import/c/dependencies/foo.h +5 -0
- data/test/import/c/dependencies/hello.c +7 -0
- data/test/import/c/dependencies/include/foo.h +0 -0
- data/test/import/c/dependencies/include/sub/sub.h +8 -0
- data/test/import/c/dependencies/include/with space.h +7 -0
- data/test/import/c/dependencies/src/abc +5 -0
- data/test/import/c/dependencies/src/abc.c +5 -0
- data/test/import/c/dependencies/src/bar.c +11 -0
- data/test/import/c/dependencies/test_c_dependencies.rb +92 -0
- data/test/import/c/dependencies/test_on_the_fly.rb +44 -0
- data/test/import/directedrule/Rantfile +7 -2
- data/test/import/directedrule/test_directedrule.rb +6 -0
- data/test/import/subfile/Rantfile +28 -0
- data/test/import/subfile/autoclean.rf +16 -0
- data/test/import/subfile/test_subfile.rb +91 -0
- data/test/import/truth/Rantfile +7 -0
- data/test/import/truth/test_truth.rb +3 -0
- data/test/project2/buildfile +2 -0
- data/test/project2/test_project.rb +5 -3
- data/test/rant-import/Rantfile +4 -0
- data/test/rant-import/test_rant-import.rb +104 -1
- data/test/rule.rf +6 -0
- data/test/test_autosubfiletask.rb +59 -0
- data/test/test_clean.rb +48 -5
- data/test/test_dirtask.rb +45 -1
- data/test/test_examples.rb +25 -3
- data/test/test_filelist.rb +14 -2
- data/test/test_lighttask.rb +4 -6
- data/test/test_rant_interface.rb +8 -8
- data/test/test_rantfile_api.rb +37 -1
- data/test/test_rule.rb +6 -3
- data/test/test_source.rb +28 -1
- data/test/test_sourcenode.rb +163 -0
- data/test/test_task.rb +2 -2
- data/test/test_var.rb +3 -3
- data/test/tutil.rb +23 -2
- metadata +45 -3
- data/test/test_metatask.rb +0 -29
data/lib/rant/rantfile.rb
CHANGED
@@ -24,31 +24,34 @@ module Rant
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
class Rantfile
|
27
|
+
class Rantfile
|
28
28
|
|
29
|
-
attr_reader :tasks
|
29
|
+
attr_reader :tasks, :path
|
30
30
|
attr_accessor :project_subdir
|
31
31
|
|
32
|
-
def initialize(
|
33
|
-
|
32
|
+
def initialize(path)
|
33
|
+
@path = path or raise ArgumentError, "path required"
|
34
34
|
@tasks = []
|
35
35
|
@project_subdir = nil
|
36
36
|
end
|
37
|
+
def to_s
|
38
|
+
@path
|
39
|
+
end
|
37
40
|
end # class Rantfile
|
38
41
|
|
39
42
|
# Any +object+ is considered a _task_ if
|
40
|
-
# <tt>Rant::
|
43
|
+
# <tt>Rant::Node === object</tt> is true.
|
41
44
|
#
|
42
45
|
# Most important classes including this module are the Rant::Task
|
43
46
|
# class and the Rant::FileTask class.
|
44
|
-
module
|
47
|
+
module Node
|
45
48
|
|
46
49
|
INVOKE_OPT = {}.freeze
|
47
50
|
|
48
51
|
# Name of the task, this is always a string.
|
49
52
|
attr_reader :name
|
50
|
-
# A reference to the
|
51
|
-
attr_reader :
|
53
|
+
# A reference to the Rant compiler this task belongs to.
|
54
|
+
attr_reader :rac
|
52
55
|
# Description for this task.
|
53
56
|
attr_accessor :description
|
54
57
|
# The rantfile this task was defined in.
|
@@ -90,7 +93,7 @@ module Rant
|
|
90
93
|
# Important for subclasses: Call this method always before
|
91
94
|
# invoking code from Rantfiles (e.g. task action blocks).
|
92
95
|
def goto_task_home
|
93
|
-
@
|
96
|
+
@rac.goto_project_dir project_subdir
|
94
97
|
end
|
95
98
|
|
96
99
|
def done?
|
@@ -107,11 +110,11 @@ module Rant
|
|
107
110
|
end
|
108
111
|
|
109
112
|
# +opt+ is a Hash and shouldn't be modified.
|
110
|
-
# All objects implementing the Rant::
|
113
|
+
# All objects implementing the Rant::Node protocol should
|
111
114
|
# know about the following +opt+ values:
|
112
115
|
# <tt>:needed?</tt>::
|
113
116
|
# Just check if this task is needed. Should do the same
|
114
|
-
# as calling
|
117
|
+
# as calling Node#needed?
|
115
118
|
# <tt>:force</tt>::
|
116
119
|
# Run task action even if needed? is false.
|
117
120
|
# Returns true if task action was run.
|
@@ -147,7 +150,7 @@ module Rant
|
|
147
150
|
private :run
|
148
151
|
|
149
152
|
def circular_dep
|
150
|
-
|
153
|
+
rac.warn_msg "Circular dependency on task `#{full_name}'."
|
151
154
|
false
|
152
155
|
end
|
153
156
|
private :circular_dep
|
@@ -158,121 +161,40 @@ module Rant
|
|
158
161
|
end
|
159
162
|
|
160
163
|
def eql? other
|
161
|
-
|
162
|
-
end
|
163
|
-
end # module Worker
|
164
|
-
|
165
|
-
# A list of tasks with an equal full_name.
|
166
|
-
class MetaTask < Array
|
167
|
-
include Worker
|
168
|
-
|
169
|
-
class << self
|
170
|
-
def for_task t
|
171
|
-
mt = self.new(t.full_name)
|
172
|
-
mt << t
|
173
|
-
end
|
174
|
-
def for_tasks *tasks
|
175
|
-
mt = self.new(tasks.first.full_name)
|
176
|
-
mt.concat tasks
|
177
|
-
mt
|
178
|
-
end
|
179
|
-
def for_task_list tasks
|
180
|
-
mt = self.new(tasks.first.full_name)
|
181
|
-
mt.concat tasks
|
182
|
-
mt
|
183
|
-
end
|
164
|
+
Node === other and full_name.eql? other.full_name
|
184
165
|
end
|
185
|
-
|
186
|
-
def initialize(name)
|
187
|
-
super()
|
188
|
-
@name = name or raise ArgumentError, "no name given"
|
189
|
-
end
|
190
|
-
|
191
|
-
def done?
|
192
|
-
all? { |t| t.done? }
|
193
|
-
end
|
194
|
-
|
195
|
-
def needed?
|
196
|
-
any? { |t| t.needed? }
|
197
|
-
end
|
198
|
-
|
199
|
-
def invoke(opt = INVOKE_OPT)
|
200
|
-
uf = false
|
201
|
-
each { |t| t.invoke(opt) && uf = true }
|
202
|
-
uf
|
203
|
-
end
|
204
|
-
|
205
|
-
def description
|
206
|
-
nil
|
207
|
-
end
|
208
|
-
|
209
|
-
def description=(val)
|
210
|
-
# spit out a warning?
|
211
|
-
end
|
212
|
-
|
213
|
-
def rantfile
|
214
|
-
nil
|
215
|
-
end
|
216
|
-
|
217
|
-
def rantfile=(val)
|
218
|
-
# spit out a warning?
|
219
|
-
end
|
220
|
-
|
221
|
-
def line_number
|
222
|
-
0
|
223
|
-
end
|
224
|
-
|
225
|
-
def line_number=(val)
|
226
|
-
# spit out a warning?
|
227
|
-
end
|
228
|
-
|
229
|
-
def app
|
230
|
-
empty? ? nil : first.app
|
231
|
-
end
|
232
|
-
|
233
|
-
def each_target &block
|
234
|
-
self.each { |t| t.each_target &block }
|
235
|
-
end
|
236
|
-
end # class MetaTask
|
166
|
+
end # module Node
|
237
167
|
|
238
168
|
# A very lightweight task for special purposes.
|
239
169
|
class LightTask
|
240
|
-
include
|
170
|
+
include Node
|
241
171
|
|
242
172
|
class << self
|
243
|
-
def rant_generate(
|
173
|
+
def rant_generate(rac, ch, args, &block)
|
244
174
|
unless args.size == 1
|
245
|
-
|
175
|
+
rac.abort("LightTask takes only one argument " +
|
246
176
|
"which has to be the taskname (string or symbol)")
|
247
177
|
end
|
248
|
-
|
178
|
+
rac.prepare_task({args.first => [], :__caller__ => ch},
|
249
179
|
block) { |name,pre,blk|
|
250
180
|
# TODO: ensure pre is empty
|
251
|
-
|
252
|
-
self.new(app, name, &blk)
|
181
|
+
self.new(rac, name, &blk)
|
253
182
|
}
|
254
183
|
end
|
255
184
|
end
|
256
185
|
|
257
|
-
def initialize(
|
186
|
+
def initialize(rac, name)
|
258
187
|
super()
|
259
|
-
@
|
260
|
-
@name =
|
261
|
-
when String: name
|
262
|
-
when Symbol: name.to_s
|
263
|
-
else
|
264
|
-
raise ArgumentError,
|
265
|
-
"invalid name argument: #{name.inspect}"
|
266
|
-
end
|
188
|
+
@rac = rac or raise ArgumentError, "no rac given"
|
189
|
+
@name = name
|
267
190
|
@needed = nil
|
268
191
|
@block = nil
|
269
192
|
@done = false
|
270
|
-
|
271
193
|
yield self if block_given?
|
272
194
|
end
|
273
195
|
|
274
|
-
def
|
275
|
-
@
|
196
|
+
def rac
|
197
|
+
@rac
|
276
198
|
end
|
277
199
|
|
278
200
|
def needed &block
|
@@ -297,19 +219,12 @@ module Rant
|
|
297
219
|
return needed? if opt[:needed?]
|
298
220
|
# +run+ already calls +goto_task_home+
|
299
221
|
#goto_task_home
|
300
|
-
if opt[:force] && !@done
|
301
|
-
|
222
|
+
if opt[:force] && !@done or needed?
|
223
|
+
run
|
302
224
|
@done = true
|
303
|
-
else
|
304
|
-
if needed?
|
305
|
-
run
|
306
|
-
@done = true
|
307
|
-
else
|
308
|
-
false
|
309
|
-
end
|
310
225
|
end
|
311
226
|
rescue CommandError => e
|
312
|
-
err_msg e.message if
|
227
|
+
err_msg e.message if rac[:err_commands]
|
313
228
|
self.fail(nil, e)
|
314
229
|
rescue SystemCallError => e
|
315
230
|
err_msg e.message
|
@@ -321,25 +236,25 @@ module Rant
|
|
321
236
|
end # LightTask
|
322
237
|
|
323
238
|
class Task
|
324
|
-
include
|
239
|
+
include Node
|
325
240
|
include Console
|
326
241
|
|
327
242
|
T0 = Time.at(0).freeze
|
328
243
|
|
329
244
|
class << self
|
330
|
-
def rant_generate(
|
245
|
+
def rant_generate(rac, ch, args, &block)
|
331
246
|
if args.size == 1
|
332
|
-
UserTask.rant_generate(
|
247
|
+
UserTask.rant_generate(rac, ch, args, &block)
|
333
248
|
else
|
334
|
-
|
249
|
+
rac.abort("Task generator currently takes only one" +
|
335
250
|
" argument. (generates a UserTask)")
|
336
251
|
end
|
337
252
|
end
|
338
253
|
end
|
339
254
|
|
340
|
-
def initialize(
|
255
|
+
def initialize(rac, name, prerequisites = [], &block)
|
341
256
|
super()
|
342
|
-
@
|
257
|
+
@rac = rac || Rant.rac
|
343
258
|
@name = name or raise ArgumentError, "name not given"
|
344
259
|
@pre = prerequisites || []
|
345
260
|
@pre_resolved = false
|
@@ -435,12 +350,12 @@ module Rant
|
|
435
350
|
dep = nil
|
436
351
|
uf = false
|
437
352
|
each_dep { |dep|
|
438
|
-
if
|
439
|
-
|
440
|
-
elsif
|
441
|
-
|
353
|
+
if dep.respond_to? :timestamp
|
354
|
+
handle_timestamped(dep, opt) && update = true
|
355
|
+
elsif Node === dep
|
356
|
+
handle_node(dep, opt) && update = true
|
442
357
|
else
|
443
|
-
dep, uf =
|
358
|
+
dep, uf = handle_non_node(dep, opt)
|
444
359
|
uf && update = true
|
445
360
|
dep
|
446
361
|
end
|
@@ -458,25 +373,25 @@ module Rant
|
|
458
373
|
private :internal_invoke
|
459
374
|
|
460
375
|
# Called from internal_invoke. +dep+ is a prerequisite which
|
461
|
-
# is_a?
|
462
|
-
#
|
376
|
+
# is_a? Node, but not a FileTask. +opt+ are opts as given to
|
377
|
+
# Node#invoke.
|
463
378
|
#
|
464
379
|
# Override this method in subclasses to modify behaviour of
|
465
380
|
# prerequisite handling.
|
466
381
|
#
|
467
|
-
# See also:
|
468
|
-
def
|
382
|
+
# See also: handle_timestamped, handle_non_node
|
383
|
+
def handle_node(dep, opt)
|
469
384
|
dep.invoke opt
|
470
385
|
end
|
471
386
|
|
472
387
|
# Called from internal_invoke. +dep+ is a prerequisite which
|
473
|
-
# is_a? FileTask. +opt+ are opts as given to
|
388
|
+
# is_a? FileTask. +opt+ are opts as given to Node#invoke.
|
474
389
|
#
|
475
390
|
# Override this method in subclasses to modify behaviour of
|
476
391
|
# prerequisite handling.
|
477
392
|
#
|
478
|
-
# See also:
|
479
|
-
def
|
393
|
+
# See also: handle_node, handle_non_node
|
394
|
+
def handle_timestamped(dep, opt)
|
480
395
|
dep.invoke opt
|
481
396
|
end
|
482
397
|
|
@@ -488,8 +403,8 @@ module Rant
|
|
488
403
|
# [1] Fail with an exception.
|
489
404
|
# [2] Return two values: replacement_for_dep, update_required
|
490
405
|
#
|
491
|
-
# See also:
|
492
|
-
def
|
406
|
+
# See also: handle_node, handle_timestamped
|
407
|
+
def handle_non_node(dep, opt)
|
493
408
|
err_msg "Unknown task `#{dep}',",
|
494
409
|
"referenced in `#{rantfile.path}', line #{@line_number}!"
|
495
410
|
self.fail
|
@@ -506,7 +421,7 @@ module Rant
|
|
506
421
|
my_full_name = full_name
|
507
422
|
my_project_subdir = project_subdir
|
508
423
|
@pre.map! { |t|
|
509
|
-
if
|
424
|
+
if Node === t
|
510
425
|
# Remove references to self from prerequisites!
|
511
426
|
if t.full_name == my_full_name
|
512
427
|
nil
|
@@ -520,7 +435,7 @@ module Rant
|
|
520
435
|
nil
|
521
436
|
else
|
522
437
|
#STDERR.puts "selecting `#{t}'"
|
523
|
-
selection = @
|
438
|
+
selection = @rac.resolve t,
|
524
439
|
my_project_subdir
|
525
440
|
#STDERR.puts selection.size
|
526
441
|
if selection.empty?
|
@@ -544,14 +459,14 @@ module Rant
|
|
544
459
|
class UserTask < Task
|
545
460
|
|
546
461
|
class << self
|
547
|
-
def rant_generate(
|
462
|
+
def rant_generate(rac, ch, args, &block)
|
548
463
|
unless args.size == 1
|
549
|
-
|
464
|
+
rac.abort("UserTask takes only one argument " +
|
550
465
|
"which has to be like one given to the " +
|
551
466
|
"`task' function")
|
552
467
|
end
|
553
|
-
|
554
|
-
self.new(
|
468
|
+
rac.prepare_task(args.first, nil, ch) { |name,pre,blk|
|
469
|
+
self.new(rac, name, pre, &block)
|
555
470
|
}
|
556
471
|
end
|
557
472
|
end
|
@@ -602,19 +517,9 @@ module Rant
|
|
602
517
|
|
603
518
|
def initialize *args
|
604
519
|
super
|
605
|
-
if @name.is_a? Path
|
606
|
-
@path = @name
|
607
|
-
@name = @path.to_s
|
608
|
-
else
|
609
|
-
@path = Path.new @name
|
610
|
-
end
|
611
520
|
@ts = T0
|
612
521
|
end
|
613
522
|
|
614
|
-
def path
|
615
|
-
@path
|
616
|
-
end
|
617
|
-
|
618
523
|
def needed?
|
619
524
|
return false if done?
|
620
525
|
invoke(:needed? => true)
|
@@ -626,8 +531,8 @@ module Rant
|
|
626
531
|
begin
|
627
532
|
return if done?
|
628
533
|
goto_task_home
|
629
|
-
if
|
630
|
-
@ts =
|
534
|
+
if File.exist? @name
|
535
|
+
@ts = File.mtime @name
|
631
536
|
internal_invoke opt, false
|
632
537
|
else
|
633
538
|
@ts = T0
|
@@ -638,23 +543,23 @@ module Rant
|
|
638
543
|
end
|
639
544
|
end
|
640
545
|
|
641
|
-
def
|
546
|
+
def timestamp
|
547
|
+
File.exist?(@name) ? File.mtime(@name) : T0
|
548
|
+
end
|
549
|
+
|
550
|
+
def handle_timestamped(dep, opt)
|
642
551
|
return true if dep.invoke opt
|
643
|
-
#
|
644
|
-
|
645
|
-
#puts "***`#{dep.name}' requires update" if dep.path.mtime > @ts
|
646
|
-
dep.path.mtime > @ts
|
647
|
-
end
|
552
|
+
#puts "***`#{dep.name}' requires update" if dep.timestamp > @ts
|
553
|
+
dep.timestamp > @ts
|
648
554
|
end
|
649
555
|
|
650
|
-
def
|
651
|
-
|
652
|
-
|
653
|
-
err_msg @app.pos_text(rantfile.path, line_number),
|
556
|
+
def handle_non_node(dep, opt)
|
557
|
+
unless File.exist? dep
|
558
|
+
err_msg @rac.pos_text(rantfile.path, line_number),
|
654
559
|
"in prerequisites: no such file or task: `#{dep}'"
|
655
560
|
self.fail
|
656
561
|
end
|
657
|
-
[dep,
|
562
|
+
[dep, File.mtime(dep) > @ts]
|
658
563
|
end
|
659
564
|
|
660
565
|
def each_target
|
@@ -663,6 +568,18 @@ module Rant
|
|
663
568
|
end
|
664
569
|
end # class FileTask
|
665
570
|
|
571
|
+
class AutoSubFileTask < FileTask
|
572
|
+
private
|
573
|
+
def run
|
574
|
+
dir, = File.split(name)
|
575
|
+
unless dir == "."
|
576
|
+
dt = @rac.resolve(dir, project_subdir).last
|
577
|
+
dt.invoke if DirTask === dt
|
578
|
+
end
|
579
|
+
super
|
580
|
+
end
|
581
|
+
end # class AutoSubFileTask
|
582
|
+
|
666
583
|
# An instance of this class is a task to create a _single_
|
667
584
|
# directory.
|
668
585
|
class DirTask < Task
|
@@ -677,12 +594,23 @@ module Rant
|
|
677
594
|
# block will be called after complete directory creation.
|
678
595
|
# After the block execution, the modification time of the
|
679
596
|
# directory will be updated.
|
680
|
-
def rant_generate(
|
681
|
-
|
682
|
-
|
683
|
-
|
597
|
+
def rant_generate(rac, ch, args, &block)
|
598
|
+
case args.size
|
599
|
+
when 1
|
600
|
+
name, pre, file, ln = rac.normalize_task_arg(args.first, ch)
|
601
|
+
self.task(rac, ch, name, pre, &block)
|
602
|
+
when 2
|
603
|
+
basedir = args.shift
|
604
|
+
if basedir.respond_to? :to_str
|
605
|
+
basedir = basedir.to_str
|
606
|
+
else
|
607
|
+
rac.abort_at(ch,
|
608
|
+
"Directory: basedir argument has to be a string.")
|
609
|
+
end
|
610
|
+
name, pre, file, ln = rac.normalize_task_arg(args.first, ch)
|
611
|
+
self.task(rac, ch, name, pre, basedir, &block)
|
684
612
|
else
|
685
|
-
|
613
|
+
rac.abort(rac.pos_text(ch[:file], ch[:ln]),
|
686
614
|
"Directory takes one argument, " +
|
687
615
|
"which should be like one given to the `task' command.")
|
688
616
|
end
|
@@ -691,44 +619,40 @@ module Rant
|
|
691
619
|
# Returns the task which creates the last directory
|
692
620
|
# element (and has all other necessary directories as
|
693
621
|
# prerequisites).
|
694
|
-
def task(
|
622
|
+
def task(rac, ch, name, prerequisites=[], basedir=nil, &block)
|
695
623
|
dirs = ::Rant::Sys.split_path(name)
|
696
624
|
if dirs.empty?
|
697
|
-
|
625
|
+
rac.abort_at(ch,
|
698
626
|
"Not a valid directory name: `#{name}'")
|
699
627
|
end
|
700
|
-
|
701
|
-
path = nil
|
628
|
+
path = basedir
|
702
629
|
last_task = nil
|
703
630
|
task_block = nil
|
631
|
+
desc_for_last = rac.pop_desc
|
704
632
|
dirs.each { |dir|
|
705
|
-
pre = [
|
633
|
+
pre = [path]
|
706
634
|
pre.compact!
|
707
635
|
if dir.equal?(dirs.last)
|
636
|
+
rac.cx.desc desc_for_last
|
708
637
|
pre.concat prerequisites if prerequisites
|
709
638
|
task_block = block
|
710
639
|
end
|
711
640
|
path = path.nil? ? dir : File.join(path, dir)
|
712
|
-
last_task =
|
641
|
+
last_task = rac.prepare_task({:__caller__ => ch,
|
713
642
|
path => pre}, task_block) { |name,pre,blk|
|
714
|
-
self.new(
|
643
|
+
self.new(rac, name, pre, &blk)
|
715
644
|
}
|
716
|
-
ld = dir
|
717
645
|
}
|
718
646
|
last_task
|
719
647
|
end
|
720
648
|
end
|
721
649
|
|
722
|
-
def
|
650
|
+
def initialize *args
|
723
651
|
super
|
724
652
|
@ts = T0
|
725
653
|
@isdir = nil
|
726
654
|
end
|
727
655
|
|
728
|
-
#def needed?
|
729
|
-
# invoke(:needed? => true)
|
730
|
-
#end
|
731
|
-
|
732
656
|
def invoke(opt = INVOKE_OPT)
|
733
657
|
return circular_dep if @run
|
734
658
|
@run = true
|
@@ -748,29 +672,26 @@ module Rant
|
|
748
672
|
end
|
749
673
|
end
|
750
674
|
|
751
|
-
def
|
675
|
+
def handle_timestamped(dep, opt)
|
752
676
|
return @block if dep.invoke opt
|
753
|
-
|
754
|
-
@block && dep.path.mtime > @ts
|
755
|
-
end
|
677
|
+
@block && dep.timestamp > @ts
|
756
678
|
end
|
757
679
|
|
758
|
-
def
|
759
|
-
|
760
|
-
|
761
|
-
err_msg @app.pos_text(rantfile.path, line_number),
|
680
|
+
def handle_non_node(dep, opt)
|
681
|
+
unless File.exist? dep
|
682
|
+
err_msg @rac.pos_text(rantfile.path, line_number),
|
762
683
|
"in prerequisites: no such file or task: `#{dep}'"
|
763
684
|
self.fail
|
764
685
|
end
|
765
|
-
[dep, @block &&
|
686
|
+
[dep, @block && File.mtime(dep) > @ts]
|
766
687
|
end
|
767
688
|
|
768
689
|
def run
|
769
|
-
@
|
690
|
+
@rac.sys.mkdir @name unless @isdir
|
770
691
|
if @block
|
771
692
|
@block.arity == 0 ? @block.call : @block[self]
|
772
693
|
goto_task_home
|
773
|
-
@
|
694
|
+
@rac.sys.touch @name
|
774
695
|
end
|
775
696
|
end
|
776
697
|
|
@@ -779,10 +700,102 @@ module Rant
|
|
779
700
|
yield name
|
780
701
|
end
|
781
702
|
end # class DirTask
|
703
|
+
|
704
|
+
# A SourceNode describes dependencies between source files. Thus
|
705
|
+
# there is no action attached to a SourceNode. The target should
|
706
|
+
# be an existing file as well as all dependencies.
|
707
|
+
#
|
708
|
+
# An example would be a C source file which depends on other C
|
709
|
+
# source files because of <tt>#include</tt> statements.
|
710
|
+
#
|
711
|
+
# Rantfile usage:
|
712
|
+
# gen SourceNode, "myext.c" => %w(ruby.h myext.h)
|
713
|
+
class SourceNode
|
714
|
+
include Node
|
715
|
+
|
716
|
+
def self.rant_generate(rac, ch, args)
|
717
|
+
unless args.size == 1
|
718
|
+
rac.abort_at(ch, "SourceNode takes one argument.")
|
719
|
+
end
|
720
|
+
if block_given?
|
721
|
+
rac.abort_at(ch, "SourceNode doesn't take a block.")
|
722
|
+
end
|
723
|
+
rac.prepare_task(args.first, nil, ch) { |name, pre, blk|
|
724
|
+
new(rac, name, pre, &blk)
|
725
|
+
}
|
726
|
+
end
|
727
|
+
|
728
|
+
def initialize(rac, name, prerequisites = [])
|
729
|
+
super()
|
730
|
+
@rac = rac
|
731
|
+
@name = name or raise ArgumentError, "name not given"
|
732
|
+
@pre = prerequisites
|
733
|
+
@run = false
|
734
|
+
# The timestamp is the latest of this file and all
|
735
|
+
# dependencies:
|
736
|
+
@ts = nil
|
737
|
+
end
|
738
|
+
|
739
|
+
# Use this readonly!
|
740
|
+
def prerequisites
|
741
|
+
@pre
|
742
|
+
end
|
743
|
+
|
744
|
+
# Note: The timestamp will only be calculated once!
|
745
|
+
def timestamp
|
746
|
+
# Circular dependencies don't generate endless
|
747
|
+
# recursion/loops because before calling the timestamp
|
748
|
+
# method of any other node, we set @ts to some non-nil
|
749
|
+
# value.
|
750
|
+
return @ts if @ts
|
751
|
+
goto_task_home
|
752
|
+
if File.exist?(@name)
|
753
|
+
@ts = File.mtime @name
|
754
|
+
else
|
755
|
+
rac.abort(rac.pos_text(@rantfile, @line_number),
|
756
|
+
"SourceNode: no such file -- #@name")
|
757
|
+
end
|
758
|
+
sd = project_subdir
|
759
|
+
@pre.each { |f|
|
760
|
+
nodes = rac.resolve f, sd
|
761
|
+
if nodes.empty?
|
762
|
+
if File.exist? f
|
763
|
+
mtime = File.mtime f
|
764
|
+
@ts = mtime if mtime > @ts
|
765
|
+
else
|
766
|
+
rac.abort(rac.pos_text(@rantfile, @line_number),
|
767
|
+
"SourceNode: no such file -- #{f}")
|
768
|
+
end
|
769
|
+
else
|
770
|
+
nodes.each { |node|
|
771
|
+
if node.respond_to? :timestamp
|
772
|
+
node_ts = node.timestamp
|
773
|
+
@ts = node_ts if node_ts > @ts
|
774
|
+
else
|
775
|
+
rac.abort(rac.pos_text(@rantfile, @line_number),
|
776
|
+
"SourceNode can't depend on #{node.name}")
|
777
|
+
end
|
778
|
+
}
|
779
|
+
end
|
780
|
+
}
|
781
|
+
@ts
|
782
|
+
end
|
783
|
+
|
784
|
+
def needed?
|
785
|
+
false
|
786
|
+
end
|
787
|
+
|
788
|
+
def invoke(opt = INVOKE_OPT)
|
789
|
+
false
|
790
|
+
end
|
791
|
+
|
792
|
+
end # class SourceNode
|
793
|
+
|
782
794
|
module Generators
|
783
795
|
Task = ::Rant::Task
|
784
796
|
LightTask = ::Rant::LightTask
|
785
797
|
Directory = ::Rant::DirTask
|
798
|
+
SourceNode = ::Rant::SourceNode
|
786
799
|
|
787
800
|
class Rule < ::Proc
|
788
801
|
# Generate a rule by installing an at_resolve hook for
|
@@ -843,7 +856,7 @@ module Rant
|
|
843
856
|
end
|
844
857
|
}
|
845
858
|
blk.target_rx = target_rx
|
846
|
-
rac.
|
859
|
+
rac.resolve_hooks << blk
|
847
860
|
nil
|
848
861
|
end
|
849
862
|
attr_accessor :target_rx
|