rake 0.7.3 → 0.8.7

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.
Files changed (66) hide show
  1. data/CHANGES +126 -1
  2. data/README +86 -132
  3. data/Rakefile +111 -64
  4. data/TODO +1 -0
  5. data/bin/rake +24 -0
  6. data/doc/command_line_usage.rdoc +102 -0
  7. data/doc/rakefile.rdoc +126 -3
  8. data/doc/release_notes/rake-0.7.3.rdoc +0 -0
  9. data/doc/release_notes/rake-0.8.0.rdoc +114 -0
  10. data/doc/release_notes/rake-0.8.2.rdoc +165 -0
  11. data/doc/release_notes/rake-0.8.3.rdoc +112 -0
  12. data/doc/release_notes/rake-0.8.4.rdoc +147 -0
  13. data/doc/release_notes/rake-0.8.5.rdoc +53 -0
  14. data/doc/release_notes/rake-0.8.6.rdoc +55 -0
  15. data/doc/release_notes/rake-0.8.7.rdoc +55 -0
  16. data/lib/rake/alt_system.rb +108 -0
  17. data/lib/rake/contrib/ftptools.rb +24 -10
  18. data/lib/rake/contrib/publisher.rb +1 -1
  19. data/lib/rake/contrib/sys.rb +5 -2
  20. data/lib/rake/gempackagetask.rb +2 -6
  21. data/lib/rake/loaders/makefile.rb +17 -15
  22. data/lib/rake/rdoctask.rb +83 -21
  23. data/lib/rake/ruby182_test_unit_fix.rb +0 -0
  24. data/lib/rake/tasklib.rb +8 -3
  25. data/lib/rake/testtask.rb +1 -1
  26. data/lib/rake/win32.rb +55 -0
  27. data/lib/rake.rb +861 -386
  28. data/test/check_expansion.rb +5 -0
  29. data/test/check_no_expansion.rb +5 -0
  30. data/test/data/file_creation_task/Rakefile +4 -1
  31. data/test/data/multidesc/Rakefile +3 -0
  32. data/test/data/sample.mf +6 -1
  33. data/test/data/statusreturn/Rakefile +8 -0
  34. data/test/filecreation.rb +0 -2
  35. data/test/functional.rb +3 -1
  36. data/test/in_environment.rb +30 -0
  37. data/test/rake_test_setup.rb +24 -0
  38. data/test/session_functional.rb +145 -24
  39. data/test/shellcommand.rb +0 -0
  40. data/test/test_application.rb +345 -95
  41. data/test/test_definitions.rb +4 -1
  42. data/test/test_earlytime.rb +2 -2
  43. data/test/test_extension.rb +63 -0
  44. data/test/test_file_task.rb +20 -16
  45. data/test/test_filelist.rb +59 -10
  46. data/test/test_fileutils.rb +59 -38
  47. data/test/test_ftp.rb +5 -1
  48. data/test/test_invocation_chain.rb +81 -0
  49. data/test/test_makefile_loader.rb +5 -2
  50. data/test/test_namespace.rb +37 -14
  51. data/test/test_package_task.rb +3 -15
  52. data/test/test_pathmap.rb +24 -2
  53. data/test/test_pseudo_status.rb +26 -0
  54. data/test/test_rake.rb +9 -2
  55. data/test/test_rdoc_task.rb +88 -0
  56. data/test/test_require.rb +3 -1
  57. data/test/test_rules.rb +56 -12
  58. data/test/test_task_arguments.rb +89 -0
  59. data/test/test_task_manager.rb +27 -2
  60. data/test/test_tasklib.rb +12 -0
  61. data/test/test_tasks.rb +248 -20
  62. data/test/test_test_task.rb +3 -2
  63. data/test/test_top_level_functions.rb +10 -3
  64. data/test/test_win32.rb +72 -0
  65. metadata +105 -69
  66. /data/test/contrib/{testsys.rb → test_sys.rb} +0 -0
data/lib/rake.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  #--
4
4
 
5
- # Copyright (c) 2003, 2004, 2005, 2006 Jim Weirich
5
+ # Copyright 2003, 2004, 2005, 2006, 2007, 2008 by Jim Weirich (jim@weirichhouse.org)
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,26 +24,28 @@
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.7'
33
33
 
34
34
  require 'rbconfig'
35
- require 'ftools'
36
- require 'getoptlong'
37
35
  require 'fileutils'
38
36
  require 'singleton'
39
- require 'thread'
37
+ require 'monitor'
38
+ require 'optparse'
40
39
  require 'ostruct'
41
40
 
41
+ require 'rake/win32'
42
+
43
+ $trace = false
44
+
42
45
  ######################################################################
43
46
  # Rake extensions to Module.
44
47
  #
45
48
  class Module
46
-
47
49
  # Check for an existing method in the current class before extending. IF
48
50
  # the method already exists, then a warning is printed and the extension is
49
51
  # not added. Otherwise the block is yielded and any definitions in the
@@ -60,13 +62,13 @@ class Module
60
62
  # end
61
63
  #
62
64
  def rake_extension(method)
63
- if instance_methods.include?(method)
65
+ if method_defined?(method)
64
66
  $stderr.puts "WARNING: Possible conflict with Rake extension: #{self}##{method} already exists"
65
67
  else
66
68
  yield
67
69
  end
68
70
  end
69
- end
71
+ end # module Module
70
72
 
71
73
 
72
74
  ######################################################################
@@ -74,7 +76,7 @@ end
74
76
  #
75
77
  class String
76
78
  rake_extension("ext") do
77
- # Replace the file extension with +newext+. If there is no extenson on
79
+ # Replace the file extension with +newext+. If there is no extension on
78
80
  # the string, append the new extension to the end. If the new extension
79
81
  # is not given, or is the empty string, remove any existing extension.
80
82
  #
@@ -84,7 +86,7 @@ class String
84
86
  if newext != ''
85
87
  newext = (newext =~ /^\./) ? newext : ("." + newext)
86
88
  end
87
- dup.sub!(%r(([^/\\])\.[^./\\]*$)) { $1 + newext } || self + newext
89
+ self.chomp(File.extname(self)) << newext
88
90
  end
89
91
  end
90
92
 
@@ -103,23 +105,19 @@ class String
103
105
  # front end (left hand side) if +n+ is positive. Include |+n+|
104
106
  # directories from the back end (right hand side) if +n+ is negative.
105
107
  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
108
+ dirs = File.dirname(self).pathmap_explode
109
+ partial_dirs =
110
+ if n > 0
111
+ dirs[0...n]
112
+ elsif n < 0
113
+ dirs.reverse[0...-n].reverse
114
114
  else
115
- File.join(partial)
115
+ "."
116
116
  end
117
- else
118
- "."
119
- end
117
+ File.join(partial_dirs)
120
118
  end
121
119
  protected :pathmap_partial
122
-
120
+
123
121
  # Preform the pathmap replacement operations on the given path. The
124
122
  # patterns take the form 'pat1,rep1;pat2,rep2...'.
125
123
  def pathmap_replace(patterns, &block)
@@ -143,7 +141,7 @@ class String
143
141
  # controls the details of the mapping. The following special patterns are
144
142
  # recognized:
145
143
  #
146
- # * <b>%p</b> -- The complete path.
144
+ # * <b>%p</b> -- The complete path.
147
145
  # * <b>%f</b> -- The base file name of the path, with its file extension,
148
146
  # but without any directories.
149
147
  # * <b>%n</b> -- The file name of the path without its file extension.
@@ -165,7 +163,7 @@ class String
165
163
  # 'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b'
166
164
  # 'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d'
167
165
  #
168
- # Also the %d, %p, $f, $n, %x, and %X operators can take a
166
+ # Also the %d, %p, %f, %n, %x, and %X operators can take a
169
167
  # pattern/replacement argument to perform simple string substititions on a
170
168
  # particular part of the path. The pattern and replacement are speparated
171
169
  # by a comma and are enclosed by curly braces. The replacement spec comes
@@ -178,10 +176,10 @@ class String
178
176
  # excluded from both the pattern and replacement text (let's keep parsing
179
177
  # reasonable).
180
178
  #
181
- # For example:
179
+ # For example:
182
180
  #
183
181
  # "src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")
184
- #
182
+ #
185
183
  # returns:
186
184
  #
187
185
  # "bin/org/onestepback/proj/A.class"
@@ -211,13 +209,9 @@ class String
211
209
  when '%d'
212
210
  result << File.dirname(self)
213
211
  when '%x'
214
- result << $1 if self =~ /[^\/](\.[^.]+)$/
212
+ result << File.extname(self)
215
213
  when '%X'
216
- if self =~ /^(.+[^\/])(\.[^.]+)$/
217
- result << $1
218
- else
219
- result << self
220
- end
214
+ result << self.ext
221
215
  when '%p'
222
216
  result << self
223
217
  when '%s'
@@ -240,11 +234,33 @@ class String
240
234
  result
241
235
  end
242
236
  end
243
- end
237
+ end # class String
244
238
 
245
239
  ##############################################################################
246
240
  module Rake
247
241
 
242
+ # Errors -----------------------------------------------------------
243
+
244
+ # Error indicating an ill-formed task declaration.
245
+ class TaskArgumentError < ArgumentError
246
+ end
247
+
248
+ # Error indicating a recursion overflow error in task selection.
249
+ class RuleRecursionOverflowError < StandardError
250
+ def initialize(*args)
251
+ super
252
+ @targets = []
253
+ end
254
+
255
+ def add_target(target)
256
+ @targets << target
257
+ end
258
+
259
+ def message
260
+ super + ": [" + @targets.reverse.join(' => ') + "]"
261
+ end
262
+ end
263
+
248
264
  # --------------------------------------------------------------------------
