rant 0.3.2 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/NEWS +22 -1
- data/README +9 -12
- data/Rantfile +32 -9
- data/devel-notes +16 -0
- data/doc/advanced.rdoc +55 -0
- data/doc/rant.rdoc +27 -2
- data/doc/rantfile.rdoc +104 -30
- data/install.rb +6 -0
- data/lib/rant.rb +5 -1
- data/lib/rant/import.rb +12 -4
- data/lib/rant/import/rubydoc.rb +1 -1
- data/lib/rant/import/rubypackage.rb +2 -2
- data/lib/rant/import/rubytest.rb +3 -2
- data/lib/rant/plugin/csharp.rb +5 -9
- data/lib/rant/rantenv.rb +1 -0
- data/lib/rant/rantfile.rb +184 -68
- data/lib/rant/rantlib.rb +203 -195
- data/lib/rant/rantsys.rb +87 -44
- data/lib/rant/rantvar.rb +236 -17
- data/rantmethods.rb +9 -4
- data/run_rant +1 -1
- data/test/Rantfile +16 -0
- data/test/plugin/csharp/test_csharp.rb +2 -1
- data/test/plugin/rantfile +1 -0
- data/test/project1/Rantfile +8 -4
- data/test/rule.rf +27 -0
- data/test/subdirs/Rantfile +2 -0
- data/test/subdirs/sub2/sub/rantfile +17 -0
- data/test/subdirs/test_subdirs.rb +46 -2
- data/test/test_dirtask.rb +33 -0
- data/test/test_filelist.rb +81 -0
- data/test/test_filetask.rb +6 -6
- data/test/test_rant_interface.rb +4 -3
- data/test/test_rule.rb +67 -0
- data/test/test_source.rb +26 -0
- data/test/test_task.rb +27 -6
- data/test/test_var.rb +102 -0
- data/test/toplevel.rf +1 -1
- data/test/var.rf +19 -0
- metadata +11 -2
data/lib/rant/rantlib.rb
CHANGED
@@ -13,38 +13,6 @@ require 'rant/rantenv'
|
|
13
13
|
require 'rant/rantfile'
|
14
14
|
require 'rant/rantsys'
|
15
15
|
|
16
|
-
module Rant
|
17
|
-
VERSION = '0.3.2'
|
18
|
-
|
19
|
-
# Those are the filenames for rantfiles.
|
20
|
-
# Case matters!
|
21
|
-
RANTFILES = [ "Rantfile",
|
22
|
-
"rantfile",
|
23
|
-
"Rantfile.rb",
|
24
|
-
"rantfile.rb",
|
25
|
-
]
|
26
|
-
|
27
|
-
# Names of plugins and imports for which code was loaded.
|
28
|
-
# Files that where loaded with the `import' commant are directly
|
29
|
-
# added; files loaded with the `plugin' command are prefixed with
|
30
|
-
# "plugin/".
|
31
|
-
CODE_IMPORTS = []
|
32
|
-
|
33
|
-
class RantAbortException < StandardError
|
34
|
-
end
|
35
|
-
|
36
|
-
class RantDoneException < StandardError
|
37
|
-
end
|
38
|
-
|
39
|
-
class RantfileException < StandardError
|
40
|
-
end
|
41
|
-
|
42
|
-
# This module is a namespace for generator classes.
|
43
|
-
module Generators
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
16
|
# There is one problem with executing Rantfiles in a special context:
|
49
17
|
# In the top-level execution environment, there are some methods
|
50
18
|
# available which are not available to all objects. One example is the
|
@@ -56,6 +24,9 @@ end
|
|
56
24
|
Rant::MAIN_OBJECT = self
|
57
25
|
|
58
26
|
class Array
|
27
|
+
|
28
|
+
# Concatenates all elements like #join(' ') but also puts quotes
|
29
|
+
# around strings that contain a space.
|
59
30
|
def arglist
|
60
31
|
self.shell_pathes.join(' ')
|
61
32
|
end
|
@@ -82,6 +53,16 @@ class Array
|
|
82
53
|
end
|
83
54
|
end
|
84
55
|
|
56
|
+
class String
|
57
|
+
def 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
|
+
|
85
66
|
module Rant::Lib
|
86
67
|
|
87
68
|
# Parses one string (elem) as it occurs in the array
|
@@ -89,51 +70,13 @@ module Rant::Lib
|
|
89
70
|
# E.g.:
|
90
71
|
# p parse_caller_elem "/usr/local/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'"
|
91
72
|
# prints:
|
92
|
-
# {:
|
73
|
+
# {:ln=>52, :file=>"/usr/local/lib/ruby/1.8/irb/workspace.rb"}
|
93
74
|
def parse_caller_elem elem
|
94
75
|
parts = elem.split(":")
|
95
|
-
|
96
|
-
:ln => parts[1].to_i
|
97
|
-
}
|
98
|
-
=begin
|
99
|
-
# commented for better performance
|
100
|
-
meth = parts[2]
|
101
|
-
if meth && meth =~ /\`(\w+)'/
|
102
|
-
meth = $1
|
103
|
-
end
|
104
|
-
rh[:method] = meth
|
105
|
-
=end
|
106
|
-
rh
|
76
|
+
{ :file => parts[0], :ln => parts[1].to_i }
|
107
77
|
end
|
108
|
-
|
109
78
|
module_function :parse_caller_elem
|
110
79
|
|
111
|
-
# currently unused
|
112
|
-
class Caller
|
113
|
-
def self.[](i)
|
114
|
-
new(caller[i+1])
|
115
|
-
end
|
116
|
-
def initialize(clr)
|
117
|
-
@clr = clr
|
118
|
-
@file = @ln = nil
|
119
|
-
end
|
120
|
-
def file
|
121
|
-
unless @file
|
122
|
-
ca = Lib.parse_caller_elem(clr)
|
123
|
-
@file = ca[:file]
|
124
|
-
@ln = ca[:ln]
|
125
|
-
end
|
126
|
-
@file
|
127
|
-
end
|
128
|
-
def ln
|
129
|
-
unless @ln
|
130
|
-
ca = Lib.parse_caller_elem(clr)
|
131
|
-
@file = ca[:file]
|
132
|
-
@ln = ca[:ln]
|
133
|
-
end
|
134
|
-
@ln
|
135
|
-
end
|
136
|
-
end
|
137
80
|
end
|
138
81
|
|
139
82
|
# The methods in this module are the public interface to Rant that can
|
@@ -141,62 +84,69 @@ end
|
|
141
84
|
module RantContext
|
142
85
|
include Rant::Generators
|
143
86
|
|
87
|
+
Env = Rant::Env
|
88
|
+
FileList = Rant::FileList
|
89
|
+
|
144
90
|
# Define a basic task.
|
145
91
|
def task targ, &block
|
146
|
-
|
92
|
+
rac.task(targ, &block)
|
147
93
|
end
|
148
94
|
|
149
95
|
# Define a file task.
|
150
96
|
def file targ, &block
|
151
|
-
|
97
|
+
rac.file(targ, &block)
|
152
98
|
end
|
153
99
|
|
154
100
|
# Add code and/or prerequisites to existing task.
|
155
101
|
def enhance targ, &block
|
156
|
-
|
102
|
+
rac.enhance(targ, &block)
|
157
103
|
end
|
158
104
|
|
159
105
|
def desc(*args)
|
160
|
-
|
106
|
+
rac.desc(*args)
|
161
107
|
end
|
162
108
|
|
163
109
|
def gen(*args, &block)
|
164
|
-
|
110
|
+
rac.gen(*args, &block)
|
165
111
|
end
|
166
112
|
|
167
113
|
def import(*args, &block)
|
168
|
-
|
114
|
+
rac.import(*args, &block)
|
169
115
|
end
|
170
116
|
|
171
117
|
def plugin(*args, &block)
|
172
|
-
|
118
|
+
rac.plugin(*args, &block)
|
173
119
|
end
|
174
120
|
|
175
121
|
# Look in the subdirectories, given by args,
|
176
122
|
# for rantfiles.
|
177
123
|
def subdirs *args
|
178
|
-
|
124
|
+
rac.subdirs(*args)
|
179
125
|
end
|
180
126
|
|
181
127
|
def source rantfile
|
182
|
-
|
128
|
+
rac.source(rantfile)
|
129
|
+
end
|
130
|
+
|
131
|
+
def sys(*args, &block)
|
132
|
+
rac.sys(*args)
|
183
133
|
end
|
184
134
|
|
185
|
-
def
|
186
|
-
|
135
|
+
def var(*args, &block)
|
136
|
+
rac.var(*args, &block)
|
187
137
|
end
|
188
138
|
end # module RantContext
|
189
139
|
|
190
140
|
class RantAppContext
|
191
|
-
include Rant
|
192
141
|
include RantContext
|
193
142
|
|
194
143
|
def initialize(app)
|
195
|
-
@
|
144
|
+
@rac = app
|
196
145
|
end
|
197
146
|
|
198
|
-
|
199
|
-
|
147
|
+
# +rac+ stands for "rant compiler"
|
148
|
+
def rac
|
149
|
+
@rac
|
200
150
|
end
|
201
151
|
|
202
152
|
def method_missing(sym, *args)
|
@@ -212,11 +162,10 @@ class RantAppContext
|
|
212
162
|
end
|
213
163
|
|
214
164
|
module Rant
|
215
|
-
include RantContext
|
216
165
|
|
217
166
|
# In the class definition of Rant::RantApp, this will be set to a
|
218
167
|
# new application object.
|
219
|
-
@@
|
168
|
+
@@rac = nil
|
220
169
|
|
221
170
|
class << self
|
222
171
|
|
@@ -246,42 +195,30 @@ module Rant
|
|
246
195
|
def run(first_arg=nil, *other_args)
|
247
196
|
other_args = other_args.flatten
|
248
197
|
args = first_arg.nil? ? ARGV.dup : ([first_arg] + other_args)
|
249
|
-
if @@
|
250
|
-
@@
|
251
|
-
@@
|
198
|
+
if @@rac && !@@rac.ran?
|
199
|
+
@@rac.args.replace(args.flatten)
|
200
|
+
@@rac.run
|
252
201
|
else
|
253
|
-
@@
|
254
|
-
@@
|
202
|
+
@@rac = Rant::RantApp.new(args)
|
203
|
+
@@rac.run
|
255
204
|
end
|
256
205
|
end
|
257
206
|
|
258
|
-
def
|
259
|
-
@@
|
207
|
+
def rac
|
208
|
+
@@rac
|
260
209
|
end
|
261
210
|
|
262
|
-
def
|
263
|
-
@@
|
211
|
+
def rac=(app)
|
212
|
+
@@rac = app
|
264
213
|
end
|
265
214
|
|
266
215
|
# "Clear" the current Rant application. After this call,
|
267
216
|
# Rant has the same state as immediately after startup.
|
268
217
|
def reset
|
269
|
-
@@
|
218
|
+
@@rac = nil
|
270
219
|
end
|
271
220
|
end
|
272
221
|
|
273
|
-
def rantapp
|
274
|
-
@@rantapp
|
275
|
-
end
|
276
|
-
|
277
|
-
# Pre 0.2.7: Manually making necessary methods module
|
278
|
-
# functions. Note that it caused problems with caller
|
279
|
-
# parsing when the Rantfile did a `require "rant"' (irb!).
|
280
|
-
#module_function :task, :file, :desc, :subdirs,
|
281
|
-
# :gen, :source, :enhance, :sys, :plugin
|
282
|
-
|
283
|
-
extend self
|
284
|
-
|
285
222
|
end # module Rant
|
286
223
|
|
287
224
|
class Rant::RantApp
|
@@ -290,6 +227,9 @@ class Rant::RantApp
|
|
290
227
|
# Important: We try to synchronize all tasks referenced indirectly
|
291
228
|
# by @rantfiles with the task hash @tasks. The task hash is
|
292
229
|
# intended for fast task lookup per task name.
|
230
|
+
#
|
231
|
+
# All tasks are registered to the system by the +prepare_task+
|
232
|
+
# method.
|
293
233
|
|
294
234
|
# The RantApp class has no own state.
|
295
235
|
|
@@ -323,6 +263,8 @@ class Rant::RantApp
|
|
323
263
|
[ "--trace-abort", GetoptLong::NO_ARGUMENT, nil ],
|
324
264
|
]
|
325
265
|
|
266
|
+
# Reference project's root directory in task names by preceding
|
267
|
+
# them with this character.
|
326
268
|
ROOT_DIR_ID = "#"
|
327
269
|
ESCAPE_ID = "\\"
|
328
270
|
|
@@ -342,16 +284,14 @@ class Rant::RantApp
|
|
342
284
|
# may be called through an instance_eval on this object (e.g. from
|
343
285
|
# plugins).
|
344
286
|
attr_reader :context
|
345
|
-
|
346
|
-
# object (like a hash). It is intended to let the different
|
347
|
-
# modules, plugins and tasks to communicate to each other.
|
348
|
-
attr_reader :var
|
287
|
+
alias cx context
|
349
288
|
# A hash with all tasks. For fast task lookup use this hash with
|
350
289
|
# the taskname as key.
|
351
290
|
attr_reader :tasks
|
352
|
-
# A list
|
291
|
+
# A list of all imports (code loaded with +import+).
|
353
292
|
attr_reader :imports
|
354
|
-
|
293
|
+
# Current subdirectory relative to project's root directory
|
294
|
+
# (#rootdir).
|
355
295
|
attr_reader :current_subdir
|
356
296
|
|
357
297
|
def initialize *args
|
@@ -359,7 +299,7 @@ class Rant::RantApp
|
|
359
299
|
# Rantfiles will be loaded in the context of this object.
|
360
300
|
@context = RantAppContext.new(self)
|
361
301
|
@sys = ::Rant::SysObject.new(self)
|
362
|
-
Rant.
|
302
|
+
Rant.rac ||= self
|
363
303
|
@rantfiles = []
|
364
304
|
@tasks = {}
|
365
305
|
@opts = {
|
@@ -373,6 +313,7 @@ class Rant::RantApp
|
|
373
313
|
@done = false
|
374
314
|
@plugins = []
|
375
315
|
@var = Rant::RantVar::Space.new
|
316
|
+
@var.query :ignore, :AutoList, []
|
376
317
|
@imports = []
|
377
318
|
|
378
319
|
@task_show = nil
|
@@ -380,7 +321,7 @@ class Rant::RantApp
|
|
380
321
|
|
381
322
|
@orig_pwd = nil
|
382
323
|
@current_subdir = ""
|
383
|
-
|
324
|
+
@resolve_hooks = []
|
384
325
|
end
|
385
326
|
|
386
327
|
def [](opt)
|
@@ -412,22 +353,6 @@ class Rant::RantApp
|
|
412
353
|
### experimental support for subdirectories ######################
|
413
354
|
def expand_project_path(path)
|
414
355
|
expand_path(@current_subdir, path)
|
415
|
-
=begin
|
416
|
-
case path
|
417
|
-
when nil: @current_subdir.dup
|
418
|
-
when "": @current_subdir.dup
|
419
|
-
when /^#/: path.sub(/^#/, '')
|
420
|
-
when /^\\#/: path.sub(/^\\/, '')
|
421
|
-
else
|
422
|
-
#puts "epp: current_subdir: #@current_subdir"
|
423
|
-
if @current_subdir.empty?
|
424
|
-
# we are in project's root directory
|
425
|
-
path
|
426
|
-
else
|
427
|
-
File.join(@current_subdir, path)
|
428
|
-
end
|
429
|
-
end
|
430
|
-
=end
|
431
356
|
end
|
432
357
|
def expand_path(subdir, path)
|
433
358
|
case path
|
@@ -456,7 +381,8 @@ class Rant::RantApp
|
|
456
381
|
def goto(dir)
|
457
382
|
# TODO: optimize
|
458
383
|
p_dir = expand_project_path(dir)
|
459
|
-
|
384
|
+
base = rootdir.empty? ? Dir.pwd : rootdir
|
385
|
+
abs_path = p_dir.empty? ? base : File.join(base, p_dir)
|
460
386
|
@current_subdir = p_dir
|
461
387
|
unless Dir.pwd == abs_path
|
462
388
|
#puts "pwd: #{Dir.pwd}; abs_path: #{abs_path}"
|
@@ -466,6 +392,7 @@ class Rant::RantApp
|
|
466
392
|
#STDERR.puts "rant: in #{p_dir}"
|
467
393
|
end
|
468
394
|
end
|
395
|
+
# +dir+ is a path relative to +rootdir+
|
469
396
|
def goto_project_dir(dir)
|
470
397
|
# TODO: optimize
|
471
398
|
goto "##{dir}"
|
@@ -512,6 +439,7 @@ class Rant::RantApp
|
|
512
439
|
end
|
513
440
|
# run tasks
|
514
441
|
run_tasks
|
442
|
+
goto "#"
|
515
443
|
raise Rant::RantDoneException
|
516
444
|
rescue Rant::RantDoneException
|
517
445
|
@done = true
|
@@ -522,6 +450,10 @@ class Rant::RantApp
|
|
522
450
|
err_msg "Invalid Rantfile: " + $!.message
|
523
451
|
$stderr.puts "rant aborted!"
|
524
452
|
return 1
|
453
|
+
rescue Rant::RantError
|
454
|
+
err_msg $!.message, $!.backtrace[0..4]
|
455
|
+
$stderr.puts "rant aborted!"
|
456
|
+
return 1
|
525
457
|
rescue Rant::RantAbortException
|
526
458
|
$stderr.puts "rant aborted!"
|
527
459
|
return 1
|
@@ -535,7 +467,7 @@ class Rant::RantApp
|
|
535
467
|
@plugins.each { |plugin| plugin.rant_quit }
|
536
468
|
# restore pwd
|
537
469
|
Dir.pwd != @orig_pwd && Dir.chdir(@orig_pwd)
|
538
|
-
Rant.
|
470
|
+
Rant.rac = self.class.new
|
539
471
|
end
|
540
472
|
|
541
473
|
###### methods accessible through RantContext ####################
|
@@ -573,14 +505,6 @@ class Rant::RantApp
|
|
573
505
|
file = ch[:file]
|
574
506
|
# validate args
|
575
507
|
generator = args.shift
|
576
|
-
# Let modules/classes from the Generator namespace override
|
577
|
-
# other generators.
|
578
|
-
begin
|
579
|
-
if generator.is_a? Module
|
580
|
-
generator = ::Rant::Generators.const_get(generator.to_s)
|
581
|
-
end
|
582
|
-
rescue NameError, ArgumentError
|
583
|
-
end
|
584
508
|
unless generator.respond_to? :rant_generate
|
585
509
|
abort(pos_text(file, ln),
|
586
510
|
"First argument to `gen' has to be a task-generator.")
|
@@ -591,20 +515,23 @@ class Rant::RantApp
|
|
591
515
|
|
592
516
|
# Currently ignores block.
|
593
517
|
def import(*args, &block)
|
518
|
+
ch = Rant::Lib::parse_caller_elem(caller[1])
|
594
519
|
if block
|
595
|
-
warn_msg
|
520
|
+
warn_msg pos_text(ch[:file], ch[:ln]),
|
521
|
+
"import: ignoring block"
|
596
522
|
end
|
597
523
|
args.flatten.each { |arg|
|
598
524
|
unless String === arg
|
599
|
-
abort(
|
600
|
-
"only strings
|
525
|
+
abort(pos_text(ch[:file], ch[:ln]),
|
526
|
+
"import: only strings allowed as arguments")
|
601
527
|
end
|
602
528
|
unless @imports.include? arg
|
603
529
|
unless Rant::CODE_IMPORTS.include? arg
|
604
530
|
begin
|
605
531
|
require "rant/import/#{arg}"
|
606
532
|
rescue LoadError => e
|
607
|
-
abort(
|
533
|
+
abort(pos_text(ch[:file], ch[:ln]),
|
534
|
+
"No such import - #{arg}")
|
608
535
|
end
|
609
536
|
Rant::CODE_IMPORTS << arg.dup
|
610
537
|
end
|
@@ -683,9 +610,11 @@ class Rant::RantApp
|
|
683
610
|
def source rantfile
|
684
611
|
rf, is_new = rantfile_for_path(rantfile)
|
685
612
|
return false unless is_new
|
613
|
+
build rantfile
|
686
614
|
unless rf.exist?
|
687
|
-
abort("source: No such file
|
615
|
+
abort("source: No such file - #{rantfile}")
|
688
616
|
end
|
617
|
+
|
689
618
|
load_file rf
|
690
619
|
true
|
691
620
|
end
|
@@ -704,7 +633,7 @@ class Rant::RantApp
|
|
704
633
|
end
|
705
634
|
unless arg.is_a? String
|
706
635
|
abort(pos_text(file, ln),
|
707
|
-
"
|
636
|
+
"subdirs: arguments must be strings")
|
708
637
|
end
|
709
638
|
loaded = false
|
710
639
|
prev_subdir = @current_subdir
|
@@ -727,22 +656,32 @@ class Rant::RantApp
|
|
727
656
|
goto_project_dir prev_subdir
|
728
657
|
end
|
729
658
|
unless loaded || quiet?
|
730
|
-
warn_msg(pos_text(file, ln)
|
731
|
-
"No Rantfile in subdir `#{arg}'.")
|
659
|
+
warn_msg(pos_text(file, ln),
|
660
|
+
"subdirs: No Rantfile in subdir `#{arg}'.")
|
732
661
|
end
|
733
662
|
}
|
734
663
|
rescue SystemCallError => e
|
735
|
-
abort(pos_text(file, ln),
|
736
|
-
"in `subdirs' command: " + e.message)
|
664
|
+
abort(pos_text(file, ln), "subdirs: " + e.message)
|
737
665
|
end
|
738
666
|
|
739
|
-
def sys(*args)
|
667
|
+
def sys(*args, &block)
|
740
668
|
if args.empty?
|
741
669
|
@sys
|
742
670
|
else
|
743
671
|
@sys.sh(*args)
|
744
672
|
end
|
745
673
|
end
|
674
|
+
|
675
|
+
# The [] and []= operators may be used to set/get values from this
|
676
|
+
# object (like a hash). It is intended to let the different
|
677
|
+
# modules, plugins and tasks to communicate with each other.
|
678
|
+
def var(*args, &block)
|
679
|
+
if args.empty?
|
680
|
+
@var
|
681
|
+
else
|
682
|
+
@var.query(*args, &block)
|
683
|
+
end
|
684
|
+
end
|
746
685
|
##################################################################
|
747
686
|
|
748
687
|
# Pop (remove and return) current pending task description.
|
@@ -759,6 +698,12 @@ class Rant::RantApp
|
|
759
698
|
raise Rant::RantAbortException
|
760
699
|
end
|
761
700
|
|
701
|
+
def abort_at(ch, *msg)
|
702
|
+
err_msg(pos_text(ch[:file], ch[:ln]), msg)
|
703
|
+
$stderr.puts caller if @opts[:trace_abort]
|
704
|
+
raise Rant::RantAbortException
|
705
|
+
end
|
706
|
+
|
762
707
|
def help
|
763
708
|
puts "rant [-f RANTFILE] [OPTIONS] tasks..."
|
764
709
|
puts
|
@@ -769,27 +714,56 @@ class Rant::RantApp
|
|
769
714
|
|
770
715
|
def show_descriptions
|
771
716
|
tlist = select_tasks { |t| t.description }
|
717
|
+
# +target_list+ aborts if no task defined, so we can be sure
|
718
|
+
# that +default+ is not nil
|
719
|
+
def_target = target_list.first
|
772
720
|
if tlist.empty?
|
773
|
-
|
721
|
+
puts "rant # => " + list_task_names(
|
722
|
+
resolve(def_target)).join(', ')
|
723
|
+
msg "No described tasks."
|
774
724
|
return
|
775
725
|
end
|
776
726
|
prefix = "rant "
|
777
727
|
infix = " # "
|
778
728
|
name_length = 0
|
779
729
|
tlist.each { |t|
|
780
|
-
if t.
|
781
|
-
name_length = t.
|
730
|
+
if t.full_name.length > name_length
|
731
|
+
name_length = t.full_name.length
|
782
732
|
end
|
783
733
|
}
|
784
734
|
name_length < 7 && name_length = 7
|
785
735
|
cmd_length = prefix.length + name_length
|
736
|
+
# TODO: show what's done if rant is invoked without argument
|
737
|
+
unless tlist.first.full_name == def_target
|
738
|
+
defaults = list_task_names(
|
739
|
+
resolve(def_target)).join(', ')
|
740
|
+
puts "#{prefix}#{' ' * name_length}#{infix}=> #{defaults}"
|
741
|
+
end
|
786
742
|
tlist.each { |t|
|
787
|
-
print(prefix + t.
|
743
|
+
print(prefix + t.full_name.ljust(name_length) + infix)
|
788
744
|
dt = t.description.sub(/\s+$/, "")
|
789
745
|
puts dt.sub("\n", "\n" + ' ' * cmd_length + infix + " ")
|
790
746
|
}
|
791
747
|
true
|
792
748
|
end
|
749
|
+
def list_task_names(*tasks)
|
750
|
+
rsl = []
|
751
|
+
tasks.flatten.each { |t|
|
752
|
+
if t.respond_to?(:has_actions?) && t.has_actions?
|
753
|
+
rsl << t
|
754
|
+
elsif t.respond_to? :prerequisites
|
755
|
+
if t.prerequisites.empty?
|
756
|
+
rsl << t
|
757
|
+
else
|
758
|
+
rsl.concat(list_task_names(t.prerequisites))
|
759
|
+
end
|
760
|
+
else
|
761
|
+
rsl << t
|
762
|
+
end
|
763
|
+
}
|
764
|
+
rsl
|
765
|
+
end
|
766
|
+
private :list_task_names
|
793
767
|
|
794
768
|
# Increase verbosity.
|
795
769
|
def more_verbose
|
@@ -864,8 +838,8 @@ class Rant::RantApp
|
|
864
838
|
not @rantfiles.all? { |f| f.tasks.empty? }
|
865
839
|
end
|
866
840
|
|
867
|
-
def
|
868
|
-
|
841
|
+
def target_list
|
842
|
+
if !have_any_task? && @resolve_hooks.empty?
|
869
843
|
abort("No tasks defined for this rant application!")
|
870
844
|
end
|
871
845
|
|
@@ -876,49 +850,81 @@ class Rant::RantApp
|
|
876
850
|
target_list = @force_targets + @arg_targets
|
877
851
|
# The target list is a list of strings, not Task objects!
|
878
852
|
if target_list.empty?
|
879
|
-
|
880
|
-
|
881
|
-
}
|
882
|
-
|
853
|
+
def_tasks = resolve "default"
|
854
|
+
#have_default = @rantfiles.any? { |f|
|
855
|
+
# f.tasks.any? { |t| t.name == "default" }
|
856
|
+
#}
|
857
|
+
unless def_tasks.empty?
|
883
858
|
target_list << "default"
|
884
859
|
else
|
885
860
|
first = nil
|
886
861
|
@rantfiles.each { |f|
|
887
862
|
unless f.tasks.empty?
|
888
|
-
first = f.tasks.first.
|
863
|
+
first = f.tasks.first.full_name
|
889
864
|
break
|
890
865
|
end
|
891
866
|
}
|
892
867
|
target_list << first
|
893
868
|
end
|
894
869
|
end
|
870
|
+
target_list
|
871
|
+
end
|
872
|
+
|
873
|
+
def run_tasks
|
895
874
|
# Now, run all specified tasks in all rantfiles,
|
896
875
|
# rantfiles in reverse order.
|
897
876
|
opt = {}
|
898
877
|
matching_tasks = 0
|
899
878
|
target_list.each do |target|
|
900
|
-
|
901
|
-
if
|
902
|
-
opt[:force] = true
|
903
|
-
@force_targets.delete(target)
|
904
|
-
end
|
905
|
-
### pre 0.3.1 ###
|
906
|
-
#(select_tasks { |t| t.name == target }).each { |t|
|
907
|
-
select_tasks_by_name(target).each { |t|
|
908
|
-
matching_tasks += 1
|
909
|
-
begin
|
910
|
-
t.invoke(opt)
|
911
|
-
rescue Rant::TaskFail => e
|
912
|
-
# TODO: Report failed dependancy.
|
913
|
-
abort("Task `#{e.tname}' fail.")
|
914
|
-
end
|
915
|
-
}
|
916
|
-
if matching_tasks == 0
|
879
|
+
goto "#"
|
880
|
+
if build(target) == 0
|
917
881
|
abort("Don't know how to build `#{target}'.")
|
918
882
|
end
|
919
883
|
end
|
920
884
|
end
|
921
885
|
|
886
|
+
# Invoke all tasks necessary to build +target+. Returns the number
|
887
|
+
# of tasks invoked.
|
888
|
+
def build target, opt = {}
|
889
|
+
opt[:force] = true if @force_targets.delete(target)
|
890
|
+
matching_tasks = 0
|
891
|
+
resolve(target).each { |t|
|
892
|
+
matching_tasks += 1
|
893
|
+
begin
|
894
|
+
t.invoke(opt)
|
895
|
+
rescue Rant::TaskFail => e
|
896
|
+
# TODO: Report failed dependancy.
|
897
|
+
abort("Task `#{e.tname}' fail.")
|
898
|
+
end
|
899
|
+
}
|
900
|
+
matching_tasks
|
901
|
+
end
|
902
|
+
|
903
|
+
def resolve task_name, rel_project_dir = @current_subdir
|
904
|
+
#select_tasks_by_name task_name, rel_project_dir
|
905
|
+
# Note: first lines copied from +select_tasks_by_name+
|
906
|
+
# for efficiency reasons
|
907
|
+
s = @tasks[expand_path(rel_project_dir, task_name)]
|
908
|
+
case s
|
909
|
+
when nil
|
910
|
+
@resolve_hooks.each { |s|
|
911
|
+
# Note: will probably change to get more params
|
912
|
+
s = s[task_name]
|
913
|
+
return s if s
|
914
|
+
}
|
915
|
+
[]
|
916
|
+
when Rant::Worker: [s]
|
917
|
+
else # assuming MetaTask
|
918
|
+
s
|
919
|
+
end
|
920
|
+
end
|
921
|
+
public :resolve
|
922
|
+
|
923
|
+
def at_resolve &block
|
924
|
+
@resolve_hooks << block if block
|
925
|
+
end
|
926
|
+
public :at_resolve
|
927
|
+
|
922
928
|
# Returns a list with all tasks for which yield
|
923
929
|
# returns true.
|
924
930
|
def select_tasks
|
@@ -1074,8 +1080,8 @@ class Rant::RantApp
|
|
1074
1080
|
ARGV.replace(old_argv)
|
1075
1081
|
rem_args.each { |ra|
|
1076
1082
|
if ra =~ /(^[^=]+)=([^=]+)$/
|
1077
|
-
msg 2, "
|
1078
|
-
|
1083
|
+
msg 2, "var: #$1=#$2"
|
1084
|
+
@var[$1] = $2
|
1079
1085
|
else
|
1080
1086
|
@arg_targets << ra
|
1081
1087
|
end
|
@@ -1165,13 +1171,15 @@ class Rant::RantApp
|
|
1165
1171
|
name = normalize_task_name(k, file, ln)
|
1166
1172
|
pre = v
|
1167
1173
|
}
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1174
|
+
unless ::Rant::FileList === pre
|
1175
|
+
if pre.respond_to? :to_ary
|
1176
|
+
pre = pre.to_ary.dup
|
1177
|
+
pre.map! { |elem|
|
1178
|
+
normalize_task_name(elem, file, ln)
|
1179
|
+
}
|
1180
|
+
else
|
1181
|
+
pre = [normalize_task_name(pre, file, ln)]
|
1182
|
+
end
|
1175
1183
|
end
|
1176
1184
|
else
|
1177
1185
|
name = normalize_task_name(targ, file, ln)
|
@@ -1216,9 +1224,9 @@ class Rant::RantApp
|
|
1216
1224
|
end
|
1217
1225
|
end
|
1218
1226
|
|
1219
|
-
# Just ensure that Rant.
|
1227
|
+
# Just ensure that Rant.rac holds an RantApp after loading
|
1220
1228
|
# this file. The code in initialize will register the new app with
|
1221
|
-
# Rant.
|
1229
|
+
# Rant.rac= if necessary.
|
1222
1230
|
self.new
|
1223
1231
|
|
1224
1232
|
end # class Rant::RantApp
|