rant 0.3.6 → 0.3.8
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/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
|