249
265
  # Rake module singleton methods.
250
266
  #
@@ -266,28 +282,182 @@ module Rake
266
282
 
267
283
  end
268
284
 
269
- # ##########################################################################
285
+ ####################################################################
270
286
  # Mixin for creating easily cloned objects.
271
287
  #
272
288
  module Cloneable
273
289
  # Clone an object by making a new object and setting all the instance
274
290
  # variables to the same values.
275
- def clone
291
+ def dup
276
292
  sibling = self.class.new
277
293
  instance_variables.each do |ivar|
278
294
  value = self.instance_variable_get(ivar)
279
295
  new_value = value.clone rescue value
280
296
  sibling.instance_variable_set(ivar, new_value)
281
297
  end
298
+ sibling.taint if tainted?
299
+ sibling
300
+ end
301
+
302
+ def clone
303
+ sibling = dup
304
+ sibling.freeze if frozen?
282
305
  sibling
283
306
  end
284
- alias dup clone
285
307
  end
286
- end
308
+
309
+ ####################################################################
310
+ # Exit status class for times the system just gives us a nil.
311
+ class PseudoStatus
312
+ attr_reader :exitstatus
313
+ def initialize(code=0)
314
+ @exitstatus = code
315
+ end
316
+ def to_i
317
+ @exitstatus << 8
318
+ end
319
+ def >>(n)
320
+ to_i >> n
321
+ end
322
+ def stopped?
323
+ false
324
+ end
325
+ def exited?
326
+ true
327
+ end
328
+ end
329
+
330
+ ####################################################################
331
+ # TaskAguments manage the arguments passed to a task.
332
+ #
333
+ class TaskArguments
334
+ include Enumerable
335
+
336
+ attr_reader :names
337
+
338
+ # Create a TaskArgument object with a list of named arguments
339
+ # (given by :names) and a set of associated values (given by
340
+ # :values). :parent is the parent argument object.
341
+ def initialize(names, values, parent=nil)
342
+ @names = names
343
+ @parent = parent
344
+ @hash = {}
345
+ names.each_with_index { |name, i|
346
+ @hash[name.to_sym] = values[i] unless values[i].nil?
347
+ }
348
+ end
349
+
350
+ # Create a new argument scope using the prerequisite argument
351
+ # names.
352
+ def new_scope(names)
353
+ values = names.collect { |n| self[n] }
354
+ self.class.new(names, values, self)
355
+ end
356
+
357
+ # Find an argument value by name or index.
358
+ def [](index)
359
+ lookup(index.to_sym)
360
+ end
361
+
362
+ # Specify a hash of default values for task arguments. Use the
363
+ # defaults only if there is no specific value for the given
364
+ # argument.
365
+ def with_defaults(defaults)
366
+ @hash = defaults.merge(@hash)
367
+ end
368
+
369
+ def each(&block)
370
+ @hash.each(&block)
371
+ end
372
+
373
+ def method_missing(sym, *args, &block)
374
+ lookup(sym.to_sym)
375
+ end
376
+
377
+ def to_hash
378
+ @hash
379
+ end
380
+
381
+ def to_s
382
+ @hash.inspect
383
+ end
384
+
385
+ def inspect
386
+ to_s
387
+ end
388
+
389
+ protected
390
+
391
+ def lookup(name)
392
+ if @hash.has_key?(name)
393
+ @hash[name]
394
+ elsif ENV.has_key?(name.to_s)
395
+ ENV[name.to_s]
396
+ elsif ENV.has_key?(name.to_s.upcase)
397
+ ENV[name.to_s.upcase]
398
+ elsif @parent
399
+ @parent.lookup(name)
400
+ end
401
+ end
402
+ end
403
+
404
+ EMPTY_TASK_ARGS = TaskArguments.new([], [])
405
+
406
+ ####################################################################
407
+ # InvocationChain tracks the chain of task invocations to detect
408
+ # circular dependencies.
409
+ class InvocationChain
410
+ def initialize(value, tail)
411
+ @value = value
412
+ @tail = tail
413
+ end
414
+
415
+ def member?(obj)
416
+ @value == obj || @tail.member?(obj)
417
+ end
418
+
419
+ def append(value)
420
+ if member?(value)
421
+ fail RuntimeError, "Circular dependency detected: #{to_s} => #{value}"
422
+ end
423
+ self.class.new(value, self)
424
+ end
425
+
426
+ def to_s
427
+ "#{prefix}#{@value}"
428
+ end
429
+
430
+ def self.append(value, chain)
431
+ chain.append(value)
432
+ end
433
+
434
+ private
435
+
436
+ def prefix
437
+ "#{@tail.to_s} => "
438
+ end
439
+
440
+ class EmptyInvocationChain
441
+ def member?(obj)
442
+ false
443
+ end
444
+ def append(value)
445
+ InvocationChain.new(value, self)
446
+ end
447
+ def to_s
448
+ "TOP"
449
+ end
450
+ end
451
+
452
+ EMPTY = EmptyInvocationChain.new
453
+
454
+ end # class InvocationChain
455
+
456
+ end # module Rake
287
457
 
288
458
  module Rake
289
459
 
290
- # #########################################################################
460
+ ###########################################################################
291
461
  # A Task is the basic unit of work in a Rakefile. Tasks have associated
292
462
  # actions (possibly more than one) and a list of prerequisites. When
293
463
  # invoked, a task will first ensure that all of its prerequisites have an
@@ -300,12 +470,19 @@ module Rake
300
470
  # List of prerequisites for a task.
301
471
  attr_reader :prerequisites
302
472
 
473
+ # List of actions attached to a task.
474
+ attr_reader :actions
475
+
303
476
  # Application owning this task.
304
477
  attr_accessor :application
305
-
306
- # Comment for this task.
307
- attr_accessor :comment
308
-
478
+
479
+ # Comment for this task. Restricted to a single line of no more than 50
480
+ # characters.
481
+ attr_reader :comment
482
+
483
+ # Full text of the (possibly multi-line) comment.
484
+ attr_reader :full_comment
485
+
309
486
  # Array of nested namespaces names used for task lookup by this task.
310
487
  attr_reader :scope
311
488
 
@@ -313,7 +490,11 @@ module Rake
313
490
  def to_s
314
491
  name
315
492
  end
316
-
493
+
494
+ def inspect
495
+ "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
496
+ end
497
+
317
498
  # List of sources for task.
318
499
  attr_writer :sources
319
500
  def sources
@@ -324,49 +505,106 @@ module Rake
324
505
  def source
325
506
  @sources.first if defined?(@sources)
326
507
  end
327
-
508
+
328
509
  # Create a task named +task_name+ with no actions or prerequisites. Use
329
510
  # +enhance+ to add actions and prerequisites.
330
511
  def initialize(task_name, app)
331
512
  @name = task_name.to_s
332
- @prerequisites = FileList[]
513
+ @prerequisites = []
333
514
  @actions = []
334
515
  @already_invoked = false
516
+ @full_comment = nil
335
517
  @comment = nil
336
- @lock = Mutex.new
518
+ @lock = Monitor.new
337
519
  @application = app
338
520
  @scope = app.current_scope
521
+ @arg_names = nil
339
522
  end
340
-
523
+
341
524
  # Enhance a task with prerequisites or actions. Returns self.
342
525
  def enhance(deps=nil, &block)
343
526
  @prerequisites |= deps if deps
344
527
  @actions << block if block_given?
345
528
  self
346
529
  end
347
-
530
+
348
531
  # Name of the task, including any namespace qualifiers.
349
532
  def name
350
533
  @name.to_s
351
534
  end
352
-
535
+
536
+ # Name of task with argument list description.
537
+ def name_with_args # :nodoc:
538
+ if arg_description
539
+ "#{name}#{arg_description}"
540
+ else
541
+ name
542
+ end
543
+ end
544
+
545
+ # Argument description (nil if none).
546
+ def arg_description # :nodoc:
547
+ @arg_names ? "[#{(arg_names || []).join(',')}]" : nil
548
+ end
549
+
550
+ # Name of arguments for this task.
551
+ def arg_names
552
+ @arg_names || []
553
+ end
554
+
555
+ # Reenable the task, allowing its tasks to be executed if the task
556
+ # is invoked again.
557
+ def reenable
558
+ @already_invoked = false
559
+ end
560
+
561
+ # Clear the existing prerequisites and actions of a rake task.
562
+ def clear
563
+ clear_prerequisites
564
+ clear_actions
565
+ self
566
+ end
567
+
568
+ # Clear the existing prerequisites of a rake task.
569
+ def clear_prerequisites
570
+ prerequisites.clear
571
+ self
572
+ end
573
+
574
+ # Clear the existing actions on a rake task.
575
+ def clear_actions
576
+ actions.clear
577
+ self
578
+ end
579
+
353
580
  # Invoke the task if it is needed. Prerequites are invoked first.
354
- def invoke
581
+ def invoke(*args)
582
+ task_args = TaskArguments.new(arg_names, args)
583
+ invoke_with_call_chain(task_args, InvocationChain::EMPTY)
584
+ end
585
+
586
+ # Same as invoke, but explicitly pass a call chain to detect
587
+ # circular dependencies.
588
+ def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
589
+ new_chain = InvocationChain.append(self, invocation_chain)
355
590
  @lock.synchronize do
356
591
  if application.options.trace
357
592
  puts "** Invoke #{name} #{format_trace_flags}"
