rake 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rake might be problematic. Click here for more details.

data/CHANGES CHANGED
@@ -1,6 +1,20 @@
1
1
  = Rake Changelog
2
2
 
3
- == Pre-version 0.7.3
3
+ == Pre-Version 0.7.4
4
+
5
+ * Added task parameters (e.g. "rake build[version7]")
6
+ * Made task parameters passable to prerequisites.
7
+ * The 'desc' command will now document task argument names.
8
+ * Comments are limited to 80 columns or so (suggested by Jamis Buck).
9
+ * Added -D to display full comments (suggested by Jamis Buck).
10
+ * The rake program will set the status value used in any explicit
11
+ exit(n) calls. (patch provided by Stephen Touset)
12
+ * Fixed error in functional tests that were not including session (and
13
+ silently skipping the functionl tests.
14
+ * Removed --usage and make -h the same as -H.
15
+ * Make a prettier inspect for tasks.
16
+
17
+ == Version 0.7.3
4
18
 
5
19
  * Added existing and existing! methods to FileList
6
20
  * FileLists now claim to be Arrays (via is_a?) to get better support
data/Rakefile CHANGED
@@ -23,7 +23,7 @@ CLOBBER.include('test/data/chains/play.*')
23
23
  CLOBBER.include('test/data/file_creation_task/build')
24
24
  CLOBBER.include('test/data/file_creation_task/src')
25
25
  CLOBBER.include('TAGS')
26
- CLOBBER.include('coverage')
26
+ CLOBBER.include('coverage', 'rcov_aggregate')
27
27
 
28
28
  def announce(msg='')
29
29
  STDERR.puts msg
@@ -37,11 +37,7 @@ else
37
37
  CURRENT_VERSION = "0.0.0"
38
38
  end
39
39
 
40
- if ENV['REL']
41
- PKG_VERSION = ENV['REL']
42
- else
43
- PKG_VERSION = CURRENT_VERSION
44
- end
40
+ $package_version = CURRENT_VERSION
45
41
 
46
42
  SRC_RB = FileList['lib/**/*.rb']
47
43
 
@@ -51,6 +47,9 @@ desc "Default Task"
51
47
  task :default => :test_all
52
48
 
53
49
  # Test Tasks ---------------------------------------------------------
50
+ task :dbg do |t|
51
+ puts "Arguments are: #{t.args.join(', ')}"
52
+ end
54
53
 
55
54
  # Common Abbreviations ...
56
55
 
@@ -79,13 +78,13 @@ end
79
78
  Rake::TestTask.new(:test_functional) do |t|
80
79
  t.test_files = FileList['test/fun*.rb']
81
80
  t.warning = true
82
- t.warning = true
81
+ t.verbose = false
83
82
  end
84
83
 
85
84
  Rake::TestTask.new(:test_contribs) do |t|
86
85
  t.test_files = FileList['test/contrib/test*.rb']
87
- t.verbose = false
88
86
  t.warning = true
87
+ t.verbose = false
89
88
  end
90
89
 
91
90
  begin
@@ -93,15 +92,17 @@ begin
93
92
 
94
93
  Rcov::RcovTask.new do |t|
95
94
  t.libs << "test"
96
- t.rcov_opts = ['-xRakefile', '-xrakefile', '-xpublish.rf', '--text-report']
95
+ t.rcov_opts = [
96
+ '-xRakefile', '-xrakefile', '-xpublish.rf', '--text-report',
97
+ ]
97
98
  t.test_files = FileList[
98
- 'test/test*.rb',
99
- 'test/contrib/test*.rb'
99
+ 'test/test*.rb', 'test/functional.rb'
100
100
  ]
101
+ t.output_dir = 'coverage'
101
102
  t.verbose = true
102
103
  end
103
104
  rescue LoadError
104
- # No rcov available
105
+ puts "RCov is not available"
105
106
  end
106
107
 
107
108
  directory 'testdata'
@@ -160,7 +161,7 @@ else
160
161
  #### Basic information.
161
162
 
162
163
  s.name = 'rake'
163
- s.version = PKG_VERSION
164
+ s.version = $package_version
164
165
  s.summary = "Ruby based make-like utility."
165
166
  s.description = <<-EOF
166
167
  Rake is a Make-like program implemented in Ruby. Tasks
@@ -246,12 +247,6 @@ task :lines do
246
247
  show_line("TOTAL", total_lines, total_code)
247
248
  end
248
249
 
249
- ARCHIVEDIR = '/mnt/usb'
250
-
251
- task :archive => [:package] do
252
- cp FileList["pkg/*.tgz", "pkg/*.zip", "pkg/*.gem"], ARCHIVEDIR
253
- end
254
-
255
250
  # Define an optional publish target in an external file. If the
256
251
  # publish.rf file is not found, the publish targets won't be defined.
257
252
 
@@ -259,86 +254,108 @@ load "publish.rf" if File.exist? "publish.rf"
259
254
 
260
255
  # Support Tasks ------------------------------------------------------
261
256
 
257
+ RUBY_FILES = FileList['**/*.rb'].exclude('pkg')
258
+
262
259
  desc "Look for TODO and FIXME tags in the code"
263
260
  task :todo do
264
- FileList['**/*.rb'].exclude('pkg').egrep(/#.*(FIXME|TODO|TBD)/)
261
+ RUBY_FILES.egrep(/#.*(FIXME|TODO|TBD)/)
265
262
  end
266
263
 
267
264
  desc "Look for Debugging print lines"
268
265
  task :dbg do
269
- FileList['**/*.rb'].egrep(/\bDBG|\bbreakpoint\b/)
266
+ RUBY_FILES.egrep(/\bDBG|\bbreakpoint\b/)
270
267
  end
271
268
 
272
269
  desc "List all ruby files"
273
270
  task :rubyfiles do
274
- puts Dir['**/*.rb'].reject { |fn| fn =~ /^pkg/ }
275
- puts Dir['bin/*'].reject { |fn| fn =~ /CVS|(~$)|(\.rb$)/ }
271
+ puts RUBY_FILES
272
+ puts FileList['bin/*'].exclude('bin/*.rb')
276
273
  end
277
274
  task :rf => :rubyfiles
278
275
 
276
+ desc "Create a TAGS file"
277
+ task :tags => "TAGS"
278
+
279
+ TAGS = 'xctags -e'
280
+
281
+ file "TAGS" => RUBY_FILES do
282
+ puts "Makings TAGS"
283
+ sh "#{TAGS} #{RUBY_FILES}", :verbose => false
284
+ end
285
+
279
286
  # --------------------------------------------------------------------
280
287
  # Creating a release
281
288
 
289
+ def plugin(plugin_name)
290
+ require "rake/plugins/#{plugin_name}"
291
+ end
292
+
293
+ task :noop
294
+ #plugin "release_manager"
295
+
282
296
  desc "Make a new release"
283
- task :release => [
284
- :prerelease,
285
- :clobber,
286
- :test_all,
287
- :update_version,
288
- :package,
289
- :tag] do
290
-
297
+ task :release, :rel, :reuse, :reltest,
298
+ :needs => [
299
+ :prerelease,
300
+ :clobber,
301
+ :test_all,
302
+ :update_version,
303
+ :package,
304
+ :tag
305
+ ] do
291
306
  announce
292
307
  announce "**************************************************************"
293
- announce "* Release #{PKG_VERSION} Complete."
308
+ announce "* Release #{$package_version} Complete."
294
309
  announce "* Packages ready to upload."
295
310
  announce "**************************************************************"
296
311
  announce
297
312
  end
298
313
 
299
314
  # Validate that everything is ready to go for a release.
300
- task :prerelease do
315
+ task :prerelease, :rel, :reuse, :reltest do |t, args|
316
+ $package_version = args.rel
301
317
  announce
302
318
  announce "**************************************************************"
303
- announce "* Making RubyGem Release #{PKG_VERSION}"
319
+ announce "* Making RubyGem Release #{$package_version}"
304
320
  announce "* (current version #{CURRENT_VERSION})"
305
321
  announce "**************************************************************"
306
322
  announce
307
323
 
308
324
  # Is a release number supplied?
309
- unless ENV['REL']
310
- fail "Usage: rake release REL=x.y.z [REUSE=tag_suffix]"
325
+ unless args.rel
326
+ fail "Usage: rake release[X.Y.Z] [REUSE=tag_suffix]"
311
327
  end
312
328
 
313
329
  # Is the release different than the current release.
314
330
  # (or is REUSE set?)
315
- if PKG_VERSION == CURRENT_VERSION && ! ENV['REUSE']
316
- fail "Current version is #{PKG_VERSION}, must specify REUSE=tag_suffix to reuse version"
331
+ if $package_version == CURRENT_VERSION && ! args.reuse
332
+ fail "Current version is #{$package_version}, must specify REUSE=tag_suffix to reuse version"
317
333
  end
318
334
 
319
335
  # Are all source files checked in?
320
- if ENV['RELTEST']
336
+ if args.reltest
321
337
  announce "Release Task Testing, skipping checked-in file test"
322
338
  else
323
339
  announce "Checking for unchecked-in files..."
324
- data = `cvs -q update`
340
+ data = `svn st`
325
341
  unless data =~ /^$/
326
- fail "CVS update is not clean ... do you have unchecked-in files?"
342
+ abort "svn status is not clean ... do you have unchecked-in files?"
327
343
  end
328
344
  announce "No outstanding checkins found ... OK"
329
345
  end
330
346
  end
331
347
 
332
- task :update_version => [:prerelease] do
333
- if PKG_VERSION == CURRENT_VERSION
348
+ task :update_version, :rel, :reuse, :reltest,
349
+ :needs => [:prerelease] do |t, args|
350
+ if args.rel == CURRENT_VERSION
334
351
  announce "No version change ... skipping version update"
335
352
  else
336
- announce "Updating Rake version to #{PKG_VERSION}"
353
+ announce "Updating Rake version to #{args.rel}"
337
354
  open("lib/rake.rb") do |rakein|
338
355
  open("lib/rake.rb.new", "w") do |rakeout|
339
356
  rakein.each do |line|
340
357
  if line =~ /^RAKEVERSION\s*=\s*/
341
- rakeout.puts "RAKEVERSION = '#{PKG_VERSION}'"
358
+ rakeout.puts "RAKEVERSION = '#{args.rel}'"
342
359
  else
343
360
  rakeout.puts line
344
361
  end
@@ -346,23 +363,24 @@ task :update_version => [:prerelease] do
346
363
  end
347
364
  end
348
365
  mv "lib/rake.rb.new", "lib/rake.rb"
349
- if ENV['RELTEST']
366
+ if args.reltest
350
367
  announce "Release Task Testing, skipping commiting of new version"
351
368
  else
352
- sh %{cvs commit -m "Updated to version #{PKG_VERSION}" lib/rake.rb} # "
369
+ sh %{svn commit -m "Updated to version #{args.rel}" lib/rake.rb} # "
353
370
  end
354
371
  end
355
372
  end
356
373
 
357
374
  desc "Tag all the CVS files with the latest release number (REL=x.y.z)"
358
- task :tag => [:prerelease] do
359
- reltag = "REL_#{PKG_VERSION.gsub(/\./, '_')}"
360
- reltag << ENV['REUSE'].gsub(/\./, '_') if ENV['REUSE']
361
- announce "Tagging CVS with [#{reltag}]"
362
- if ENV['RELTEST']
375
+ task :tag, :rel, :reuse, :reltest,
376
+ :needs => [:prerelease] do |t, args|
377
+ reltag = "REL_#{args.rel.gsub(/\./, '_')}"
378
+ reltag << args.reuse.gsub(/\./, '_') if args.reuse
379
+ announce "Tagging Repository with [#{reltag}]"
380
+ if args.reltest
363
381
  announce "Release Task Testing, skipping CVS tagging"
364
382
  else
365
- sh %{cvs tag #{reltag}}
383
+ sh %{svn copy svn+ssh://rubyforge.org/var/svn/rake/trunk svn+ssh://rubyforge.org/var/svn/rake/tags/#{reltag} -m 'Commiting release #{reltag}'} ###'
366
384
  end
367
385
  end
368
386
 
@@ -378,6 +396,7 @@ end
378
396
 
379
397
  load 'xforge.rf' if File.exist?('xforge.rf')
380
398
 
399
+ desc "Where is the current directory. This task displays\nthe current rake directory"
381
400
  task :where_am_i do
382
401
  puts Rake.original_dir
383
402
  end
data/TODO CHANGED
@@ -4,6 +4,7 @@ Send suggestions for this list to mailto:jim@weirichhouse.org or on
4
4
  the rake-devel@rubyforge.org mailing list.
5
5
 
6
6
  === To Do
7
+ * Need a nice API for accessing tasks in namespaces, namespaces in an app, etc.
7
8
  * Provide a way to disable -w warning mode.
8
9
  * Define a set of default rules that work in the absense of any Rakefile
9
10
  * What about cyclic dependencies?
data/bin/rake CHANGED
@@ -1,3 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to
8
+ # deal in the Software without restriction, including without limitation the
9
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
+ # sell copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
+ # IN THE SOFTWARE.
23
+ #++
24
+
1
25
  begin
2
26
  require 'rake'
3
27
  rescue LoadError
@@ -2,7 +2,7 @@
2
2
 
3
3
  #--
4
4
 
5
- # Copyright (c) 2003, 2004, 2005, 2006 Jim Weirich
5
+ # Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"), to
@@ -24,12 +24,12 @@
24
24
  #++
25
25
  #
26
26
  # = Rake -- Ruby Make
27
- #
27
+ #
28
28
  # This is the main file for the Rake application. Normally it is referenced
29
29
  # as a library via a require statement, but it can be distributed
30
30
  # independently as an application.
31
31
 
32
- RAKEVERSION = '0.7.3'
32
+ RAKEVERSION = '0.8.0'
33
33
 
34
34
  require 'rbconfig'
35
35
  require 'ftools'
@@ -43,7 +43,6 @@ require 'ostruct'
43
43
  # Rake extensions to Module.
44
44
  #
45
45
  class Module
46
-
47
46
  # Check for an existing method in the current class before extending. IF
48
47
  # the method already exists, then a warning is printed and the extension is
49
48
  # not added. Otherwise the block is yielded and any definitions in the
@@ -60,13 +59,13 @@ class Module
60
59
  # end
61
60
  #
62
61
  def rake_extension(method)
63
- if instance_methods.include?(method)
62
+ if instance_methods.include?(method.to_s) || instance_methods.include?(method.to_sym)
64
63
  $stderr.puts "WARNING: Possible conflict with Rake extension: #{self}##{method} already exists"
65
64
  else
66
65
  yield
67
66
  end
68
67
  end
69
- end
68
+ end # module Module
70
69
 
71
70
 
72
71
  ######################################################################
@@ -103,23 +102,19 @@ class String
103
102
  # front end (left hand side) if +n+ is positive. Include |+n+|
104
103
  # directories from the back end (right hand side) if +n+ is negative.
105
104
  def pathmap_partial(n)
106
- target = File.dirname(self)
107
- dirs = target.pathmap_explode
108
- if n > 0
109
- File.join(dirs[0...n])
110
- elsif n < 0
111
- partial = dirs[n..-1]
112
- if partial.nil? || partial.empty?
113
- target
105
+ dirs = File.dirname(self).pathmap_explode
106
+ partial_dirs =
107
+ if n > 0
108
+ dirs[0...n]
109
+ elsif n < 0
110
+ dirs.reverse[0...-n].reverse
114
111
  else
115
- File.join(partial)
112
+ "."
116
113
  end
117
- else
118
- "."
119
- end
114
+ File.join(partial_dirs)
120
115
  end
121
116
  protected :pathmap_partial
122
-
117
+
123
118
  # Preform the pathmap replacement operations on the given path. The
124
119
  # patterns take the form 'pat1,rep1;pat2,rep2...'.
125
120
  def pathmap_replace(patterns, &block)
@@ -143,7 +138,7 @@ class String
143
138
  # controls the details of the mapping. The following special patterns are
144
139
  # recognized:
145
140
  #
146
- # * <b>%p</b> -- The complete path.
141
+ # * <b>%p</b> -- The complete path.
147
142
  # * <b>%f</b> -- The base file name of the path, with its file extension,
148
143
  # but without any directories.
149
144
  # * <b>%n</b> -- The file name of the path without its file extension.
@@ -178,10 +173,10 @@ class String
178
173
  # excluded from both the pattern and replacement text (let's keep parsing
179
174
  # reasonable).
180
175
  #
181
- # For example:
176
+ # For example:
182
177
  #
183
178
  # "src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")
184
- #
179
+ #
185
180
  # returns:
186
181
  #
187
182
  # "bin/org/onestepback/proj/A.class"
@@ -213,7 +208,7 @@ class String
213
208
  when '%x'
214
209
  result << $1 if self =~ /[^\/](\.[^.]+)$/
215
210
  when '%X'
216
- if self =~ /^(.+[^\/])(\.[^.]+)$/
211
+ if self =~ /^(.*[^\/])(\.[^.]+)$/
217
212
  result << $1
218
213
  else
219
214
  result << self
@@ -240,7 +235,7 @@ class String
240
235
  result
241
236
  end
242
237
  end
243
- end
238
+ end # class String
244
239
 
245
240
  ##############################################################################
246
241
  module Rake
@@ -283,7 +278,122 @@ module Rake
283
278
  end
284
279
  alias dup clone
285
280
  end
286
- end
281
+
282
+ ####################################################################
283
+ # TaskAguments manage the arguments passed to a task.
284
+ #
285
+ class TaskArguments
286
+ include Enumerable
287
+
288
+ attr_reader :names
289
+
290
+ def initialize(names, values, parent=nil)
291
+ @names = names
292
+ @parent = parent
293
+ @hash = {}
294
+ names.each_with_index { |name, i|
295
+ @hash[name.to_sym] = values[i]
296
+ }
297
+ end
298
+
299
+ # Create a new argument scope using the prerequisite argument
300
+ # names.
301
+ def new_scope(names)
302
+ values = names.collect { |n| self[n] }
303
+ self.class.new(names, values, self)
304
+ end
305
+
306
+ # Find an argument value by name or index.
307
+ def [](index)
308
+ lookup(index.to_sym)
309
+ end
310
+
311
+ def each(&block)
312
+ @hash.each(&block)
313
+ end
314
+
315
+ def method_missing(sym, *args, &block)
316
+ lookup(sym.to_sym)
317
+ end
318
+
319
+ def to_hash
320
+ @hash
321
+ end
322
+
323
+ def to_s
324
+ @hash.inspect
325
+ end
326
+
327
+ def inspect
328
+ to_s
329
+ end
330
+
331
+ protected
332
+
333
+ def lookup(name)
334
+ if @hash.has_key?(name)
335
+ @hash[name]
336
+ elsif ENV.has_key?(name.to_s)
337
+ ENV[name.to_s]
338
+ elsif ENV.has_key?(name.to_s.upcase)
339
+ ENV[name.to_s.upcase]
340
+ elsif @parent
341
+ @parent.lookup(name)
342
+ end
343
+ end
344
+ end
345
+
346
+ ####################################################################
347
+ # InvocationChain tracks the chain of task invocations to detect
348
+ # circular dependencies.
349
+ class InvocationChain
350
+ def initialize(value, tail)
351
+ @value = value
352
+ @tail = tail
353
+ end
354
+
355
+ def member?(obj)
356
+ @value == obj || @tail.member?(obj)
357
+ end
358
+
359
+ def append(value)
360
+ if member?(value)
361
+ fail RuntimeError, "Circular dependency detected: #{to_s} => #{value}"
362
+ end
363
+ self.class.new(value, self)
364
+ end
365
+
366
+ def to_s
367
+ "#{prefix}#{@value}"
368
+ end
369
+
370
+ def self.append(value, chain)
371
+ chain.append(value)
372
+ end
373
+
374
+ private
375
+
376
+ def prefix
377
+ "#{@tail.to_s} => "
378
+ end
379
+
380
+ class EmptyInvocationChain
381
+ def member?(obj)
382
+ false
383
+ end
384
+ def append(value)
385
+ InvocationChain.new(value, self)
386
+ end
387
+ def to_s
388
+ "TOP"
389
+ end
390
+ end
391
+
392
+ EMPTY = EmptyInvocationChain.new
393
+
394
+ end # class InvocationChain
395
+
396
+ end # module Rake
287
397
 
288
398
  module Rake
289
399
 
@@ -302,10 +412,14 @@ module Rake
302
412
 
303
413
  # Application owning this task.
304
414
  attr_accessor :application
305
-
306
- # Comment for this task.
307
- attr_accessor :comment
308
-
415
+
416
+ # Comment for this task. Restricted to a single line of no more than 50
417
+ # characters.
418
+ attr_reader :comment
419
+
420
+ # Full text of the (possibly multi-line) comment.
421
+ attr_reader :full_comment
422
+
309
423
  # Array of nested namespaces names used for task lookup by this task.
310
424
  attr_reader :scope
311
425
 
@@ -313,7 +427,11 @@ module Rake
313
427
  def to_s
314
428
  name
315
429
  end
316
-
430
+
431
+ def inspect
432
+ "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
433
+ end
434
+
317
435
  # List of sources for task.
318
436
  attr_writer :sources
319
437
  def sources
@@ -324,7 +442,7 @@ module Rake
324
442
  def source
325
443
  @sources.first if defined?(@sources)
326
444
  end
327
-
445
+
328
446
  # Create a task named +task_name+ with no actions or prerequisites. Use
329
447
  # +enhance+ to add actions and prerequisites.
330
448
  def initialize(task_name, app)
@@ -332,41 +450,73 @@ module Rake
332
450
  @prerequisites = FileList[]
333
451
  @actions = []
334
452
  @already_invoked = false
453
+ @full_comment = nil
335
454
  @comment = nil
336
455
  @lock = Mutex.new
337
456
  @application = app
338
457
  @scope = app.current_scope
458
+ @arg_names = nil
339
459
  end
340
-
460
+
341
461
  # Enhance a task with prerequisites or actions. Returns self.
342
462
  def enhance(deps=nil, &block)
343
463
  @prerequisites |= deps if deps
344
464
  @actions << block if block_given?
345
465
  self
346
466
  end
347
-
467
+
348
468
  # Name of the task, including any namespace qualifiers.
349
469
  def name
350
470
  @name.to_s
351
471
  end
352
-
472
+
473
+ # Name of task with argument list description.
474
+ def name_with_args # :nodoc:
475
+ if arg_description
476
+ "#{name}#{arg_description}"
477
+ else
478
+ name
479
+ end
480
+ end
481
+
482
+ # Argument description (nil if none).
483
+ def arg_description # :nodoc:
484
+ @arg_names ? "[#{(arg_names || []).join(',')}]" : nil
485
+ end
486
+
487
+ # Name of arguments for this task.
488
+ def arg_names
489
+ @arg_names || []
490
+ end
491
+
353
492
  # Invoke the task if it is needed. Prerequites are invoked first.
354
- def invoke
493
+ def invoke(*args)
494
+ task_args = TaskArguments.new(arg_names, args)
495
+ invoke_with_call_chain(task_args, InvocationChain::EMPTY)
496
+ end
497
+
498
+ # Same as invoke, but explicitly pass a call chain to detect
499
+ # circular dependencies.
500
+ def invoke_with_call_chain(task_args, invocation_chain)
501
+ new_chain = InvocationChain.append(self, invocation_chain)
355
502
  @lock.synchronize do
356
503
  if application.options.trace
357
504
  puts "** Invoke #{name} #{format_trace_flags}"
358
505
  end
359
506
  return if @already_invoked
360
507
  @already_invoked = true
361
- invoke_prerequisites
362
- execute if needed?
508
+ invoke_prerequisites(task_args, new_chain)
509
+ execute(task_args) if needed?
363
510
  end
364
511
  end
512
+ protected :invoke_with_call_chain
365
513
 
366
514
  # Invoke all the prerequisites of a task.
367
- def invoke_prerequisites
515
+ def invoke_prerequisites(task_args, invocation_chain)
368
516
  @prerequisites.each { |n|
369
- application[n, @scope].invoke
517
+ prereq = application[n, @scope]
518
+ prereq_args = task_args.new_scope(prereq.arg_names)
519
+ prereq.invoke_with_call_chain(prereq_args, invocation_chain)
370
520
  }
371
521
  end
372
522
 
@@ -378,9 +528,9 @@ module Rake
378
528
  flags.empty? ? "" : "(" + flags.join(", ") + ")"
379
529
  end
380
530
  private :format_trace_flags
381
-
531
+
382
532
  # Execute the actions associated with this task.
383
- def execute
533
+ def execute(args)
384
534
  if application.options.dryrun
385
535
  puts "** Execute (dry run) #{name}"
386
536
  return
@@ -389,37 +539,68 @@ module Rake
389
539
  puts "** Execute #{name}"
390
540
  end
391
541
  application.enhance_with_matching_rule(name) if @actions.empty?
392
- @actions.each { |act| result = act.call(self) }
542
+ @actions.each do |act|
543
+ case act.arity
544
+ when 1
545
+ act.call(self)
546
+ else
547
+ act.call(self, args)
548
+ end
549
+ end
393
550
  end
394
-
551
+
395
552
  # Is this task needed?
396
553
  def needed?
397
554
  true
398
555
  end
399
-
556
+
400
557
  # Timestamp for this task. Basic tasks return the current time for their
401
558
  # time stamp. Other tasks can be more sophisticated.
402
559
  def timestamp
403
560
  @prerequisites.collect { |p| application[p].timestamp }.max || Time.now
404
561
  end
405
-
562
+
563
+ # Add a description to the task. The description can consist of an option
564
+ # argument list (enclosed brackets) and an optional comment.
565
+ def add_description(description)
566
+ return if ! description
567
+ comment = description.strip
568
+ add_comment(comment) if comment && ! comment.empty?
569
+ end
570
+
571
+ # Writing to the comment attribute is the same as adding a description.
572
+ def comment=(description)
573
+ add_description(description)
574
+ end
575
+
406
576
  # Add a comment to the task. If a comment alread exists, separate
407
577
  # the new comment with " / ".
408
578
  def add_comment(comment)
409
- return if ! comment
410
- if @comment
411
- @comment << " / "
579
+ if @full_comment
580
+ @full_comment << " / "
581
+ else
582
+ @full_comment = ''
583
+ end
584
+ @full_comment << comment
585
+ if @full_comment =~ /\A([^.]+?\.)( |$)/
586
+ @comment = $1
412
587
  else
413
- @comment = ''
588
+ @comment = @full_comment
414
589
  end
415
- @comment << comment
416
590
  end
417
-
591
+ private :add_comment
592
+
593
+ # Set the names of the arguments for this task. +args+ should be
594
+ # an array of symbols, one for each argument name.
595
+ def set_arg_names(args)
596
+ @arg_names = args.map { |a| a.to_sym }
597
+ end
598
+
418
599
  # Return a string describing the internal state of a task. Useful for
419
600
  # debugging.
420
601
  def investigation
421
602
  result = "------------------------------\n"
422
- result << "Investigating #{name}\n"
603
+ result << "Investigating #{name}\n"
423
604
  result << "class: #{self.class}\n"
424
605
  result << "task needed: #{needed?}\n"
425
606
  result << "timestamp: #{timestamp}\n"
@@ -434,23 +615,23 @@ module Rake
434
615
  result << "................................\n\n"
435
616
  return result
436
617
  end
437
-
618
+
438
619
  # ----------------------------------------------------------------
439
620
  # Rake Module Methods
440
- #
621
+ #
441
622
  class << self
442
-
623
+
443
624
  # Clear the task list. This cause rake to immediately forget all the
444
625
  # tasks that have been assigned. (Normally used in the unit tests.)
445
626
  def clear
446
627
  Rake.application.clear
447
628
  end
448
-
629
+
449
630
  # List of all defined tasks.
450
631
  def tasks
451
632
  Rake.application.tasks
452
633
  end
453
-
634
+
454
635
  # Return a task with the given name. If the task is not currently
455
636
  # known, try to synthesize one from the defined rules. If no rules are
456
637
  # found, but an existing file matches the task name, assume it is a file
@@ -458,22 +639,22 @@ module Rake
458
639
  def [](task_name)
459
640
  Rake.application[task_name]
460
641
  end
461
-
642
+
462
643
  # TRUE if the task name is already defined.
463
644
  def task_defined?(task_name)
464
645
  Rake.application.lookup(task_name) != nil
465
646
  end
466
-
647
+
467
648
  # Define a task given +args+ and an option block. If a rule with the
468
649
  # given name already exists, the prerequisites and actions are added to
469
650
  # the existing task. Returns the defined task.
470
- def define_task(args, &block)
471
- Rake.application.define_task(self, args, &block)
651
+ def define_task(*args, &block)
652
+ Rake.application.define_task(self, *args, &block)
472
653
  end
473
-
474
- # Define a rule for synthesizing tasks.
475
- def create_rule(args, &block)
476
- Rake.application.create_rule(args, &block)
654
+
655
+ # Define a rule for synthesizing tasks.
656
+ def create_rule(*args, &block)
657
+ Rake.application.create_rule(*args, &block)
477
658
  end
478
659
 
479
660
  # Apply the scope to the task name according to the rules for
@@ -483,10 +664,10 @@ module Rake
483
664
  (scope + [task_name]).join(':')
484
665
  end
485
666
 
486
- end
487
- end
488
-
489
-
667
+ end # class << Rake::Task
668
+ end # class Rake::Task
669
+
670
+
490
671
  # #########################################################################
491
672
  # A FileTask is a task that includes time based dependencies. If any of a
492
673
  # FileTask's prerequisites have a timestamp that is later than the file
@@ -494,7 +675,7 @@ module Rake
494
675
  # supplied actions).
495
676
  #
496
677
  class FileTask < Task
497
-
678
+
498
679
  # Is this file task needed? Yes if it doesn't exist, or if its time stamp
499
680
  # is out of date.
500
681
  def needed?
@@ -502,7 +683,7 @@ module Rake
502
683
  return true if out_of_date?(timestamp)
503
684
  false
504
685
  end
505
-
686
+
506
687
  # Time stamp for file task.
507
688
  def timestamp
508
689
  if File.exist?(name)
@@ -529,8 +710,8 @@ module Rake
529
710
  task_name
530
711
  end
531
712
  end
532
- end
533
-
713
+ end # class Rake::FileTask
714
+
534
715
  # #########################################################################
535
716
  # A FileCreationTask is a file task that when used as a dependency will be
536
717
  # needed if and only if the file has not been created. Once created, it is
@@ -542,7 +723,7 @@ module Rake
542
723
  def needed?
543
724
  ! File.exist?(name)
544
725
  end
545
-
726
+
546
727
  # Time stamp for file creation task. This time stamp is earlier
547
728
  # than any other time stamp.
548
729
  def timestamp
@@ -555,14 +736,14 @@ module Rake
555
736
  # parallel using Ruby threads.
556
737
  #
557
738
  class MultiTask < Task
558
- def invoke_prerequisites
739
+ def invoke_prerequisites(args, invocation_chain)
559
740
  threads = @prerequisites.collect { |p|
560
- Thread.new(p) { |r| application[r].invoke }
741
+ Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
561
742
  }
562
743
  threads.each { |t| t.join }
563
744
  end
564
745
  end
565
- end
746
+ end # module Rake
566
747
 
567
748
  # ###########################################################################
568
749
  # Task Definition Functions ...
@@ -574,8 +755,8 @@ end
574
755
  # rm_rf "html"
575
756
  # end
576
757
  #
577
- def task(args, &block)
578
- Rake::Task.define_task(args, &block)
758
+ def task(*args, &block)
759
+ Rake::Task.define_task(*args, &block)
579
760
  end
580
761
 
581
762
 
@@ -648,8 +829,8 @@ end
648
829
  # sh %{cc -o #{t.name} #{t.source}}
649
830
  # end
650
831
  #
651
- def rule(args, &block)
652
- Rake::Task.create_rule(args, &block)
832
+ def rule(*args, &block)
833
+ Rake::Task.create_rule(*args, &block)
653
834
  end
654
835
 
655
836
  # Describe the next rake task.
@@ -660,8 +841,8 @@ end
660
841
  # runtests
661
842
  # end
662
843
  #
663
- def desc(comment)
664
- Rake.application.last_comment = comment
844
+ def desc(description)
845
+ Rake.application.last_description = description
665
846
  end
666
847
 
667
848
  # Import the partial Rakefiles +fn+. Imported files are loaded _after_ the
@@ -713,8 +894,8 @@ module FileUtils
713
894
  options = (Hash === cmd.last) ? cmd.pop : {}
714
895
  unless block_given?
715
896
  show_command = cmd.join(" ")
716
- show_command = show_command[0,42] + "..."
717
- # TODO code application logic heref show_command.length > 45
897
+ show_command = show_command[0,42] + "..."
898
+ # TODO code application logic heref show_command.length > 45
718
899
  block = lambda { |ok, status|
719
900
  ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
720
901
  }
@@ -737,10 +918,10 @@ module FileUtils
737
918
  if args.length > 1 then
738
919
  sh(*([RUBY] + args + [options]), &block)
739
920
  else
740
- sh("#{RUBY} #{args}", options, &block)
921
+ sh("#{RUBY} #{args.first}", options, &block)
741
922
  end
742
923
  end
743
-
924
+
744
925
  LN_SUPPORTED = [true]
745
926
 
746
927
  # Attempt to do a normal file link, but fall back to a copy if the link
@@ -783,10 +964,10 @@ module RakeFileUtils
783
964
  end
784
965
  RakeFileUtils.verbose_flag = true
785
966
  RakeFileUtils.nowrite_flag = false
786
-
967
+
787
968
  $fileutils_verbose = true
788
969
  $fileutils_nowrite = false
789
-
970
+
790
971
  FileUtils::OPT_TABLE.each do |name, opts|
791
972
  default_options = []
792
973
  if opts.include?('verbose')
@@ -807,7 +988,7 @@ module RakeFileUtils
807
988
  EOS
808
989
  end
809
990
 
810
- # Get/set the verbose flag controlling output from the FileUtils utilities.
991
+ # Get/set the verbose flag controlling output from the FileUtils utilities.
811
992
  # If verbose is true, then the utility method is echoed to standard output.
812
993
  #
813
994
  # Examples:
@@ -828,7 +1009,7 @@ module RakeFileUtils
828
1009
  RakeFileUtils.verbose_flag
829
1010
  end
830
1011
 
831
- # Get/set the nowrite flag controlling output from the FileUtils utilities.
1012
+ # Get/set the nowrite flag controlling output from the FileUtils utilities.
832
1013
  # If verbose is true, then the utility method is echoed to standard output.
833
1014
  #
834
1015
  # Examples:
@@ -852,7 +1033,7 @@ module RakeFileUtils
852
1033
  # Use this function to prevent protentially destructive ruby code from
853
1034
  # running when the :nowrite flag is set.
854
1035
  #
855
- # Example:
1036
+ # Example:
856
1037
  #
857
1038
  # when_writing("Building Project") do
858
1039
  # project.build
@@ -943,7 +1124,7 @@ module Rake
943
1124
  # FileList/Array is requested, the pending patterns are resolved into a real
944
1125
  # list of file names.
945
1126
  #
946
- class FileList
1127
+ class FileList
947
1128
 
948
1129
  include Cloneable
949
1130
 
@@ -965,7 +1146,7 @@ module Rake
965
1146
 
966
1147
  # List of array methods (that are not in +Object+) that need to be
967
1148
  # delegated.
968
- ARRAY_METHODS = Array.instance_methods - Object.instance_methods
1149
+ ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
969
1150
 
970
1151
  # List of additional methods that must be delegated.
971
1152
  MUST_DEFINE = %w[to_a inspect]
@@ -981,16 +1162,16 @@ module Rake
981
1162
  compact flatten uniq values_at
982
1163
  + - & |
983
1164
  ]
984
-
1165
+
985
1166
  DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
986
-
1167
+
987
1168
  # Now do the delegation.
988
1169
  DELEGATING_METHODS.each_with_index do |sym, i|
989
1170
  if SPECIAL_RETURN.include?(sym)
990
1171
  ln = __LINE__+1
991
1172
  class_eval %{
992
1173
  def #{sym}(*args, &block)
993
- resolve if @pending
1174
+ resolve
994
1175
  result = @items.send(:#{sym}, *args, &block)
995
1176
  FileList.new.import(result)
996
1177
  end
@@ -999,7 +1180,7 @@ module Rake
999
1180
  ln = __LINE__+1
1000
1181
  class_eval %{
1001
1182
  def #{sym}(*args, &block)
1002
- resolve if @pending
1183
+ resolve
1003
1184
  result = @items.send(:#{sym}, *args, &block)
1004
1185
  result.object_id == @items.object_id ? self : result
1005
1186
  end
@@ -1048,8 +1229,8 @@ module Rake
1048
1229
  @pending = true
1049
1230
  self
1050
1231
  end
1051
- alias :add :include
1052
-
1232
+ alias :add :include
1233
+
1053
1234
  # Register a list of file name patterns that should be excluded from the
1054
1235
  # list. Patterns may be regular expressions, glob patterns or regular
1055
1236
  # strings. In addition, a block given to exclude will remove entries that
@@ -1072,16 +1253,16 @@ module Rake
1072
1253
  #
1073
1254
  def exclude(*patterns, &block)
1074
1255
  patterns.each do |pat|
1075
- @exclude_patterns << pat
1256
+ @exclude_patterns << pat
1076
1257
  end
1077
1258
  if block_given?
1078
1259
  @exclude_procs << block
1079
- end
1260
+ end
1080
1261
  resolve_exclude if ! @pending
1081
1262
  self
1082
1263
  end
1083
1264
 
1084
-
1265
+
1085
1266
  # Clear all the exclude patterns so that we exclude nothing.
1086
1267
  def clear_exclude
1087
1268
  @exclude_patterns = []
@@ -1105,7 +1286,7 @@ module Rake
1105
1286
  def to_ary
1106
1287
  to_a
1107
1288
  end
1108
-
1289
+
1109
1290
  # Lie about our class.
1110
1291
  def is_a?(klass)
1111
1292
  klass == Array || super(klass)
@@ -1240,7 +1421,7 @@ module Rake
1240
1421
  yield fn, count, line
1241
1422
  else
1242
1423
  puts "#{fn}:#{count}:#{line}"
1243
- end
1424
+ end
1244
1425
  end
1245
1426
  end
1246
1427
  end
@@ -1250,14 +1431,14 @@ module Rake
1250
1431
  # Return a new file list that only contains file names from the current
1251
1432
  # file list that exist on the file system.
1252
1433
  def existing
1253
- select { |fn| File.exists?(fn) }
1434
+ select { |fn| File.exist?(fn) }
1254
1435
  end
1255
-
1436
+
1256
1437
  # Modify the current file list so that it contains only file name that
1257
1438
  # exist on the file system.
1258
1439
  def existing!
1259
1440
  resolve
1260
- @items = @items.select { |fn| File.exists?(fn) }
1441
+ @items = @items.select { |fn| File.exist?(fn) }
1261
1442
  self
1262
1443
  end
1263
1444
 
@@ -1271,10 +1452,10 @@ module Rake
1271
1452
  FileList.new.import(result[1]),
1272
1453
  ]
1273
1454
  end
1274
-
1455
+
1275
1456
  # Convert a FileList to a string by joining all elements with a space.
1276
1457
  def to_s
1277
- resolve if @pending
1458
+ resolve
1278
1459
  self.join(' ')
1279
1460
  end
1280
1461
 
@@ -1301,7 +1482,7 @@ module Rake
1301
1482
  DEFAULT_IGNORE_PROCS = [
1302
1483
  proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
1303
1484
  ]
1304
- @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1485
+ # @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1305
1486
 
1306
1487
  def import(array)
1307
1488
  @items = array
@@ -1315,26 +1496,6 @@ module Rake
1315
1496
  def [](*args)
1316
1497
  new(*args)
1317
1498
  end
1318
-
1319
- # Set the ignore patterns back to the default value. The default
1320
- # patterns will ignore files
1321
- # * containing "CVS" in the file path
1322
- # * containing ".svn" in the file path
1323
- # * ending with ".bak"
1324
- # * ending with "~"
1325
- # * named "core"
1326
- #
1327
- # Note that file names beginning with "." are automatically ignored by
1328
- # Ruby's glob patterns and are not specifically listed in the ignore
1329
- # patterns.
1330
- def select_default_ignore_patterns
1331
- @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1332
- end
1333
-
1334
- # Clear the ignore patterns.
1335
- def clear_ignore_patterns
1336
- @exclude_patterns = [ /^$/ ]
1337
- end
1338
1499
  end
1339
1500
  end # FileList
1340
1501
  end
@@ -1352,7 +1513,7 @@ module Rake
1352
1513
  end
1353
1514
  end
1354
1515
  end
1355
- end
1516
+ end # module Rake
1356
1517
 
1357
1518
  # Alias FileList to be available at the top level.
1358
1519
  FileList = Rake::FileList
@@ -1382,7 +1543,7 @@ module Rake
1382
1543
  end
1383
1544
 
1384
1545
  EARLY = EarlyTime.instance
1385
- end
1546
+ end # module Rake
1386
1547
 
1387
1548
  # ###########################################################################
1388
1549
  # Extensions to time to allow comparisons with an early time class.
@@ -1395,8 +1556,8 @@ class Time
1395
1556
  else
1396
1557
  rake_original_time_compare(other)
1397
1558
  end
1398
- end
1399
- end
1559
+ end
1560
+ end # class Time
1400
1561
 
1401
1562
  module Rake
1402
1563
 
@@ -1412,7 +1573,7 @@ module Rake
1412
1573
  @task_manager = task_manager
1413
1574
  @scope = scope_list.dup
1414
1575
  end
1415
-
1576
+
1416
1577
  # Lookup a task named +name+ in the namespace.
1417
1578
  def [](name)
1418
1579
  @task_manager.lookup(name, @scope)
@@ -1422,37 +1583,39 @@ module Rake
1422
1583
  def tasks
1423
1584
  @task_manager.tasks
1424
1585
  end
1425
- end
1586
+ end # NameSpace
1426
1587
 
1427
1588
 
1428
1589
  ####################################################################
1429
- # The TaskManager module is a mixin for managing tasks.
1590
+ # The TaskManager module is a mixin for managing tasks.
1430
1591
  module TaskManager
1431
1592
  # Track the last comment made in the Rakefile.
1432
- attr_accessor :last_comment
1593
+ attr_accessor :last_description
1594
+ alias :last_comment :last_description # Backwards compatibility
1433
1595
 
1434
1596
  def initialize
1435
1597
  super
1436
1598
  @tasks = Hash.new
1437
1599
  @rules = Array.new
1438
1600
  @scope = Array.new
1439
- @last_comment = nil
1601
+ @last_description = nil
1440
1602
  end
1441
1603
 
1442
- def create_rule(args, &block)
1443
- pattern, deps = resolve_args(args)
1604
+ def create_rule(*args, &block)
1605
+ pattern, arg_names, deps = resolve_args(args)
1444
1606
  pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
1445
1607
  @rules << [pattern, deps, block]
1446
1608
  end
1447
1609
 
1448
- def define_task(task_class, args, &block)
1449
- task_name, deps = resolve_args(args)
1610
+ def define_task(task_class, *args, &block)
1611
+ task_name, arg_names, deps = resolve_args(args)
1450
1612
  task_name = task_class.scope_name(@scope, task_name)
1451
1613
  deps = [deps] unless deps.respond_to?(:to_ary)
1452
1614
  deps = deps.collect {|d| d.to_s }
1453
1615
  task = intern(task_class, task_name)
1454
- task.add_comment(@last_comment)
1455
- @last_comment = nil
1616
+ task.set_arg_names(arg_names) unless arg_names.empty?
1617
+ task.add_description(@last_description)
1618
+ @last_description = nil
1456
1619
  task.enhance(deps, &block)
1457
1620
  task
1458
1621
  end
@@ -1463,7 +1626,7 @@ module Rake
1463
1626
  @tasks[task_name.to_s] ||= task_class.new(task_name, self)
1464
1627
  end
1465
1628
 
1466
- # Find a matching task for +task_name+.
1629
+ # Find a matching task for +task_name+.
1467
1630
  def [](task_name, scopes=nil)
1468
1631
  task_name = task_name.to_s
1469
1632
  self.lookup(task_name, scopes) or
@@ -1476,23 +1639,27 @@ module Rake
1476
1639
  return nil unless File.exist?(task_name)
1477
1640
  define_task(Rake::FileTask, task_name)
1478
1641
  end
1479
-
1480
- # Resolve the arguments for a task/rule.
1642
+
1643
+ # Resolve the arguments for a task/rule. Returns a triplet of
1644
+ # [task_name, arg_name_list, prerequisites].
1481
1645
  def resolve_args(args)
1482
- case args
1483
- when Hash
1484
- fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1
1485
- fail "No Task Name Given" if args.size < 1
1486
- task_name = args.keys[0]
1487
- deps = args[task_name]
1488
- deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps)
1489
- else
1490
- task_name = args
1491
- deps = []
1646
+ task_name = args.shift
1647
+ arg_names = args #.map { |a| a.to_sym }
1648
+ needs = []
1649
+ if task_name.is_a?(Hash)
1650
+ hash = task_name
1651
+ task_name = hash.keys[0]
1652
+ needs = hash[task_name]
1653
+ end
1654
+ if arg_names.last.is_a?(Hash)
1655
+ hash = arg_names.pop
1656
+ needs = hash[:needs]
1657
+ fail "Unrecognized keys in task hash: #{hash.keys.inspect}" if hash.size > 1
1492
1658
  end
1493
- [task_name, deps]
1659
+ needs = [needs] unless needs.respond_to?(:to_ary)
1660
+ [task_name, arg_names, needs]
1494
1661
  end
1495
-
1662
+
1496
1663
  # If a rule can be found that matches the task name, enhance the
1497
1664
  # task with the prerequisites and actions from the rule. Set the
1498
1665
  # source attribute of the task appropriately for the rule. Return
@@ -1511,7 +1678,7 @@ module Rake
1511
1678
  ex.add_target(task_name)
1512
1679
  fail ex
1513
1680
  end
1514
-
1681
+
1515
1682
  # List of all defined tasks in this application.
1516
1683
  def tasks
1517
1684
  @tasks.values.sort_by { |t| t.name }
@@ -1543,7 +1710,7 @@ module Rake
1543
1710
  lookup_in_scope(task_name, scopes)
1544
1711
  end
1545
1712
 
1546
- # Lookup the task name
1713
+ # Lookup the task name
1547
1714
  def lookup_in_scope(name, scope)
1548
1715
  n = scope.size
1549
1716
  while n >= 0
@@ -1599,13 +1766,13 @@ module Rake
1599
1766
  task.sources = prereqs
1600
1767
  task
1601
1768
  end
1602
-
1769
+
1603
1770
  # Make a list of sources from the list of file name extensions /
1604
1771
  # translation procs.
1605
1772
  def make_sources(task_name, extensions)
1606
1773
  extensions.collect { |ext|
1607
1774
  case ext
1608
- when /^%/
1775
+ when /%/
1609
1776
  task_name.pathmap(ext)
1610
1777
  when %r{/}
1611
1778
  ext
@@ -1614,14 +1781,18 @@ module Rake
1614
1781
  when String
1615
1782
  ext
1616
1783
  when Proc
1617
- ext.call(task_name)
1784
+ if ext.arity == 1
1785
+ ext.call(task_name)
1786
+ else
1787
+ ext.call
1788
+ end
1618
1789
  else
1619
1790
  fail "Don't know how to handle rule dependent: #{ext.inspect}"
1620
1791
  end
1621
1792
  }.flatten
1622
1793
  end
1623
-
1624
- end
1794
+
1795
+ end # TaskManager
1625
1796
 
1626
1797
  ######################################################################
1627
1798
  # Rake main application object. When invoking +rake+ from the
@@ -1635,50 +1806,50 @@ module Rake
1635
1806
 
1636
1807
  # The original directory where rake was invoked.
1637
1808
  attr_reader :original_dir
1638
-
1809
+
1639
1810
  # Name of the actual rakefile used.
1640
1811
  attr_reader :rakefile
1641
-
1812
+
1642
1813
  # List of the top level task names (task names from the command line).
1643
1814
  attr_reader :top_level_tasks
1644
1815
 
1645
1816
  DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
1646
-
1817
+
1647
1818
  OPTIONS = [ # :nodoc:
1648
- ['--dry-run', '-n', GetoptLong::NO_ARGUMENT,
1649
- "Do a dry run without executing actions."],
1650
- ['--help', '-H', GetoptLong::NO_ARGUMENT,
1819
+ ['--classic-namespace', '-C', GetoptLong::NO_ARGUMENT,
1820
+ "Put Task and FileTask in the top level namespace"],
1821
+ ['--describe', '-D', GetoptLong::OPTIONAL_ARGUMENT,
1822
+ "Describe the tasks (matching optional PATTERN), then exit."],
1823
+ ['--rakefile', '-f', GetoptLong::OPTIONAL_ARGUMENT,
1824
+ "Use FILE as the rakefile."],
1825
+ ['--help', '-h', '-H', GetoptLong::NO_ARGUMENT,
1651
1826
  "Display this help message."],
1652
1827
  ['--libdir', '-I', GetoptLong::REQUIRED_ARGUMENT,
1653
1828
  "Include LIBDIR in the search path for required modules."],
1654
- ['--rakelibdir', '-R', GetoptLong::REQUIRED_ARGUMENT,
1655
- "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')"],
1829
+ ['--dry-run', '-n', GetoptLong::NO_ARGUMENT,
1830
+ "Do a dry run without executing actions."],
1656
1831
  ['--nosearch', '-N', GetoptLong::NO_ARGUMENT,
1657
1832
  "Do not search parent directories for the Rakefile."],
1658
1833
  ['--prereqs', '-P', GetoptLong::NO_ARGUMENT,
1659
1834
  "Display the tasks and dependencies, then exit."],
1660
1835
  ['--quiet', '-q', GetoptLong::NO_ARGUMENT,
1661
1836
  "Do not log messages to standard output."],
1662
- ['--rakefile', '-f', GetoptLong::OPTIONAL_ARGUMENT,
1663
- "Use FILE as the rakefile."],
1664
1837
  ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT,
1665
1838
  "Require MODULE before executing rakefile."],
1839
+ ['--rakelibdir', '-R', GetoptLong::REQUIRED_ARGUMENT,
1840
+ "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')"],
1666
1841
  ['--silent', '-s', GetoptLong::NO_ARGUMENT,
1667
1842
  "Like --quiet, but also suppresses the 'in directory' announcement."],
1668
1843
  ['--tasks', '-T', GetoptLong::OPTIONAL_ARGUMENT,
1669
1844
  "Display the tasks (matching optional PATTERN) with descriptions, then exit."],
1670
1845
  ['--trace', '-t', GetoptLong::NO_ARGUMENT,
1671
1846
  "Turn on invoke/execute tracing, enable full backtrace."],
1672
- ['--usage', '-h', GetoptLong::NO_ARGUMENT,
1673
- "Display usage."],
1674
1847
  ['--verbose', '-v', GetoptLong::NO_ARGUMENT,
1675
1848
  "Log message to standard output (default)."],
1676
1849
  ['--version', '-V', GetoptLong::NO_ARGUMENT,
1677
1850
  "Display the program version."],
1678
- ['--classic-namespace', '-C', GetoptLong::NO_ARGUMENT,
1679
- "Put Task and FileTask in the top level namespace"],
1680
1851
  ]
1681
-
1852
+
1682
1853
  # Initialize a Rake::Application object.
1683
1854
  def initialize
1684
1855
  super
@@ -1701,7 +1872,7 @@ module Rake
1701
1872
  # * Define the tasks (+load_rakefile+).
1702
1873
  # * Run the top level tasks (+run_tasks+).
1703
1874
  #
1704
- # If you wish to build a custom rake command, you should call +init+ on your
1875
+ # If you wish to build a custom rake command, you should call +init+ on your
1705
1876
  # application. The define any tasks. Finally, call +top_level+ to run your top
1706
1877
  # level tasks.
1707
1878
  def run
@@ -1726,7 +1897,7 @@ module Rake
1726
1897
  standard_exception_handling do
1727
1898
  raw_load_rakefile
1728
1899
  end
1729
- end
1900
+ end
1730
1901
 
1731
1902
  # Run the top level tasks of a Rake application.
1732
1903
  def top_level
@@ -1736,7 +1907,7 @@ module Rake
1736
1907
  elsif options.show_prereqs
1737
1908
  display_prerequisites
1738
1909
  else
1739
- top_level_tasks.each { |task_name| self[task_name].invoke }
1910
+ top_level_tasks.each { |task_name| invoke_task(task_name) }
1740
1911
  end
1741
1912
  end
1742
1913
  end
@@ -1747,7 +1918,7 @@ module Rake
1747
1918
  ext = ".#{ext}" unless ext =~ /^\./
1748
1919
  @loaders[ext] = loader
1749
1920
  end
1750
-
1921
+
1751
1922
  # Application options from the command line
1752
1923
  def options
1753
1924
  @options ||= OpenStruct.new
@@ -1755,10 +1926,30 @@ module Rake
1755
1926
 
1756
1927
  # private ----------------------------------------------------------------
1757
1928
 
1929
+ def invoke_task(task_string)
1930
+ name, args = parse_task_string(task_string)
1931
+ t = self[name]
1932
+ t.invoke(*args)
1933
+ end
1934
+
1935
+ def parse_task_string(string)
1936
+ if string =~ /^([^\[]+)(\[(.*)\])$/
1937
+ name = $1
1938
+ args = $3.split(/\s*,\s*/)
1939
+ else
1940
+ name = string
1941
+ args = []
1942
+ end
1943
+ [name, args]
1944
+ end
1945
+
1758
1946
  # Provide standard execption handling for the given block.
1759
1947
  def standard_exception_handling
1760
1948
  begin
1761
1949
  yield
1950
+ rescue SystemExit => ex
1951
+ # Exit silently with current status
1952
+ exit(ex.status)
1762
1953
  rescue SystemExit, GetoptLong::InvalidOption => ex
1763
1954
  # Exit silently
1764
1955
  exit(1)
@@ -1773,9 +1964,9 @@ module Rake
1773
1964
  $stderr.puts "(See full trace by running task with --trace)"
1774
1965
  end
1775
1966
  exit(1)
1776
- end
1967
+ end
1777
1968
  end
1778
-
1969
+
1779
1970
  # True if one of the files in RAKEFILES is in the current directory.
1780
1971
  # If a match is found, it is copied into @rakefile.
1781
1972
  def have_rakefile
@@ -1787,15 +1978,10 @@ module Rake
1787
1978
  end
1788
1979
  return false
1789
1980
  end
1790
-
1791
- # Display the program usage line.
1792
- def usage
1793
- puts "rake [-f rakefile] {options} targets..."
1794
- end
1795
-
1981
+
1796
1982
  # Display the rake command line help.
1797
1983
  def help
1798
- usage
1984
+ puts "rake [-f rakefile] {options} targets..."
1799
1985
  puts
1800
1986
  puts "Options are ..."
1801
1987
  puts
@@ -1809,18 +1995,38 @@ module Rake
1809
1995
  printf " %s\n", desc
1810
1996
  end
1811
1997
  end
1812
-
1998
+
1813
1999
  # Display the tasks and dependencies.
1814
2000
  def display_tasks_and_comments
1815
2001
  displayable_tasks = tasks.select { |t|
1816
2002
  t.comment && t.name =~ options.show_task_pattern
1817
2003
  }
1818
- width = displayable_tasks.collect { |t| t.name.length }.max
1819
- displayable_tasks.each do |t|
1820
- printf "#{name} %-#{width}s # %s\n", t.name, t.comment
2004
+ if options.full_description
2005
+ displayable_tasks.each do |t|
2006
+ puts "rake #{t.name_with_args}"
2007
+ t.full_comment.split("\n").each do |line|
2008
+ puts " #{line}"
2009
+ end
2010
+ puts
2011
+ end
2012
+ else
2013
+ width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
2014
+ max_column = 80 - name.size - width - 7
2015
+ displayable_tasks.each do |t|
2016
+ printf "#{name} %-#{width}s # %s\n",
2017
+ t.name_with_args, truncate(t.comment, max_column)
2018
+ end
1821
2019
  end
1822
2020
  end
1823
-
2021
+
2022
+ def truncate(string, width)
2023
+ if string.length <= width
2024
+ string
2025
+ else
2026
+ string[0, width-3] + "..."
2027
+ end
2028
+ end
2029
+
1824
2030
  # Display the tasks and prerequisites
1825
2031
  def display_prerequisites
1826
2032
  tasks.each do |t|
@@ -1828,16 +2034,20 @@ module Rake
1828
2034
  t.prerequisites.each { |pre| puts " #{pre}" }
1829
2035
  end
1830
2036
  end
1831
-
2037
+
1832
2038
  # Return a list of the command line options supported by the
1833
2039
  # program.
1834
2040
  def command_line_options
1835
2041
  OPTIONS.collect { |lst| lst[0..-2] }
1836
2042
  end
1837
-
2043
+
1838
2044
  # Do the option defined by +opt+ and +value+.
1839
2045
  def do_option(opt, value)
1840
2046
  case opt
2047
+ when '--describe'
2048
+ options.show_tasks = true
2049
+ options.show_task_pattern = Regexp.new(value || '.')
2050
+ options.full_description = true
1841
2051
  when '--dry-run'
1842
2052
  verbose(true)
1843
2053
  nowrite(true)
@@ -1875,12 +2085,10 @@ module Rake
1875
2085
  when '--tasks'
1876
2086
  options.show_tasks = true
1877
2087
  options.show_task_pattern = Regexp.new(value || '.')
2088
+ options.full_description = false
1878
2089
  when '--trace'
1879
2090
  options.trace = true
1880
2091
  verbose(true)
1881
- when '--usage'
1882
- usage
1883
- exit
1884
2092
  when '--verbose'
1885
2093
  verbose(true)
1886
2094
  when '--version'
@@ -1891,10 +2099,10 @@ module Rake
1891
2099
  options.classic_namespace = true
1892
2100
  end
1893
2101
  end
1894
-
2102
+
1895
2103
  # Read and handle the command line options.
1896
2104
  def handle_options
1897
- options.rakelib = 'rakelib'
2105
+ options.rakelib = ['rakelib']
1898
2106
 
1899
2107
  opts = GetoptLong.new(*command_line_options)
1900
2108
  opts.each { |opt, value| do_option(opt, value) }
@@ -1908,8 +2116,10 @@ module Rake
1908
2116
  $dryrun = options.dryrun
1909
2117
  $silent = options.silent
1910
2118
  end
2119
+ rescue NoMethodError => ex
2120
+ raise GetoptLong::InvalidOption, "While parsing options, error = #{ex.class}:#{ex.message}"
1911
2121
  end
1912
-
2122
+
1913
2123
  # Similar to the regular Ruby +require+ command, but will check
1914
2124
  # for .rake files in addition to .rb files.
1915
2125
  def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
@@ -1943,7 +2153,7 @@ module Rake
1943
2153
  end
1944
2154
  load_imports
1945
2155
  end
1946
-
2156
+
1947
2157
  # Collect the list of tasks on the command line. If no tasks are
1948
2158
  # given, return a list containing only the default task.
1949
2159
  # Environmental assignments are processed at this time as well.
@@ -1958,12 +2168,12 @@ module Rake
1958
2168
  end
1959
2169
  @top_level_tasks.push("default") if @top_level_tasks.size == 0
1960
2170
  end
1961
-
2171
+
1962
2172
  # Add a file to the list of files to be imported.
1963
2173
  def add_import(fn)
1964
2174
  @pending_imports << fn
1965
2175
  end
1966
-
2176
+
1967
2177
  # Load the pending list of imported files.
1968
2178
  def load_imports
1969
2179
  while fn = @pending_imports.shift
@@ -1977,7 +2187,7 @@ module Rake
1977
2187
  @imported << fn
1978
2188
  end
1979
2189
  end
1980
-
2190
+
1981
2191
  # Warn about deprecated use of top level constant names.
1982
2192
  def const_warning(const_name)
1983
2193
  @const_warning ||= false
@@ -2004,7 +2214,7 @@ end
2004
2214
  class Module
2005
2215
  # Rename the original handler to make it available.
2006
2216
  alias :rake_original_const_missing :const_missing
2007
-
2217
+
2008
2218
  # Check for deprecated uses of top level (i.e. in Object) uses of
2009
2219
  # Rake class names. If someone tries to reference the constant
2010
2220
  # name, display a warning and return the proper object. Using the