358
593
  end
359
594
  return if @already_invoked
360
595
  @already_invoked = true
361
- invoke_prerequisites
362
- execute if needed?
596
+ invoke_prerequisites(task_args, new_chain)
597
+ execute(task_args) if needed?
363
598
  end
364
599
  end
600
+ protected :invoke_with_call_chain
365
601
 
366
602
  # Invoke all the prerequisites of a task.
367
- def invoke_prerequisites
603
+ def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
368
604
  @prerequisites.each { |n|
369
- application[n, @scope].invoke
605
+ prereq = application[n, @scope]
606
+ prereq_args = task_args.new_scope(prereq.arg_names)
607
+ prereq.invoke_with_call_chain(prereq_args, invocation_chain)
370
608
  }
371
609
  end
372
610
 
@@ -378,9 +616,10 @@ module Rake
378
616
  flags.empty? ? "" : "(" + flags.join(", ") + ")"
379
617
  end
380
618
  private :format_trace_flags
381
-
619
+
382
620
  # Execute the actions associated with this task.
383
- def execute
621
+ def execute(args=nil)
622
+ args ||= EMPTY_TASK_ARGS
384
623
  if application.options.dryrun
385
624
  puts "** Execute (dry run) #{name}"
386
625
  return
@@ -389,37 +628,68 @@ module Rake
389
628
  puts "** Execute #{name}"
390
629
  end
391
630
  application.enhance_with_matching_rule(name) if @actions.empty?
392
- @actions.each { |act| result = act.call(self) }
631
+ @actions.each do |act|
632
+ case act.arity
633
+ when 1
634
+ act.call(self)
635
+ else
636
+ act.call(self, args)
637
+ end
638
+ end
393
639
  end
394
-
640
+
395
641
  # Is this task needed?
396
642
  def needed?
397
643
  true
398
644
  end
399
-
645
+
400
646
  # Timestamp for this task. Basic tasks return the current time for their
401
647
  # time stamp. Other tasks can be more sophisticated.
402
648
  def timestamp
403
649
  @prerequisites.collect { |p| application[p].timestamp }.max || Time.now
404
650
  end
405
-
651
+
652
+ # Add a description to the task. The description can consist of an option
653
+ # argument list (enclosed brackets) and an optional comment.
654
+ def add_description(description)
655
+ return if ! description
656
+ comment = description.strip
657
+ add_comment(comment) if comment && ! comment.empty?
658
+ end
659
+
660
+ # Writing to the comment attribute is the same as adding a description.
661
+ def comment=(description)
662
+ add_description(description)
663
+ end
664
+
406
665
  # Add a comment to the task. If a comment alread exists, separate
407
666
  # the new comment with " / ".
408
667
  def add_comment(comment)
409
- return if ! comment
410
- if @comment
411
- @comment << " / "
668
+ if @full_comment
669
+ @full_comment << " / "
670
+ else
671
+ @full_comment = ''
672
+ end
673
+ @full_comment << comment
674
+ if @full_comment =~ /\A([^.]+?\.)( |$)/
675
+ @comment = $1
412
676
  else
413
- @comment = ''
677
+ @comment = @full_comment
414
678
  end
415
- @comment << comment
416
679
  end
417
-
680
+ private :add_comment
681
+
682
+ # Set the names of the arguments for this task. +args+ should be
683
+ # an array of symbols, one for each argument name.
684
+ def set_arg_names(args)
685
+ @arg_names = args.map { |a| a.to_sym }
686
+ end
687
+
418
688
  # Return a string describing the internal state of a task. Useful for
419
689
  # debugging.
420
690
  def investigation
421
691
  result = "------------------------------\n"
422
- result << "Investigating #{name}\n"
692
+ result << "Investigating #{name}\n"
423
693
  result << "class: #{self.class}\n"
424
694
  result << "task needed: #{needed?}\n"
425
695
  result << "timestamp: #{timestamp}\n"
@@ -434,23 +704,23 @@ module Rake
434
704
  result << "................................\n\n"
435
705
  return result
436
706
  end
437
-
707
+
438
708
  # ----------------------------------------------------------------
439
709
  # Rake Module Methods
440
- #
710
+ #
441
711
  class << self
442
-
712
+
443
713
  # Clear the task list. This cause rake to immediately forget all the
444
714
  # tasks that have been assigned. (Normally used in the unit tests.)
445
715
  def clear
446
716
  Rake.application.clear
447
717
  end
448
-
718
+
449
719
  # List of all defined tasks.
450
720
  def tasks
451
721
  Rake.application.tasks
452
722
  end
453
-
723
+
454
724
  # Return a task with the given name. If the task is not currently
455
725
  # known, try to synthesize one from the defined rules. If no rules are
456
726
  # found, but an existing file matches the task name, assume it is a file
@@ -458,22 +728,22 @@ module Rake
458
728
  def [](task_name)
459
729
  Rake.application[task_name]
460
730
  end
461
-
731
+
462
732
  # TRUE if the task name is already defined.
463
733
  def task_defined?(task_name)
464
734
  Rake.application.lookup(task_name) != nil
465
735
  end
466
-
736
+
467
737
  # Define a task given +args+ and an option block. If a rule with the
468
738
  # given name already exists, the prerequisites and actions are added to
469
739
  # the existing task. Returns the defined task.
470
- def define_task(args, &block)
471
- Rake.application.define_task(self, args, &block)
740
+ def define_task(*args, &block)
741
+ Rake.application.define_task(self, *args, &block)
472
742
  end
473
-
474
- # Define a rule for synthesizing tasks.
475
- def create_rule(args, &block)
476
- Rake.application.create_rule(args, &block)
743
+
744
+ # Define a rule for synthesizing tasks.
745
+ def create_rule(*args, &block)
746
+ Rake.application.create_rule(*args, &block)
477
747
  end
478
748
 
479
749
  # Apply the scope to the task name according to the rules for
@@ -483,26 +753,24 @@ module Rake
483
753
  (scope + [task_name]).join(':')
484
754
  end
485
755
 
486
- end
487
- end
488
-
489
-
490
- # #########################################################################
756
+ end # class << Rake::Task
757
+ end # class Rake::Task
758
+
759
+
760
+ ###########################################################################
491
761
  # A FileTask is a task that includes time based dependencies. If any of a
492
762
  # FileTask's prerequisites have a timestamp that is later than the file
493
763
  # represented by this task, then the file must be rebuilt (using the
494
764
  # supplied actions).
495
765
  #
496
766
  class FileTask < Task
497
-
767
+
498
768
  # Is this file task needed? Yes if it doesn't exist, or if its time stamp
499
769
  # is out of date.
500
770
  def needed?
501
- return true unless File.exist?(name)
502
- return true if out_of_date?(timestamp)
503
- false
771
+ ! File.exist?(name) || out_of_date?(timestamp)
504
772
  end
505
-
773
+
506
774
  # Time stamp for file task.
507
775
  def timestamp
508
776
  if File.exist?(name)
@@ -529,9 +797,9 @@ module Rake
529
797
  task_name
530
798
  end
531
799
  end
532
- end
533
-
534
- # #########################################################################
800
+ end # class Rake::FileTask
801
+
802
+ ###########################################################################
535
803
  # A FileCreationTask is a file task that when used as a dependency will be
536
804
  # needed if and only if the file has not been created. Once created, it is
537
805
  # not re-triggered if any of its dependencies are newer, nor does trigger
@@ -542,7 +810,7 @@ module Rake
542
810
  def needed?
543
811
  ! File.exist?(name)
544
812
  end
545
-
813
+
546
814
  # Time stamp for file creation task. This time stamp is earlier
547
815
  # than any other time stamp.
548
816
  def timestamp
@@ -550,21 +818,22 @@ module Rake
550
818
  end
551
819
  end
552
820
 
553
- # #########################################################################
821
+ ###########################################################################
554
822
  # Same as a regular task, but the immediate prerequisites are done in
555
823
  # parallel using Ruby threads.
556
824
  #
557
825
  class MultiTask < Task
558
- def invoke_prerequisites
826
+ private
827
+ def invoke_prerequisites(args, invocation_chain)
559
828
  threads = @prerequisites.collect { |p|
560
- Thread.new(p) { |r| application[r].invoke }
829
+ Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
561
830
  }
562
831
  threads.each { |t| t.join }
563
832
  end
564
833
  end
565
- end
834
+ end # module Rake
566
835
 
567
- # ###########################################################################
836
+ ## ###########################################################################
568
837
  # Task Definition Functions ...
569
838
 
570
839
  # Declare a basic task.
@@ -574,8 +843,8 @@ end
574
843
  # rm_rf "html"
575
844
  # end
576
845
  #
577
- def task(args, &block)
578
- Rake::Task.define_task(args, &block)
846
+ def task(*args, &block)
847
+ Rake::Task.define_task(*args, &block)
579
848
  end
580
849
 
581
850
 
@@ -592,8 +861,8 @@ end
592
861
  # end
593
862
  # end
594
863
  #
595
- def file(args, &block)
596
- Rake::FileTask.define_task(args, &block)
864
+ def file(*args, &block)
865
+ Rake::FileTask.define_task(*args, &block)
597
866
  end
598
867
 
599
868
  # Declare a file creation task.
@@ -648,8 +917,8 @@ end
648
917
  # sh %{cc -o #{t.name} #{t.source}}
649
918
  # end
650
919
  #
651
- def rule(args, &block)
652
- Rake::Task.create_rule(args, &block)
920
+ def rule(*args, &block)
921
+ Rake::Task.create_rule(*args, &block)
653
922
  end
654
923
 
655
924
  # Describe the next rake task.
@@ -660,8 +929,8 @@ end
660
929
  # runtests
661
930
  # end
662
931
  #
663
- def desc(comment)
664
- Rake.application.last_comment = comment
932
+ def desc(description)
933
+ Rake.application.last_description = description
665
934
  end
666
935
 
667
936
  # Import the partial Rakefiles +fn+. Imported files are loaded _after_ the
@@ -683,12 +952,19 @@ def import(*fns)
683
952
  end
684
953
  end
685
954
 
686
- # ###########################################################################
955
+ #############################################################################
687
956
  # This a FileUtils extension that defines several additional commands to be
688
957
  # added to the FileUtils utility functions.
689
958
  #
690
959
  module FileUtils
691
- RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
960
+ RUBY_EXT = ((Config::CONFIG['ruby_install_name'] =~ /\.(com|cmd|exe|bat|rb|sh)$/) ?
961
+ "" :
962
+ Config::CONFIG['EXEEXT'])
963
+
964
+ RUBY = File.join(
965
+ Config::CONFIG['bindir'],
966
+ Config::CONFIG['ruby_install_name'] + RUBY_EXT).
967
+ sub(/.*\s.*/m, '"\&"')
692
968
 
693
969
  OPT_TABLE['sh'] = %w(noop verbose)
694
970
  OPT_TABLE['ruby'] = %w(noop verbose)
@@ -713,20 +989,33 @@ module FileUtils
713
989
  options = (Hash === cmd.last) ? cmd.pop : {}
714
990
  unless block_given?
715
991
  show_command = cmd.join(" ")
716
- show_command = show_command[0,42] + "..."
717
- # TODO code application logic heref show_command.length > 45
992
+ show_command = show_command[0,42] + "..." unless $trace
993
+ # TODO code application logic heref show_command.length > 45
718
994
  block = lambda { |ok, status|
719
995
  ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
720
996
  }
721
997
  end
998
+ if RakeFileUtils.verbose_flag == :default
999
+ options[:verbose] = true
1000
+ else
1001
+ options[:verbose] ||= RakeFileUtils.verbose_flag
1002
+ end
1003
+ options[:noop] ||= RakeFileUtils.nowrite_flag
722
1004
  rake_check_options options, :noop, :verbose
723
1005
  rake_output_message cmd.join(" ") if options[:verbose]
724
1006
  unless options[:noop]
725
- res = system(*cmd)
726
- block.call(res, $?)
1007
+ res = rake_system(*cmd)
1008
+ status = $?
1009
+ status = PseudoStatus.new(1) if !res && status.nil?
1010
+ block.call(res, status)
727
1011
  end
728
1012
  end
729
1013
 
1014
+ def rake_system(*cmd)
1015
+ Rake::AltSystem.system(*cmd)
1016
+ end
1017
+ private :rake_system
1018
+
730
1019
  # Run a Ruby interpreter with the given arguments.
731
1020
  #
732
1021
  # Example:
@@ -737,10 +1026,10 @@ module FileUtils
737
1026
  if args.length > 1 then
738
1027
  sh(*([RUBY] + args + [options]), &block)
739
1028
  else
740
- sh("#{RUBY} #{args}", options, &block)
1029
+ sh("#{RUBY} #{args.first}", options, &block)
741
1030
  end
742
1031
  end
743
-
1032
+
744
1033
  LN_SUPPORTED = [true]
745
1034
 
746
1035
  # Attempt to do a normal file link, but fall back to a copy if the link
@@ -771,7 +1060,7 @@ module FileUtils
771
1060
  end
772
1061
  end
773
1062
 
774
- # ###########################################################################
1063
+ #############################################################################
775
1064
  # RakeFileUtils provides a custom version of the FileUtils methods that
776
1065
  # respond to the <tt>verbose</tt> and <tt>nowrite</tt> commands.
777
1066
  #
@@ -781,18 +1070,18 @@ module RakeFileUtils
781
1070
  class << self
782
1071
  attr_accessor :verbose_flag, :nowrite_flag
783
1072
  end
784
- RakeFileUtils.verbose_flag = true
1073
+ RakeFileUtils.verbose_flag = :default
785
1074
  RakeFileUtils.nowrite_flag = false
786
-
1075
+
787
1076
  $fileutils_verbose = true
788
1077
  $fileutils_nowrite = false
789
-
1078
+
790
1079
  FileUtils::OPT_TABLE.each do |name, opts|
791
1080
  default_options = []
792
- if opts.include?('verbose')
1081
+ if opts.include?(:verbose) || opts.include?("verbose")
793
1082
  default_options << ':verbose => RakeFileUtils.verbose_flag'
794
1083
  end
795
- if opts.include?('noop')
1084
+ if opts.include?(:noop) || opts.include?("noop")
796
1085
  default_options << ':noop => RakeFileUtils.nowrite_flag'
797
1086
  end
798
1087
 
@@ -807,7 +1096,7 @@ module RakeFileUtils
807
1096
  EOS
808
1097
  end
809
1098
 
810
- # Get/set the verbose flag controlling output from the FileUtils utilities.
1099
+ # Get/set the verbose flag controlling output from the FileUtils utilities.
811
1100
  # If verbose is true, then the utility method is echoed to standard output.
812
1101
  #
813
1102
  # Examples:
@@ -828,7 +1117,7 @@ module RakeFileUtils
828
1117
  RakeFileUtils.verbose_flag
829
1118
  end
830
1119
 
831
- # Get/set the nowrite flag controlling output from the FileUtils utilities.
1120
+ # Get/set the nowrite flag controlling output from the FileUtils utilities.
832
1121
  # If verbose is true, then the utility method is echoed to standard output.
833
1122
  #
834
1123
  # Examples:
@@ -852,7 +1141,7 @@ module RakeFileUtils
852
1141
  # Use this function to prevent protentially destructive ruby code from
853
1142
  # running when the :nowrite flag is set.
854
1143
  #
855
- # Example:
1144
+ # Example:
856
1145
  #
857
1146
  # when_writing("Building Project") do
858
1147
  # project.build
@@ -902,7 +1191,7 @@ module RakeFileUtils
902
1191
  extend self
903
1192
  end
904
1193
 
905
- # ###########################################################################
1194
+ #############################################################################
906
1195
  # Include the FileUtils file manipulation functions in the top level module,
907
1196
  # but mark them private so that they don't unintentionally define methods on
908
1197
  # other objects.
@@ -914,22 +1203,7 @@ private(*RakeFileUtils.instance_methods(false))
914
1203
  ######################################################################
915
1204
  module Rake
916
1205
 
917
- class RuleRecursionOverflowError < StandardError
918
- def initialize(*args)
919
- super
920
- @targets = []
921
- end
922
-
923
- def add_target(target)
924
- @targets << target
925
- end
926
-
927
- def message
928
- super + ": [" + @targets.reverse.join(' => ') + "]"
929
- end
930
- end
931
-
932
- # #########################################################################
1206
+ ###########################################################################
933
1207
  # A FileList is essentially an array with a few helper methods defined to
934
1208
  # make file manipulation a bit easier.
935
1209
  #
@@ -943,7 +1217,7 @@ module Rake
943
1217
  # FileList/Array is requested, the pending patterns are resolved into a real
944
1218
  # list of file names.
945
1219
  #
946
- class FileList
1220
+ class FileList
947
1221
 
948
1222
  include Cloneable
949
1223
 
@@ -965,7 +1239,7 @@ module Rake
965
1239
 
966
1240
  # List of array methods (that are not in +Object+) that need to be
967
1241
  # delegated.
968
- ARRAY_METHODS = Array.instance_methods - Object.instance_methods
1242
+ ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
969
1243
 
970
1244
  # List of additional methods that must be delegated.
971
1245
  MUST_DEFINE = %w[to_a inspect]
@@ -981,16 +1255,16 @@ module Rake
981
1255
  compact flatten uniq values_at
982
1256
  + - & |
983
1257
  ]
984
-
1258
+
985
1259
  DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
986
-
1260
+
987
1261
  # Now do the delegation.
988
1262
  DELEGATING_METHODS.each_with_index do |sym, i|
989
1263
  if SPECIAL_RETURN.include?(sym)
990
1264
  ln = __LINE__+1
991
1265
  class_eval %{
992
1266
  def #{sym}(*args, &block)
993
- resolve if @pending
1267
+ resolve
994
1268
  result = @items.send(:#{sym}, *args, &block)
995
1269
  FileList.new.import(result)
996
1270
  end
@@ -999,7 +1273,7 @@ module Rake
999
1273
  ln = __LINE__+1
1000
1274
  class_eval %{
1001
1275
  def #{sym}(*args, &block)
1002
- resolve if @pending
1276
+ resolve
1003
1277
  result = @items.send(:#{sym}, *args, &block)
1004
1278
  result.object_id == @items.object_id ? self : result
1005
1279
  end
@@ -1048,8 +1322,8 @@ module Rake
1048
1322
  @pending = true
1049
1323
  self
1050
1324
  end
1051
- alias :add :include
1052
-
1325
+ alias :add :include
1326
+
1053
1327
  # Register a list of file name patterns that should be excluded from the
1054
1328
  # list. Patterns may be regular expressions, glob patterns or regular
1055
1329
  # strings. In addition, a block given to exclude will remove entries that
@@ -1072,16 +1346,16 @@ module Rake
1072
1346
  #
1073
1347
  def exclude(*patterns, &block)
1074
1348
  patterns.each do |pat|
1075
- @exclude_patterns << pat
1349
+ @exclude_patterns << pat
1076
1350
  end
1077
1351
  if block_given?
1078
1352
  @exclude_procs << block
1079
- end
1353
+ end
1080
1354
  resolve_exclude if ! @pending
1081
1355
  self
1082
1356
  end
1083
1357
 
1084
-
1358
+
1085
1359
  # Clear all the exclude patterns so that we exclude nothing.
1086
1360
  def clear_exclude
1087
1361
  @exclude_patterns = []
@@ -1105,7 +1379,7 @@ module Rake
1105
1379
  def to_ary
1106
1380
  to_a
1107
1381
  end
1108
-
1382
+
1109
1383
  # Lie about our class.
1110
1384
  def is_a?(klass)
1111
1385
  klass == Array || super(klass)
@@ -1211,8 +1485,8 @@ module Rake
1211
1485
  collect { |fn| fn.pathmap(spec) }
1212
1486
  end
1213
1487
 
1214
- # Return a new array with <tt>String#ext</tt> method applied to each
1215
- # member of the array.
1488
+ # Return a new FileList with <tt>String#ext</tt> method applied
1489
+ # to each member of the array.
1216
1490
  #
1217
1491
  # This method is a shortcut for:
1218
1492
  #
@@ -1229,9 +1503,9 @@ module Rake
1229
1503
  # name, line number, and the matching line of text. If no block is given,
1230
1504
  # a standard emac style file:linenumber:line message will be printed to
1231
1505
  # standard out.
1232
- def egrep(pattern)
1506
+ def egrep(pattern, *options)
1233
1507
  each do |fn|
1234
- open(fn) do |inf|
1508
+ open(fn, "rb", *options) do |inf|
1235
1509
  count = 0
1236
1510
  inf.each do |line|
1237
1511
  count += 1
@@ -1240,7 +1514,7 @@ module Rake
1240
1514
  yield fn, count, line
1241
1515
  else
1242
1516
  puts "#{fn}:#{count}:#{line}"
1243
- end
1517
+ end
1244
1518
  end
1245
1519
  end
1246
1520
  end
@@ -1250,14 +1524,14 @@ module Rake
1250
1524
  # Return a new file list that only contains file names from the current
1251
1525
  # file list that exist on the file system.
1252
1526
  def existing
1253
- select { |fn| File.exists?(fn) }
1527
+ select { |fn| File.exist?(fn) }
1254
1528
  end
1255
-
1529
+
1256
1530
  # Modify the current file list so that it contains only file name that
1257
1531
  # exist on the file system.
1258
1532
  def existing!
1259
1533
  resolve
1260
- @items = @items.select { |fn| File.exists?(fn) }
1534
+ @items = @items.select { |fn| File.exist?(fn) }
1261
1535
  self
1262
1536
  end
1263
1537
 
@@ -1271,10 +1545,10 @@ module Rake
1271
1545
  FileList.new.import(result[1]),
1272
1546
  ]
1273
1547
  end
1274
-
1548
+
1275
1549
  # Convert a FileList to a string by joining all elements with a space.
1276
1550
  def to_s
1277
- resolve if @pending
1551
+ resolve
1278
1552
  self.join(' ')
1279
1553
  end
1280
1554
 
@@ -1301,7 +1575,7 @@ module Rake
1301
1575
  DEFAULT_IGNORE_PROCS = [
1302
1576
  proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
1303
1577
  ]
1304
- @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1578
+ # @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1305
1579
 
1306
1580
  def import(array)
1307
1581
  @items = array
@@ -1315,26 +1589,6 @@ module Rake
1315
1589
  def [](*args)
1316
1590
  new(*args)
1317
1591
  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
1592
  end
1339
1593
  end # FileList
1340
1594
  end
@@ -1343,7 +1597,7 @@ module Rake
1343
1597
  class << self
1344
1598
 
1345
1599
  # Yield each file or directory component.
1346
- def each_dir_parent(dir)
1600
+ def each_dir_parent(dir) # :nodoc:
1347
1601
  old_length = nil
1348
1602
  while dir != '.' && dir.length != old_length
1349
1603
  yield(dir)
@@ -1352,12 +1606,12 @@ module Rake
1352
1606
  end
1353
1607
  end
1354
1608
  end
1355
- end
1609
+ end # module Rake
1356
1610
 
1357
1611
  # Alias FileList to be available at the top level.
1358
1612
  FileList = Rake::FileList
1359
1613
 
1360
- # ###########################################################################
1614
+ #############################################################################
1361
1615
  module Rake
1362
1616
 
1363
1617
  # Default Rakefile loader used by +import+.
@@ -1382,9 +1636,9 @@ module Rake
1382
1636
  end
1383
1637
 
1384
1638
  EARLY = EarlyTime.instance
1385
- end
1639
+ end # module Rake
1386
1640
 
1387
- # ###########################################################################
1641
+ #############################################################################
1388
1642
  # Extensions to time to allow comparisons with an early time class.
1389
1643
  #
1390
1644
  class Time
@@ -1395,8 +1649,8 @@ class Time
1395
1649
  else
1396
1650
  rake_original_time_compare(other)
1397
1651
  end
1398
- end
1399
- end
1652
+ end
1653
+ end # class Time
1400
1654
 
1401
1655
  module Rake
1402
1656
 
@@ -1412,47 +1666,49 @@ module Rake
1412
1666
  @task_manager = task_manager
1413
1667
  @scope = scope_list.dup
1414
1668
  end
1415
-
1669
+
1416
1670
  # Lookup a task named +name+ in the namespace.
1417
1671
  def [](name)
1418
1672
  @task_manager.lookup(name, @scope)
1419
1673
  end
1420
1674
 
1421
- # Return the list of tasks defined in this namespace.
1675
+ # Return the list of tasks defined in this and nested namespaces.
1422
1676
  def tasks
1423
- @task_manager.tasks
1677
+ @task_manager.tasks_in_scope(@scope)
1424
1678
  end
1425
- end
1679
+ end # NameSpace
1426
1680
 
1427
1681
 
1428
1682
  ####################################################################
1429
- # The TaskManager module is a mixin for managing tasks.
1683
+ # The TaskManager module is a mixin for managing tasks.
1430
1684
  module TaskManager
1431
1685
  # Track the last comment made in the Rakefile.
1432
- attr_accessor :last_comment
1686
+ attr_accessor :last_description
1687
+ alias :last_comment :last_description # Backwards compatibility
1433
1688
 
1434
1689
  def initialize
1435
1690
  super
1436
1691
  @tasks = Hash.new
1437
1692
  @rules = Array.new
1438
1693
  @scope = Array.new
1439
- @last_comment = nil
1694
+ @last_description = nil
1440
1695
  end
1441
1696
 
1442
- def create_rule(args, &block)
1443
- pattern, deps = resolve_args(args)
1697
+ def create_rule(*args, &block)
1698
+ pattern, arg_names, deps = resolve_args(args)
1444
1699
  pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
1445
1700
  @rules << [pattern, deps, block]
1446
1701
  end
1447
1702
 
1448
- def define_task(task_class, args, &block)
1449
- task_name, deps = resolve_args(args)
1703
+ def define_task(task_class, *args, &block)
1704
+ task_name, arg_names, deps = resolve_args(args)
1450
1705
  task_name = task_class.scope_name(@scope, task_name)
1451
1706
  deps = [deps] unless deps.respond_to?(:to_ary)
1452
1707
  deps = deps.collect {|d| d.to_s }
1453
1708
  task = intern(task_class, task_name)
1454
- task.add_comment(@last_comment)
1455
- @last_comment = nil
1709
+ task.set_arg_names(arg_names) unless arg_names.empty?
1710
+ task.add_description(@last_description)
1711
+ @last_description = nil
1456
1712
  task.enhance(deps, &block)
1457
1713
  task
1458
1714
  end
@@ -1463,7 +1719,7 @@ module Rake
1463
1719
  @tasks[task_name.to_s] ||= task_class.new(task_name, self)
1464
1720
  end
1465
1721
 
1466
- # Find a matching task for +task_name+.
1722
+ # Find a matching task for +task_name+.
1467
1723
  def [](task_name, scopes=nil)
1468
1724
  task_name = task_name.to_s
1469
1725
  self.lookup(task_name, scopes) or
@@ -1476,22 +1732,68 @@ module Rake
1476
1732
  return nil unless File.exist?(task_name)
1477
1733
  define_task(Rake::FileTask, task_name)
1478
1734
  end
1479
-
1480
- # Resolve the arguments for a task/rule.
1735
+
1736
+ # Resolve the arguments for a task/rule. Returns a triplet of
1737
+ # [task_name, arg_name_list, prerequisites].
1481
1738
  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)
1739
+ if args.last.is_a?(Hash)
1740
+ deps = args.pop
1741
+ resolve_args_with_dependencies(args, deps)
1742
+ else
1743
+ resolve_args_without_dependencies(args)
1744
+ end
1745
+ end
1746
+
1747
+ # Resolve task arguments for a task or rule when there are no
1748
+ # dependencies declared.
1749
+ #
1750
+ # The patterns recognized by this argument resolving function are:
1751
+ #
1752
+ # task :t
1753
+ # task :t, [:a]
1754
+ # task :t, :a (deprecated)
1755
+ #
1756
+ def resolve_args_without_dependencies(args)
1757
+ task_name = args.shift
1758
+ if args.size == 1 && args.first.respond_to?(:to_ary)
1759
+ arg_names = args.first.to_ary
1760
+ else
1761
+ arg_names = args
1762
+ end
1763
+ [task_name, arg_names, []]
1764
+ end
1765
+ private :resolve_args_without_dependencies
1766
+
1767
+ # Resolve task arguments for a task or rule when there are
1768
+ # dependencies declared.
1769
+ #
1770
+ # The patterns recognized by this argument resolving function are:
1771
+ #
1772
+ # task :t => [:d]
1773
+ # task :t, [a] => [:d]
1774
+ # task :t, :needs => [:d] (deprecated)
1775
+ # task :t, :a, :needs => [:d] (deprecated)
1776
+ #
1777
+ def resolve_args_with_dependencies(args, hash) # :nodoc:
1778
+ fail "Task Argument Error" if hash.size != 1
1779
+ key, value = hash.map { |k, v| [k,v] }.first
1780
+ if args.empty?
1781
+ task_name = key
1782
+ arg_names = []
1783
+ deps = value
1784
+ elsif key == :needs
1785
+ task_name = args.shift
1786
+ arg_names = args
1787
+ deps = value
1489
1788
  else
1490
- task_name = args
1491
- deps = []
1789
+ task_name = args.shift
1790
+ arg_names = key
1791
+ deps = value
1492
1792
  end
1493
- [task_name, deps]
1793
+ deps = [deps] unless deps.respond_to?(:to_ary)
1794
+ [task_name, arg_names, deps]
1494
1795
  end
1796
+ private :resolve_args_with_dependencies
1495
1797
 
1496
1798
  # If a rule can be found that matches the task name, enhance the
1497
1799
  # task with the prerequisites and actions from the rule. Set the
@@ -1511,12 +1813,21 @@ module Rake
1511
1813
  ex.add_target(task_name)
1512
1814
  fail ex
1513
1815
  end
1514
-
1816
+
1515
1817
  # List of all defined tasks in this application.
1516
1818
  def tasks
1517
1819
  @tasks.values.sort_by { |t| t.name }
1518
1820
  end
1519
1821
 
1822
+ # List of all the tasks defined in the given scope (and its
1823
+ # sub-scopes).
1824
+ def tasks_in_scope(scope)
1825
+ prefix = scope.join(":")
1826
+ tasks.select { |t|
1827
+ /^#{prefix}:/ =~ t.name
1828
+ }
1829
+ end
1830
+
1520
1831
  # Clear all tasks in this application.
1521
1832
  def clear
1522
1833
  @tasks.clear
@@ -1543,7 +1854,7 @@ module Rake
1543
1854
  lookup_in_scope(task_name, scopes)
1544
1855
  end
1545
1856
 
1546
- # Lookup the task name
1857
+ # Lookup the task name
1547
1858
  def lookup_in_scope(name, scope)
1548
1859
  n = scope.size
1549
1860
  while n >= 0
@@ -1583,15 +1894,23 @@ module Rake
1583
1894
  "_anon_#{@seed}"
1584
1895
  end
1585
1896
 
1897
+ def trace_rule(level, message)
1898
+ puts "#{" "*level}#{message}" if Rake.application.options.trace_rules
1899
+ end
1900
+
1586
1901
  # Attempt to create a rule given the list of prerequisites.
1587
1902
  def attempt_rule(task_name, extensions, block, level)
1588
1903
  sources = make_sources(task_name, extensions)
1589
1904
  prereqs = sources.collect { |source|
1905
+ trace_rule level, "Attempting Rule #{task_name} => #{source}"
1590
1906
  if File.exist?(source) || Rake::Task.task_defined?(source)
1907
+ trace_rule level, "(#{task_name} => #{source} ... EXIST)"
1591
1908
  source
1592
- elsif parent = enhance_with_matching_rule(sources.first, level+1)
1909
+ elsif parent = enhance_with_matching_rule(source, level+1)
1910
+ trace_rule level, "(#{task_name} => #{source} ... ENHANCE)"
1593
1911
  parent.name
1594
1912
  else
1913
+ trace_rule level, "(#{task_name} => #{source} ... FAIL)"
1595
1914
  return nil
1596
1915
  end
1597
1916
  }
@@ -1599,13 +1918,13 @@ module Rake
1599
1918
  task.sources = prereqs
1600
1919
  task
1601
1920
  end
1602
-
1921
+
1603
1922
  # Make a list of sources from the list of file name extensions /
1604
1923
  # translation procs.
1605
1924
  def make_sources(task_name, extensions)
1606
1925
  extensions.collect { |ext|
1607
1926
  case ext
1608
- when /^%/
1927
+ when /%/
1609
1928
  task_name.pathmap(ext)
1610
1929
  when %r{/}
1611
1930
  ext
@@ -1614,14 +1933,18 @@ module Rake
1614
1933
  when String
1615
1934
  ext
1616
1935
  when Proc
1617
- ext.call(task_name)
1936
+ if ext.arity == 1
1937
+ ext.call(task_name)
1938
+ else
1939
+ ext.call
1940
+ end
1618
1941
  else
1619
1942
  fail "Don't know how to handle rule dependent: #{ext.inspect}"
1620
1943
  end
1621
1944
  }.flatten
1622
1945
  end
1623
-
1624
- end
1946
+
1947
+ end # TaskManager
1625
1948
 
1626
1949
  ######################################################################
1627
1950
  # Rake main application object. When invoking +rake+ from the
@@ -1635,50 +1958,15 @@ module Rake
1635
1958
 
1636
1959
  # The original directory where rake was invoked.
1637
1960
  attr_reader :original_dir
1638
-
1961
+
1639
1962
  # Name of the actual rakefile used.
1640
1963
  attr_reader :rakefile
1641
-
1964
+
1642
1965
  # List of the top level task names (task names from the command line).
1643
1966
  attr_reader :top_level_tasks
1644
1967
 
1645
1968
  DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
1646
-
1647
- OPTIONS = [ # :nodoc:
1648
- ['--dry-run', '-n', GetoptLong::NO_ARGUMENT,
1649
- "Do a dry run without executing actions."],
1650
- ['--help', '-H', GetoptLong::NO_ARGUMENT,
1651
- "Display this help message."],
1652
- ['--libdir', '-I', GetoptLong::REQUIRED_ARGUMENT,
1653
- "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')"],
1656
- ['--nosearch', '-N', GetoptLong::NO_ARGUMENT,
1657
- "Do not search parent directories for the Rakefile."],
1658
- ['--prereqs', '-P', GetoptLong::NO_ARGUMENT,
1659
- "Display the tasks and dependencies, then exit."],
1660
- ['--quiet', '-q', GetoptLong::NO_ARGUMENT,
1661
- "Do not log messages to standard output."],
1662
- ['--rakefile', '-f', GetoptLong::OPTIONAL_ARGUMENT,
1663
- "Use FILE as the rakefile."],
1664
- ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT,
1665
- "Require MODULE before executing rakefile."],
1666
- ['--silent', '-s', GetoptLong::NO_ARGUMENT,
1667
- "Like --quiet, but also suppresses the 'in directory' announcement."],
1668
- ['--tasks', '-T', GetoptLong::OPTIONAL_ARGUMENT,
1669
- "Display the tasks (matching optional PATTERN) with descriptions, then exit."],
1670
- ['--trace', '-t', GetoptLong::NO_ARGUMENT,
1671
- "Turn on invoke/execute tracing, enable full backtrace."],
1672
- ['--usage', '-h', GetoptLong::NO_ARGUMENT,
1673
- "Display usage."],
1674
- ['--verbose', '-v', GetoptLong::NO_ARGUMENT,
1675
- "Log message to standard output (default)."],
1676
- ['--version', '-V', GetoptLong::NO_ARGUMENT,
1677
- "Display the program version."],
1678
- ['--classic-namespace', '-C', GetoptLong::NO_ARGUMENT,
1679
- "Put Task and FileTask in the top level namespace"],
1680
- ]
1681
-
1969
+
1682
1970
  # Initialize a Rake::Application object.
1683
1971
  def initialize
1684
1972
  super
@@ -1691,8 +1979,10 @@ module Rake
1691
1979
  @default_loader = Rake::DefaultLoader.new
1692
1980
  @original_dir = Dir.pwd
1693
1981
  @top_level_tasks = []
1982
+ add_loader('rb', DefaultLoader.new)
1694
1983
  add_loader('rf', DefaultLoader.new)
1695
1984
  add_loader('rake', DefaultLoader.new)
1985
+ @tty_output = STDOUT.tty?
1696
1986
  end
1697
1987
 
1698
1988
  # Run the Rake application. The run method performs the following three steps:
@@ -1701,7 +1991,7 @@ module Rake
1701
1991
  # * Define the tasks (+load_rakefile+).
1702
1992
  # * Run the top level tasks (+run_tasks+).
1703
1993
  #
1704
- # If you wish to build a custom rake command, you should call +init+ on your
1994
+ # If you wish to build a custom rake command, you should call +init+ on your
1705
1995
  # application. The define any tasks. Finally, call +top_level+ to run your top
1706
1996
  # level tasks.
1707
1997
  def run
@@ -1726,7 +2016,7 @@ module Rake
1726
2016
  standard_exception_handling do
1727
2017
  raw_load_rakefile
1728
2018
  end
1729
- end
2019
+ end
1730
2020
 
1731
2021
  # Run the top level tasks of a Rake application.
1732
2022
  def top_level
@@ -1736,7 +2026,7 @@ module Rake
1736
2026
  elsif options.show_prereqs
1737
2027
  display_prerequisites
1738
2028
  else
1739
- top_level_tasks.each { |task_name| self[task_name].invoke }
2029
+ top_level_tasks.each { |task_name| invoke_task(task_name) }
1740
2030
  end
1741
2031
  end
1742
2032
  end
@@ -1747,7 +2037,7 @@ module Rake
1747
2037
  ext = ".#{ext}" unless ext =~ /^\./
1748
2038
  @loaders[ext] = loader
1749
2039
  end
1750
-
2040
+
1751
2041
  # Application options from the command line
1752
2042
  def options
1753
2043
  @options ||= OpenStruct.new
@@ -1755,16 +2045,36 @@ module Rake
1755
2045
 
1756
2046
  # private ----------------------------------------------------------------
1757
2047
 
2048
+ def invoke_task(task_string)
2049
+ name, args = parse_task_string(task_string)
2050
+ t = self[name]
2051
+ t.invoke(*args)
2052
+ end
2053
+
2054
+ def parse_task_string(string)
2055
+ if string =~ /^([^\[]+)(\[(.*)\])$/
2056
+ name = $1
2057
+ args = $3.split(/\s*,\s*/)
2058
+ else
2059
+ name = string
2060
+ args = []
2061
+ end
2062
+ [name, args]
2063
+ end
2064
+
1758
2065
  # Provide standard execption handling for the given block.
1759
2066
  def standard_exception_handling
1760
2067
  begin
1761
2068
  yield
1762
- rescue SystemExit, GetoptLong::InvalidOption => ex
2069
+ rescue SystemExit => ex
2070
+ # Exit silently with current status
2071
+ raise
2072
+ rescue OptionParser::InvalidOption => ex
1763
2073
  # Exit silently
1764
- exit(1)
2074
+ exit(false)
1765
2075
  rescue Exception => ex
1766
2076
  # Exit with error message
1767
- $stderr.puts "rake aborted!"
2077
+ $stderr.puts "#{name} aborted!"
1768
2078
  $stderr.puts ex.message
1769
2079
  if options.trace
1770
2080
  $stderr.puts ex.backtrace.join("\n")
@@ -1772,132 +2082,246 @@ module Rake
1772
2082
  $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
1773
2083
  $stderr.puts "(See full trace by running task with --trace)"
1774
2084
  end
1775
- exit(1)
1776
- end
2085
+ exit(false)
2086
+ end
1777
2087
  end
1778
-
2088
+
1779
2089
  # True if one of the files in RAKEFILES is in the current directory.
1780
2090
  # If a match is found, it is copied into @rakefile.
1781
2091
  def have_rakefile
1782
2092
  @rakefiles.each do |fn|
1783
- if File.exist?(fn) || fn == ''
1784
- @rakefile = fn
1785
- return true
2093
+ if File.exist?(fn)
2094
+ others = Dir.glob(fn, File::FNM_CASEFOLD)
2095
+ return others.size == 1 ? others.first : fn
2096
+ elsif fn == ''
2097
+ return fn
1786
2098
  end
1787
2099
  end
1788
- return false
2100
+ return nil
1789
2101
  end
1790
-
1791
- # Display the program usage line.
1792
- def usage
1793
- puts "rake [-f rakefile] {options} targets..."
2102
+
2103
+ # True if we are outputting to TTY, false otherwise
2104
+ def tty_output?
2105
+ @tty_output
1794
2106
  end
1795
-
1796
- # Display the rake command line help.
1797
- def help
1798
- usage
1799
- puts
1800
- puts "Options are ..."
1801
- puts
1802
- OPTIONS.sort.each do |long, short, mode, desc|
1803
- if mode == GetoptLong::REQUIRED_ARGUMENT
1804
- if desc =~ /\b([A-Z]{2,})\b/
1805
- long = long + "=#{$1}"
1806
- end
1807
- end
1808
- printf " %-20s (%s)\n", long, short
1809
- printf " %s\n", desc
1810
- end
2107
+
2108
+ # Override the detected TTY output state (mostly for testing)
2109
+ def tty_output=( tty_output_state )
2110
+ @tty_output = tty_output_state
1811
2111
  end
1812
-
1813
- # Display the tasks and dependencies.
2112
+
2113
+ # We will truncate output if we are outputting to a TTY or if we've been
2114
+ # given an explicit column width to honor
2115
+ def truncate_output?
2116
+ tty_output? || ENV['RAKE_COLUMNS']
2117
+ end
2118
+
2119
+ # Display the tasks and comments.
1814
2120
  def display_tasks_and_comments
1815
2121
  displayable_tasks = tasks.select { |t|
1816
2122
  t.comment && t.name =~ options.show_task_pattern
1817
2123
  }
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
2124
+ if options.full_description
2125
+ displayable_tasks.each do |t|
2126
+ puts "#{name} #{t.name_with_args}"
2127
+ t.full_comment.split("\n").each do |line|
2128
+ puts " #{line}"
2129
+ end
2130
+ puts
2131
+ end
2132
+ else
2133
+ width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
2134
+ max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil
2135
+ displayable_tasks.each do |t|
2136
+ printf "#{name} %-#{width}s # %s\n",
2137
+ t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment
2138
+ end
2139
+ end
2140
+ end
2141
+
2142
+ def terminal_width
2143
+ if ENV['RAKE_COLUMNS']
2144
+ result = ENV['RAKE_COLUMNS'].to_i
2145
+ else
2146
+ result = unix? ? dynamic_width : 80
1821
2147
  end
2148
+ (result < 10) ? 80 : result
2149
+ rescue
2150
+ 80
2151
+ end
2152
+
2153
+ # Calculate the dynamic width of the
2154
+ def dynamic_width
2155
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
2156
+ end
2157
+
2158
+ def dynamic_width_stty
2159
+ %x{stty size 2>/dev/null}.split[1].to_i
2160
+ end
2161
+
2162
+ def dynamic_width_tput
2163
+ %x{tput cols 2>/dev/null}.to_i
2164
+ end
2165
+
2166
+ def unix?
2167
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
1822
2168
  end
1823
2169
 
2170
+ def windows?
2171
+ Win32.windows?
2172
+ end
2173
+
2174
+ def truncate(string, width)
2175
+ if string.length <= width
2176
+ string
2177
+ else
2178
+ ( string[0, width-3] || "" ) + "..."
2179
+ end
2180
+ end
2181
+
1824
2182
  # Display the tasks and prerequisites
1825
2183
  def display_prerequisites
1826
2184
  tasks.each do |t|
1827
- puts "rake #{t.name}"
2185
+ puts "#{name} #{t.name}"
1828
2186
  t.prerequisites.each { |pre| puts " #{pre}" }
1829
2187
  end
1830
2188
  end
1831
-
1832
- # Return a list of the command line options supported by the
1833
- # program.
1834
- def command_line_options
1835
- OPTIONS.collect { |lst| lst[0..-2] }
1836
- end
1837
-
1838
- # Do the option defined by +opt+ and +value+.
1839
- def do_option(opt, value)
1840
- case opt
1841
- when '--dry-run'
1842
- verbose(true)
1843
- nowrite(true)
1844
- options.dryrun = true
1845
- options.trace = true
1846
- when '--help'
1847
- help
1848
- exit
1849
- when '--libdir'
1850
- $:.push(value)
1851
- when '--nosearch'
1852
- options.nosearch = true
1853
- when '--prereqs'
1854
- options.show_prereqs = true
1855
- when '--quiet'
1856
- verbose(false)
1857
- when '--rakefile'
1858
- @rakefiles.clear
1859
- @rakefiles << value
1860
- when '--rakelibdir'
1861
- options.rakelib = value.split(':')
1862
- when '--require'
1863
- begin
1864
- require value
1865
- rescue LoadError => ex
1866
- begin
1867
- rake_require value
1868
- rescue LoadError => ex2
1869
- raise ex
1870
- end
1871
- end
1872
- when '--silent'
1873
- verbose(false)
1874
- options.silent = true
1875
- when '--tasks'
1876
- options.show_tasks = true
1877
- options.show_task_pattern = Regexp.new(value || '.')
1878
- when '--trace'
1879
- options.trace = true
1880
- verbose(true)
1881
- when '--usage'
1882
- usage
1883
- exit
1884
- when '--verbose'
1885
- verbose(true)
1886
- when '--version'
1887
- puts "rake, version #{RAKEVERSION}"
1888
- exit
1889
- when '--classic-namespace'
1890
- require 'rake/classic_namespace'
1891
- options.classic_namespace = true
1892
- end
2189
+
2190
+ # A list of all the standard options used in rake, suitable for
2191
+ # passing to OptionParser.
2192
+ def standard_rake_options
2193
+ [
2194
+ ['--classic-namespace', '-C', "Put Task and FileTask in the top level namespace",
2195
+ lambda { |value|
2196
+ require 'rake/classic_namespace'
2197
+ options.classic_namespace = true
2198
+ }
2199
+ ],
2200
+ ['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
2201
+ lambda { |value|
2202
+ options.show_tasks = true
2203
+ options.full_description = true
2204
+ options.show_task_pattern = Regexp.new(value || '')
2205
+ }
2206
+ ],
2207
+ ['--dry-run', '-n', "Do a dry run without executing actions.",
2208
+ lambda { |value|
2209
+ verbose(true)
2210
+ nowrite(true)
2211
+ options.dryrun = true
2212
+ options.trace = true
2213
+ }
2214
+ ],
2215
+ ['--execute', '-e CODE', "Execute some Ruby code and exit.",
2216
+ lambda { |value|
2217
+ eval(value)
2218
+ exit
2219
+ }
2220
+ ],
2221
+ ['--execute-print', '-p CODE', "Execute some Ruby code, print the result, then exit.",
2222
+ lambda { |value|
2223
+ puts eval(value)
2224
+ exit
2225
+ }
2226
+ ],
2227
+ ['--execute-continue', '-E CODE',
2228
+ "Execute some Ruby code, then continue with normal task processing.",
2229
+ lambda { |value| eval(value) }
2230
+ ],
2231
+ ['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
2232
+ lambda { |value| $:.push(value) }
2233
+ ],
2234
+ ['--prereqs', '-P', "Display the tasks and dependencies, then exit.",
2235
+ lambda { |value| options.show_prereqs = true }
2236
+ ],
2237
+ ['--quiet', '-q', "Do not log messages to standard output.",
2238
+ lambda { |value| verbose(false) }
2239
+ ],
2240
+ ['--rakefile', '-f [FILE]', "Use FILE as the rakefile.",
2241
+ lambda { |value|
2242
+ value ||= ''
2243
+ @rakefiles.clear
2244
+ @rakefiles << value
2245
+ }
2246
+ ],
2247
+ ['--rakelibdir', '--rakelib', '-R RAKELIBDIR',
2248
+ "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')",
2249
+ lambda { |value| options.rakelib = value.split(':') }
2250
+ ],
2251
+ ['--require', '-r MODULE', "Require MODULE before executing rakefile.",
2252
+ lambda { |value|
2253
+ begin
2254
+ require value
2255
+ rescue LoadError => ex
2256
+ begin
2257
+ rake_require value
2258
+ rescue LoadError => ex2
2259
+ raise ex
2260
+ end
2261
+ end
2262
+ }
2263
+ ],
2264
+ ['--rules', "Trace the rules resolution.",
2265
+ lambda { |value| options.trace_rules = true }
2266
+ ],
2267
+ ['--no-search', '--nosearch', '-N', "Do not search parent directories for the Rakefile.",
2268
+ lambda { |value| options.nosearch = true }
2269
+ ],
2270
+ ['--silent', '-s', "Like --quiet, but also suppresses the 'in directory' announcement.",
2271
+ lambda { |value|
2272
+ verbose(false)
2273
+ options.silent = true
2274
+ }
2275
+ ],
2276
+ ['--system', '-g',
2277
+ "Using system wide (global) rakefiles (usually '~/.rake/*.rake').",
2278
+ lambda { |value| options.load_system = true }
2279
+ ],
2280
+ ['--no-system', '--nosystem', '-G',
2281
+ "Use standard project Rakefile search paths, ignore system wide rakefiles.",
2282
+ lambda { |value| options.ignore_system = true }
2283
+ ],
2284
+ ['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.",
2285
+ lambda { |value|
2286
+ options.show_tasks = true
2287
+ options.show_task_pattern = Regexp.new(value || '')
2288
+ options.full_description = false
2289
+ }
2290
+ ],
2291
+ ['--trace', '-t', "Turn on invoke/execute tracing, enable full backtrace.",
2292
+ lambda { |value|
2293
+ options.trace = true
2294
+ verbose(true)
2295
+ }
2296
+ ],
2297
+ ['--verbose', '-v', "Log message to standard output.",
2298
+ lambda { |value| verbose(true) }
2299
+ ],
2300
+ ['--version', '-V', "Display the program version.",
2301
+ lambda { |value|
2302
+ puts "rake, version #{RAKEVERSION}"
2303
+ exit
2304
+ }
2305
+ ]
2306
+ ]
1893
2307
  end
1894
-
2308
+
1895
2309
  # Read and handle the command line options.
1896
2310
  def handle_options
1897
- options.rakelib = 'rakelib'
2311
+ options.rakelib = ['rakelib']
1898
2312
 
1899
- opts = GetoptLong.new(*command_line_options)
1900
- opts.each { |opt, value| do_option(opt, value) }
2313
+ OptionParser.new do |opts|
2314
+ opts.banner = "rake [-f rakefile] {options} targets..."
2315
+ opts.separator ""
2316
+ opts.separator "Options are ..."
2317
+
2318
+ opts.on_tail("-h", "--help", "-H", "Display this help message.") do
2319
+ puts opts
2320
+ exit
2321
+ end
2322
+
2323
+ standard_rake_options.each { |args| opts.on(*args) }
2324
+ end.parse!
1901
2325
 
1902
2326
  # If class namespaces are requested, set the global options
1903
2327
  # according to the values in the options structure.
@@ -1909,9 +2333,9 @@ module Rake
1909
2333
  $silent = options.silent
1910
2334
  end
1911
2335
  end
1912
-
2336
+
1913
2337
  # Similar to the regular Ruby +require+ command, but will check
1914
- # for .rake files in addition to .rb files.
2338
+ # for *.rake files in addition to *.rb files.
1915
2339
  def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
1916
2340
  return false if loaded.include?(file_name)
1917
2341
  paths.each do |path|
@@ -1926,24 +2350,75 @@ module Rake
1926
2350
  fail LoadError, "Can't find #{file_name}"
1927
2351
  end
1928
2352
 
1929
- def raw_load_rakefile # :nodoc:
2353
+ def find_rakefile_location
1930
2354
  here = Dir.pwd
1931
- while ! have_rakefile
2355
+ while ! (fn = have_rakefile)
1932
2356
  Dir.chdir("..")
1933
2357
  if Dir.pwd == here || options.nosearch
1934
- fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})"
2358
+ return nil
1935
2359
  end
1936
2360
  here = Dir.pwd
1937
2361
  end
1938
- puts "(in #{Dir.pwd})" unless options.silent
1939
- $rakefile = @rakefile
1940
- load File.expand_path(@rakefile) if @rakefile != ''
1941
- options.rakelib.each do |rlib|
1942
- Dir["#{rlib}/*.rake"].each do |name| add_import name end
2362
+ [fn, here]
2363
+ ensure
2364
+ Dir.chdir(Rake.original_dir)
2365
+ end
2366
+
2367
+ def raw_load_rakefile # :nodoc:
2368
+ rakefile, location = find_rakefile_location
2369
+ if (! options.ignore_system) &&
2370
+ (options.load_system || rakefile.nil?) &&
2371
+ system_dir && File.directory?(system_dir)
2372
+ puts "(in #{Dir.pwd})" unless options.silent
2373
+ glob("#{system_dir}/*.rake") do |name|
2374
+ add_import name
2375
+ end
2376
+ else
2377
+ fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if
2378
+ rakefile.nil?
2379
+ @rakefile = rakefile
2380
+ Dir.chdir(location)
2381
+ puts "(in #{Dir.pwd})" unless options.silent
2382
+ $rakefile = @rakefile if options.classic_namespace
2383
+ load File.expand_path(@rakefile) if @rakefile && @rakefile != ''
2384
+ options.rakelib.each do |rlib|
2385
+ glob("#{rlib}/*.rake") do |name|
2386
+ add_import name
2387
+ end
2388
+ end
1943
2389
  end
1944
2390
  load_imports
1945
2391
  end
2392
+
2393
+ def glob(path, &block)
2394
+ Dir[path.gsub("\\", '/')].each(&block)
2395
+ end
2396
+ private :glob
2397
+
2398
+ # The directory path containing the system wide rakefiles.
2399
+ def system_dir
2400
+ @system_dir ||=
2401
+ begin
2402
+ if ENV['RAKE_SYSTEM']
2403
+ ENV['RAKE_SYSTEM']
2404
+ else
2405
+ standard_system_dir
2406
+ end
2407
+ end
2408
+ end
1946
2409
 
2410
+ # The standard directory containing system wide rake files.
2411
+ if Win32.windows?
2412
+ def standard_system_dir #:nodoc:
2413
+ Win32.win32_system_dir
2414
+ end
2415
+ else
2416
+ def standard_system_dir #:nodoc:
2417
+ File.join(File.expand_path('~'), '.rake')
2418
+ end
2419
+ end
2420
+ private :standard_system_dir
2421
+
1947
2422
  # Collect the list of tasks on the command line. If no tasks are
1948
2423
  # given, return a list containing only the default task.
1949
2424
  # Environmental assignments are processed at this time as well.
@@ -1953,17 +2428,17 @@ module Rake
1953
2428
  if arg =~ /^(\w+)=(.*)$/
1954
2429
  ENV[$1] = $2
1955
2430
  else
1956
- @top_level_tasks << arg
2431
+ @top_level_tasks << arg unless arg =~ /^-/
1957
2432
  end
1958
2433
  end
1959
2434
  @top_level_tasks.push("default") if @top_level_tasks.size == 0
1960
2435
  end
1961
-
2436
+
1962
2437
  # Add a file to the list of files to be imported.
1963
2438
  def add_import(fn)
1964
2439
  @pending_imports << fn
1965
2440
  end
1966
-
2441
+
1967
2442
  # Load the pending list of imported files.
1968
2443
  def load_imports
1969
2444
  while fn = @pending_imports.shift
@@ -1977,7 +2452,7 @@ module Rake
1977
2452
  @imported << fn
1978
2453
  end
1979
2454
  end
1980
-
2455
+
1981
2456
  # Warn about deprecated use of top level constant names.
1982
2457
  def const_warning(const_name)
1983
2458
  @const_warning ||= false
@@ -2004,7 +2479,7 @@ end
2004
2479
  class Module
2005
2480
  # Rename the original handler to make it available.
2006
2481
  alias :rake_original_const_missing :const_missing
2007
-
2482
+
2008
2483
  # Check for deprecated uses of top level (i.e. in Object) uses of
2009
2484
  # Rake class names. If someone tries to reference the constant
2010
2485
  # name, display a warning and return the proper object. Using the