Geminstaller C0 Coverage Information - RCov

/Users/woolley/.rvm/gems/ruby-1.8.7-p174@geminstaller/gems/rake-0.8.7/lib/rake.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
/Users/woolley/.rvm/gems/ruby-1.8.7-p174@geminstaller/gems/rake-0.8.7/lib/rake.rb 2506 1587
52.08%
25.27%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 #!/usr/bin/env ruby
2 
3 #--
4 
5 # Copyright 2003, 2004, 2005, 2006, 2007, 2008 by Jim Weirich (jim@weirichhouse.org)
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to
9 # deal in the Software without restriction, including without limitation the
10 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11 # sell copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24 #++
25 #
26 # = Rake -- Ruby Make
27 #
28 # This is the main file for the Rake application.  Normally it is referenced
29 # as a library via a require statement, but it can be distributed
30 # independently as an application.
31 
32 RAKEVERSION = '0.8.7'
33 
34 require 'rbconfig'
35 require 'fileutils'
36 require 'singleton'
37 require 'monitor'
38 require 'optparse'
39 require 'ostruct'
40 
41 require 'rake/win32'
42 
43 $trace = false
44 
45 ######################################################################
46 # Rake extensions to Module.
47 #
48 class Module
49   # Check for an existing method in the current class before extending.  IF
50   # the method already exists, then a warning is printed and the extension is
51   # not added.  Otherwise the block is yielded and any definitions in the
52   # block will take effect.
53   #
54   # Usage:
55   #
56   #   class String
57   #     rake_extension("xyz") do
58   #       def xyz
59   #         ...
60   #       end
61   #     end
62   #   end
63   #
64   def rake_extension(method)
65     if method_defined?(method)
66       $stderr.puts "WARNING: Possible conflict with Rake extension: #{self}##{method} already exists"
67     else
68       yield
69     end
70   end
71 end # module Module
72 
73 
74 ######################################################################
75 # User defined methods to be added to String.
76 #
77 class String
78   rake_extension("ext") do
79     # Replace the file extension with +newext+.  If there is no extension on
80     # the string, append the new extension to the end.  If the new extension
81     # is not given, or is the empty string, remove any existing extension.
82     #
83     # +ext+ is a user added method for the String class.
84     def ext(newext='')
85       return self.dup if ['.', '..'].include? self
86       if newext != ''
87         newext = (newext =~ /^\./) ? newext : ("." + newext)
88       end
89       self.chomp(File.extname(self)) << newext
90     end
91   end
92 
93   rake_extension("pathmap") do
94     # Explode a path into individual components.  Used by +pathmap+.
95     def pathmap_explode
96       head, tail = File.split(self)
97       return [self] if head == self
98       return [tail] if head == '.' || tail == '/'
99       return [head, tail] if head == '/'
100       return head.pathmap_explode + [tail]
101     end
102     protected :pathmap_explode
103 
104     # Extract a partial path from the path.  Include +n+ directories from the
105     # front end (left hand side) if +n+ is positive.  Include |+n+|
106     # directories from the back end (right hand side) if +n+ is negative.
107     def pathmap_partial(n)
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         else
115           "."
116         end
117       File.join(partial_dirs)
118     end
119     protected :pathmap_partial
120       
121     # Preform the pathmap replacement operations on the given path. The
122     # patterns take the form 'pat1,rep1;pat2,rep2...'.
123     def pathmap_replace(patterns, &block)
124       result = self
125       patterns.split(';').each do |pair|
126         pattern, replacement = pair.split(',')
127         pattern = Regexp.new(pattern)
128         if replacement == '*' && block_given?
129           result = result.sub(pattern, &block)
130         elsif replacement
131           result = result.sub(pattern, replacement)
132         else
133           result = result.sub(pattern, '')
134         end
135       end
136       result
137     end
138     protected :pathmap_replace
139 
140     # Map the path according to the given specification.  The specification
141     # controls the details of the mapping.  The following special patterns are
142     # recognized:
143     #
144     # * <b>%p</b> -- The complete path.
145     # * <b>%f</b> -- The base file name of the path, with its file extension,
146     #   but without any directories.
147     # * <b>%n</b> -- The file name of the path without its file extension.
148     # * <b>%d</b> -- The directory list of the path.
149     # * <b>%x</b> -- The file extension of the path.  An empty string if there
150     #   is no extension.
151     # * <b>%X</b> -- Everything *but* the file extension.
152     # * <b>%s</b> -- The alternate file separater if defined, otherwise use
153     #   the standard file separator.
154     # * <b>%%</b> -- A percent sign.
155     #
156     # The %d specifier can also have a numeric prefix (e.g. '%2d'). If the
157     # number is positive, only return (up to) +n+ directories in the path,
158     # starting from the left hand side.  If +n+ is negative, return (up to)
159     # |+n+| directories from the right hand side of the path.
160     #
161     # Examples:
162     #
163     #   'a/b/c/d/file.txt'.pathmap("%2d")   => 'a/b'
164     #   'a/b/c/d/file.txt'.pathmap("%-2d")  => 'c/d'
165     #
166     # Also the %d, %p, %f, %n, %x, and %X operators can take a
167     # pattern/replacement argument to perform simple string substititions on a
168     # particular part of the path.  The pattern and replacement are speparated
169     # by a comma and are enclosed by curly braces.  The replacement spec comes
170     # after the % character but before the operator letter.  (e.g.
171     # "%{old,new}d").  Muliple replacement specs should be separated by
172     # semi-colons (e.g. "%{old,new;src,bin}d").
173     #
174     # Regular expressions may be used for the pattern, and back refs may be
175     # used in the replacement text.  Curly braces, commas and semi-colons are
176     # excluded from both the pattern and replacement text (let's keep parsing
177     # reasonable).
178     #
179     # For example:
180     #
181     #    "src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")
182     #
183     # returns:
184     #
185     #    "bin/org/onestepback/proj/A.class"
186     #
187     # If the replacement text is '*', then a block may be provided to perform
188     # some arbitrary calculation for the replacement.
189     #
190     # For example:
191     #
192     #   "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext|
193     #      ext.downcase
194     #   }
195     #
196     # Returns:
197     #
198     #  "/path/to/file.txt"
199     #
200     def pathmap(spec=nil, &block)
201       return self if spec.nil?
202       result = ''
203       spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
204         case frag
205         when '%f'
206           result << File.basename(self)
207         when '%n'
208           result << File.basename(self).ext
209         when '%d'
210           result << File.dirname(self)
211         when '%x'
212           result << File.extname(self)
213         when '%X'
214           result << self.ext
215         when '%p'
216           result << self
217         when '%s'
218           result << (File::ALT_SEPARATOR || File::SEPARATOR)
219         when '%-'
220           # do nothing
221         when '%%'
222           result << "%"
223         when /%(-?\d+)d/
224           result << pathmap_partial($1.to_i)
225         when /^%\{([^}]*)\}(\d*[dpfnxX])/
226           patterns, operator = $1, $2
227           result << pathmap('%' + operator).pathmap_replace(patterns, &block)
228         when /^%/
229           fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'"
230         else
231           result << frag
232         end
233       end
234       result
235     end
236   end
237 end # class String
238 
239 ##############################################################################
240 module Rake
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 
264   # --------------------------------------------------------------------------
265   # Rake module singleton methods.
266   #
267   class << self
268     # Current Rake Application
269     def application
270       @application ||= Rake::Application.new
271     end
272 
273     # Set the current Rake application object.
274     def application=(app)
275       @application = app
276     end
277 
278     # Return the original directory where the Rake application was started.
279     def original_dir
280       application.original_dir
281     end
282 
283   end
284 
285   ####################################################################
286   # Mixin for creating easily cloned objects.
287   #
288   module Cloneable
289     # Clone an object by making a new object and setting all the instance
290     # variables to the same values.
291     def dup
292       sibling = self.class.new
293       instance_variables.each do |ivar|
294         value = self.instance_variable_get(ivar)
295         new_value = value.clone rescue value
296         sibling.instance_variable_set(ivar, new_value)
297       end
298       sibling.taint if tainted?
299       sibling
300     end
301 
302     def clone
303       sibling = dup
304       sibling.freeze if frozen?
305       sibling
306     end
307   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
457 
458 module Rake
459 
460   ###########################################################################
461   # A Task is the basic unit of work in a Rakefile.  Tasks have associated
462   # actions (possibly more than one) and a list of prerequisites.  When
463   # invoked, a task will first ensure that all of its prerequisites have an
464   # opportunity to run and then it will execute its own actions.
465   #
466   # Tasks are not usually created directly using the new method, but rather
467   # use the +file+ and +task+ convenience methods.
468   #
469   class Task
470     # List of prerequisites for a task.
471     attr_reader :prerequisites
472 
473     # List of actions attached to a task.
474     attr_reader :actions
475 
476     # Application owning this task.
477     attr_accessor :application
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 
486     # Array of nested namespaces names used for task lookup by this task.
487     attr_reader :scope
488 
489     # Return task name
490     def to_s
491       name
492     end
493 
494     def inspect
495       "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
496     end
497 
498     # List of sources for task.
499     attr_writer :sources
500     def sources
501       @sources ||= []
502     end
503 
504     # First source from a rule (nil if no sources)
505     def source
506       @sources.first if defined?(@sources)
507     end
508 
509     # Create a task named +task_name+ with no actions or prerequisites. Use
510     # +enhance+ to add actions and prerequisites.
511     def initialize(task_name, app)
512       @name = task_name.to_s
513       @prerequisites = []
514       @actions = []
515       @already_invoked = false
516       @full_comment = nil
517       @comment = nil
518       @lock = Monitor.new
519       @application = app
520       @scope = app.current_scope
521       @arg_names = nil
522     end
523 
524     # Enhance a task with prerequisites or actions.  Returns self.
525     def enhance(deps=nil, &block)
526       @prerequisites |= deps if deps
527       @actions << block if block_given?
528       self
529     end
530 
531     # Name of the task, including any namespace qualifiers.
532     def name
533       @name.to_s
534     end
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 
580     # Invoke the task if it is needed.  Prerequites are invoked first.
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)
590       @lock.synchronize do
591         if application.options.trace
592           puts "** Invoke #{name} #{format_trace_flags}"
593         end
594         return if @already_invoked
595         @already_invoked = true
596         invoke_prerequisites(task_args, new_chain)
597         execute(task_args) if needed?
598       end
599     end
600     protected :invoke_with_call_chain
601 
602     # Invoke all the prerequisites of a task.
603     def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
604       @prerequisites.each { |n|
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)
608       }
609     end
610 
611     # Format the trace flags for display.
612     def format_trace_flags
613       flags = []
614       flags << "first_time" unless @already_invoked
615       flags << "not_needed" unless needed?
616       flags.empty? ? "" : "(" + flags.join(", ") + ")"
617     end
618     private :format_trace_flags
619 
620     # Execute the actions associated with this task.
621     def execute(args=nil)
622       args ||= EMPTY_TASK_ARGS
623       if application.options.dryrun
624         puts "** Execute (dry run) #{name}"
625         return
626       end
627       if application.options.trace
628         puts "** Execute #{name}"
629       end
630       application.enhance_with_matching_rule(name) if @actions.empty?
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
639     end
640 
641     # Is this task needed?
642     def needed?
643       true
644     end
645 
646     # Timestamp for this task.  Basic tasks return the current time for their
647     # time stamp.  Other tasks can be more sophisticated.
648     def timestamp
649       @prerequisites.collect { |p| application[p].timestamp }.max || Time.now
650     end
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 
665     # Add a comment to the task.  If a comment alread exists, separate
666     # the new comment with " / ".
667     def add_comment(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
676       else
677         @comment = @full_comment
678       end
679     end
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 
688     # Return a string describing the internal state of a task.  Useful for
689     # debugging.
690     def investigation
691       result = "------------------------------\n"
692       result << "Investigating #{name}\n"
693       result << "class: #{self.class}\n"
694       result <<  "task needed: #{needed?}\n"
695       result <<  "timestamp: #{timestamp}\n"
696       result << "pre-requisites: \n"
697       prereqs = @prerequisites.collect {|name| application[name]}
698       prereqs.sort! {|a,b| a.timestamp <=> b.timestamp}
699       prereqs.each do |p|
700         result << "--#{p.name} (#{p.timestamp})\n"
701       end
702       latest_prereq = @prerequisites.collect{|n| application[n].timestamp}.max
703       result <<  "latest-prerequisite time: #{latest_prereq}\n"
704       result << "................................\n\n"
705       return result
706     end
707 
708     # ----------------------------------------------------------------
709     # Rake Module Methods
710     #
711     class << self
712 
713       # Clear the task list.  This cause rake to immediately forget all the
714       # tasks that have been assigned.  (Normally used in the unit tests.)
715       def clear
716         Rake.application.clear
717       end
718 
719       # List of all defined tasks.
720       def tasks
721         Rake.application.tasks
722       end
723 
724       # Return a task with the given name.  If the task is not currently
725       # known, try to synthesize one from the defined rules.  If no rules are
726       # found, but an existing file matches the task name, assume it is a file
727       # task with no dependencies or actions.
728       def [](task_name)
729         Rake.application[task_name]
730       end
731 
732       # TRUE if the task name is already defined.
733       def task_defined?(task_name)
734         Rake.application.lookup(task_name) != nil
735       end
736 
737       # Define a task given +args+ and an option block.  If a rule with the
738       # given name already exists, the prerequisites and actions are added to
739       # the existing task.  Returns the defined task.
740       def define_task(*args, &block)
741         Rake.application.define_task(self, *args, &block)
742       end
743 
744       # Define a rule for synthesizing tasks.
745       def create_rule(*args, &block)
746         Rake.application.create_rule(*args, &block)
747       end
748 
749       # Apply the scope to the task name according to the rules for
750       # this kind of task.  Generic tasks will accept the scope as
751       # part of the name.
752       def scope_name(scope, task_name)
753         (scope + [task_name]).join(':')
754       end
755 
756     end # class << Rake::Task
757   end # class Rake::Task
758 
759 
760   ###########################################################################
761   # A FileTask is a task that includes time based dependencies.  If any of a
762   # FileTask's prerequisites have a timestamp that is later than the file
763   # represented by this task, then the file must be rebuilt (using the
764   # supplied actions).
765   #
766   class FileTask < Task
767 
768     # Is this file task needed?  Yes if it doesn't exist, or if its time stamp
769     # is out of date.
770     def needed?
771       ! File.exist?(name) || out_of_date?(timestamp)
772     end
773 
774     # Time stamp for file task.
775     def timestamp
776       if File.exist?(name)
777         File.mtime(name.to_s)
778       else
779         Rake::EARLY
780       end
781     end
782 
783     private
784 
785     # Are there any prerequisites with a later time than the given time stamp?
786     def out_of_date?(stamp)
787       @prerequisites.any? { |n| application[n].timestamp > stamp}
788     end
789 
790     # ----------------------------------------------------------------
791     # Task class methods.
792     #
793     class << self
794       # Apply the scope to the task name according to the rules for this kind
795       # of task.  File based tasks ignore the scope when creating the name.
796       def scope_name(scope, task_name)
797         task_name
798       end
799     end
800   end # class Rake::FileTask
801 
802   ###########################################################################
803   # A FileCreationTask is a file task that when used as a dependency will be
804   # needed if and only if the file has not been created.  Once created, it is
805   # not re-triggered if any of its dependencies are newer, nor does trigger
806   # any rebuilds of tasks that depend on it whenever it is updated.
807   #
808   class FileCreationTask < FileTask
809     # Is this file task needed?  Yes if it doesn't exist.
810     def needed?
811       ! File.exist?(name)
812     end
813 
814     # Time stamp for file creation task.  This time stamp is earlier
815     # than any other time stamp.
816     def timestamp
817       Rake::EARLY
818     end
819   end
820 
821   ###########################################################################
822   # Same as a regular task, but the immediate prerequisites are done in
823   # parallel using Ruby threads.
824   #
825   class MultiTask < Task
826     private
827     def invoke_prerequisites(args, invocation_chain)
828       threads = @prerequisites.collect { |p|
829         Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
830       }
831       threads.each { |t| t.join }
832     end
833   end
834 end # module Rake
835 
836 ## ###########################################################################
837 # Task Definition Functions ...
838 
839 # Declare a basic task.
840 #
841 # Example:
842 #   task :clobber => [:clean] do
843 #     rm_rf "html"
844 #   end
845 #
846 def task(*args, &block)
847   Rake::Task.define_task(*args, &block)
848 end
849 
850 
851 # Declare a file task.
852 #
853 # Example:
854 #   file "config.cfg" => ["config.template"] do
855 #     open("config.cfg", "w") do |outfile|
856 #       open("config.template") do |infile|
857 #         while line = infile.gets
858 #           outfile.puts line
859 #         end
860 #       end
861 #     end
862 #  end
863 #
864 def file(*args, &block)
865   Rake::FileTask.define_task(*args, &block)
866 end
867 
868 # Declare a file creation task.
869 # (Mainly used for the directory command).
870 def file_create(args, &block)
871   Rake::FileCreationTask.define_task(args, &block)
872 end
873 
874 # Declare a set of files tasks to create the given directories on demand.
875 #
876 # Example:
877 #   directory "testdata/doc"
878 #
879 def directory(dir)
880   Rake.each_dir_parent(dir) do |d|
881     file_create d do |t|
882       mkdir_p t.name if ! File.exist?(t.name)
883     end
884   end
885 end
886 
887 # Declare a task that performs its prerequisites in parallel. Multitasks does
888 # *not* guarantee that its prerequisites will execute in any given order
889 # (which is obvious when you think about it)
890 #
891 # Example:
892 #   multitask :deploy => [:deploy_gem, :deploy_rdoc]
893 #
894 def multitask(args, &block)
895   Rake::MultiTask.define_task(args, &block)
896 end
897 
898 # Create a new rake namespace and use it for evaluating the given block.
899 # Returns a NameSpace object that can be used to lookup tasks defined in the
900 # namespace.
901 #
902 # E.g.
903 #
904 #   ns = namespace "nested" do
905 #     task :run
906 #   end
907 #   task_run = ns[:run] # find :run in the given namespace.
908 #
909 def namespace(name=nil, &block)
910   Rake.application.in_namespace(name, &block)
911 end
912 
913 # Declare a rule for auto-tasks.
914 #
915 # Example:
916 #  rule '.o' => '.c' do |t|
917 #    sh %{cc -o #{t.name} #{t.source}}
918 #  end
919 #
920 def rule(*args, &block)
921   Rake::Task.create_rule(*args, &block)
922 end
923 
924 # Describe the next rake task.
925 #
926 # Example:
927 #   desc "Run the Unit Tests"
928 #   task :test => [:build]
929 #     runtests
930 #   end
931 #
932 def desc(description)
933   Rake.application.last_description = description
934 end
935 
936 # Import the partial Rakefiles +fn+.  Imported files are loaded _after_ the
937 # current file is completely loaded.  This allows the import statement to
938 # appear anywhere in the importing file, and yet allowing the imported files
939 # to depend on objects defined in the importing file.
940 #
941 # A common use of the import statement is to include files containing
942 # dependency declarations.
943 #
944 # See also the --rakelibdir command line option.
945 #
946 # Example:
947 #   import ".depend", "my_rules"
948 #
949 def import(*fns)
950   fns.each do |fn|
951     Rake.application.add_import(fn)
952   end
953 end
954 
955 #############################################################################
956 # This a FileUtils extension that defines several additional commands to be
957 # added to the FileUtils utility functions.
958 #
959 module FileUtils
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, '"\&"')
968 
969   OPT_TABLE['sh']  = %w(noop verbose)
970   OPT_TABLE['ruby'] = %w(noop verbose)
971 
972   # Run the system command +cmd+. If multiple arguments are given the command
973   # is not run with the shell (same semantics as Kernel::exec and
974   # Kernel::system).
975   #
976   # Example:
977   #   sh %{ls -ltr}
978   #
979   #   sh 'ls', 'file with spaces'
980   #
981   #   # check exit status after command runs
982   #   sh %{grep pattern file} do |ok, res|
983   #     if ! ok
984   #       puts "pattern not found (status = #{res.exitstatus})"
985   #     end
986   #   end
987   #
988   def sh(*cmd, &block)
989     options = (Hash === cmd.last) ? cmd.pop : {}
990     unless block_given?
991       show_command = cmd.join(" ")
992       show_command = show_command[0,42] + "..." unless $trace
993       # TODO code application logic heref show_command.length > 45
994       block = lambda { |ok, status|
995         ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
996       }
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
1004     rake_check_options options, :noop, :verbose
1005     rake_output_message cmd.join(" ") if options[:verbose]
1006     unless options[:noop]
1007       res = rake_system(*cmd)
1008       status = $?
1009       status = PseudoStatus.new(1) if !res && status.nil?
1010       block.call(res, status)
1011     end
1012   end
1013 
1014   def rake_system(*cmd)
1015     Rake::AltSystem.system(*cmd)
1016   end
1017   private :rake_system
1018 
1019   # Run a Ruby interpreter with the given arguments.
1020   #
1021   # Example:
1022   #   ruby %{-pe '$_.upcase!' <README}
1023   #
1024   def ruby(*args,&block)
1025     options = (Hash === args.last) ? args.pop : {}
1026     if args.length > 1 then
1027       sh(*([RUBY] + args + [options]), &block)
1028     else
1029       sh("#{RUBY} #{args.first}", options, &block)
1030     end
1031   end
1032 
1033   LN_SUPPORTED = [true]
1034 
1035   #  Attempt to do a normal file link, but fall back to a copy if the link
1036   #  fails.
1037   def safe_ln(*args)
1038     unless LN_SUPPORTED[0]
1039       cp(*args)
1040     else
1041       begin
1042         ln(*args)
1043       rescue StandardError, NotImplementedError => ex
1044         LN_SUPPORTED[0] = false
1045         cp(*args)
1046       end
1047     end
1048   end
1049 
1050   # Split a file path into individual directory names.
1051   #
1052   # Example:
1053   #   split_all("a/b/c") =>  ['a', 'b', 'c']
1054   #
1055   def split_all(path)
1056     head, tail = File.split(path)
1057     return [tail] if head == '.' || tail == '/'
1058     return [head, tail] if head == '/'
1059     return split_all(head) + [tail]
1060   end
1061 end
1062 
1063 #############################################################################
1064 # RakeFileUtils provides a custom version of the FileUtils methods that
1065 # respond to the <tt>verbose</tt> and <tt>nowrite</tt> commands.
1066 #
1067 module RakeFileUtils
1068   include FileUtils
1069 
1070   class << self
1071     attr_accessor :verbose_flag, :nowrite_flag
1072   end
1073   RakeFileUtils.verbose_flag = :default
1074   RakeFileUtils.nowrite_flag = false
1075 
1076   $fileutils_verbose = true
1077   $fileutils_nowrite = false
1078 
1079   FileUtils::OPT_TABLE.each do |name, opts|
1080     default_options = []
1081     if opts.include?(:verbose) || opts.include?("verbose")
1082       default_options << ':verbose => RakeFileUtils.verbose_flag'
1083     end
1084     if opts.include?(:noop) || opts.include?("noop")
1085       default_options << ':noop => RakeFileUtils.nowrite_flag'
1086     end
1087 
1088     next if default_options.empty?
1089     module_eval(<<-EOS, __FILE__, __LINE__ + 1)
1090     def #{name}( *args, &block )
1091       super(
1092         *rake_merge_option(args,
1093           #{default_options.join(', ')}
1094           ), &block)
1095     end
1096     EOS
1097   end
1098 
1099   # Get/set the verbose flag controlling output from the FileUtils utilities.
1100   # If verbose is true, then the utility method is echoed to standard output.
1101   #
1102   # Examples:
1103   #    verbose              # return the current value of the verbose flag
1104   #    verbose(v)           # set the verbose flag to _v_.
1105   #    verbose(v) { code }  # Execute code with the verbose flag set temporarily to _v_.
1106   #                         # Return to the original value when code is done.
1107   def verbose(value=nil)
1108     oldvalue = RakeFileUtils.verbose_flag
1109     RakeFileUtils.verbose_flag = value unless value.nil?
1110     if block_given?
1111       begin
1112         yield
1113       ensure
1114         RakeFileUtils.verbose_flag = oldvalue
1115       end
1116     end
1117     RakeFileUtils.verbose_flag
1118   end
1119 
1120   # Get/set the nowrite flag controlling output from the FileUtils utilities.
1121   # If verbose is true, then the utility method is echoed to standard output.
1122   #
1123   # Examples:
1124   #    nowrite              # return the current value of the nowrite flag
1125   #    nowrite(v)           # set the nowrite flag to _v_.
1126   #    nowrite(v) { code }  # Execute code with the nowrite flag set temporarily to _v_.
1127   #                         # Return to the original value when code is done.
1128   def nowrite(value=nil)
1129     oldvalue = RakeFileUtils.nowrite_flag
1130     RakeFileUtils.nowrite_flag = value unless value.nil?
1131     if block_given?
1132       begin
1133         yield
1134       ensure
1135         RakeFileUtils.nowrite_flag = oldvalue
1136       end
1137     end
1138     oldvalue
1139   end
1140 
1141   # Use this function to prevent protentially destructive ruby code from
1142   # running when the :nowrite flag is set.
1143   #
1144   # Example:
1145   #
1146   #   when_writing("Building Project") do
1147   #     project.build
1148   #   end
1149   #
1150   # The following code will build the project under normal conditions. If the
1151   # nowrite(true) flag is set, then the example will print:
1152   #      DRYRUN: Building Project
1153   # instead of actually building the project.
1154   #
1155   def when_writing(msg=nil)
1156     if RakeFileUtils.nowrite_flag
1157       puts "DRYRUN: #{msg}" if msg
1158     else
1159       yield
1160     end
1161   end
1162 
1163   # Merge the given options with the default values.
1164   def rake_merge_option(args, defaults)
1165     if Hash === args.last
1166       defaults.update(args.last)
1167       args.pop
1168     end
1169     args.push defaults
1170     args
1171   end
1172   private :rake_merge_option
1173 
1174   # Send the message to the default rake output (which is $stderr).
1175   def rake_output_message(message)
1176     $stderr.puts(message)
1177   end
1178   private :rake_output_message
1179 
1180   # Check that the options do not contain options not listed in +optdecl+.  An
1181   # ArgumentError exception is thrown if non-declared options are found.
1182   def rake_check_options(options, *optdecl)
1183     h = options.dup
1184     optdecl.each do |name|
1185       h.delete name
1186     end
1187     raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
1188   end
1189   private :rake_check_options
1190 
1191   extend self
1192 end
1193 
1194 #############################################################################
1195 # Include the FileUtils file manipulation functions in the top level module,
1196 # but mark them private so that they don't unintentionally define methods on
1197 # other objects.
1198 
1199 include RakeFileUtils
1200 private(*FileUtils.instance_methods(false))
1201 private(*RakeFileUtils.instance_methods(false))
1202 
1203 ######################################################################
1204 module Rake
1205 
1206   ###########################################################################
1207   # A FileList is essentially an array with a few helper methods defined to
1208   # make file manipulation a bit easier.
1209   #
1210   # FileLists are lazy.  When given a list of glob patterns for possible files
1211   # to be included in the file list, instead of searching the file structures
1212   # to find the files, a FileList holds the pattern for latter use.
1213   #
1214   # This allows us to define a number of FileList to match any number of
1215   # files, but only search out the actual files when then FileList itself is
1216   # actually used.  The key is that the first time an element of the
1217   # FileList/Array is requested, the pending patterns are resolved into a real
1218   # list of file names.
1219   #
1220   class FileList
1221 
1222     include Cloneable
1223 
1224     # == Method Delegation
1225     #
1226     # The lazy evaluation magic of FileLists happens by implementing all the
1227     # array specific methods to call +resolve+ before delegating the heavy
1228     # lifting to an embedded array object (@items).
1229     #
1230     # In addition, there are two kinds of delegation calls.  The regular kind
1231     # delegates to the @items array and returns the result directly.  Well,
1232     # almost directly.  It checks if the returned value is the @items object
1233     # itself, and if so will return the FileList object instead.
1234     #
1235     # The second kind of delegation call is used in methods that normally
1236     # return a new Array object.  We want to capture the return value of these
1237     # methods and wrap them in a new FileList object.  We enumerate these
1238     # methods in the +SPECIAL_RETURN+ list below.
1239 
1240     # List of array methods (that are not in +Object+) that need to be
1241     # delegated.
1242     ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
1243 
1244     # List of additional methods that must be delegated.
1245     MUST_DEFINE = %w[to_a inspect]
1246 
1247     # List of methods that should not be delegated here (we define special
1248     # versions of them explicitly below).
1249     MUST_NOT_DEFINE = %w[to_a to_ary partition *]
1250 
1251     # List of delegated methods that return new array values which need
1252     # wrapping.
1253     SPECIAL_RETURN = %w[
1254       map collect sort sort_by select find_all reject grep
1255       compact flatten uniq values_at
1256       + - & |
1257     ]
1258 
1259     DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
1260 
1261     # Now do the delegation.
1262     DELEGATING_METHODS.each_with_index do |sym, i|
1263       if SPECIAL_RETURN.include?(sym)
1264         ln = __LINE__+1
1265         class_eval %{
1266           def #{sym}(*args, &block)
1267             resolve
1268             result = @items.send(:#{sym}, *args, &block)
1269             FileList.new.import(result)
1270           end
1271         }, __FILE__, ln
1272       else
1273         ln = __LINE__+1
1274         class_eval %{
1275           def #{sym}(*args, &block)
1276             resolve
1277             result = @items.send(:#{sym}, *args, &block)
1278             result.object_id == @items.object_id ? self : result
1279           end
1280         }, __FILE__, ln
1281       end
1282     end
1283 
1284     # Create a file list from the globbable patterns given.  If you wish to
1285     # perform multiple includes or excludes at object build time, use the
1286     # "yield self" pattern.
1287     #
1288     # Example:
1289     #   file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
1290     #
1291     #   pkg_files = FileList.new('lib/**/*') do |fl|
1292     #     fl.exclude(/\bCVS\b/)
1293     #   end
1294     #
1295     def initialize(*patterns)
1296       @pending_add = []
1297       @pending = false
1298       @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1299       @exclude_procs = DEFAULT_IGNORE_PROCS.dup
1300       @exclude_re = nil
1301       @items = []
1302       patterns.each { |pattern| include(pattern) }
1303       yield self if block_given?
1304     end
1305 
1306     # Add file names defined by glob patterns to the file list.  If an array
1307     # is given, add each element of the array.
1308     #
1309     # Example:
1310     #   file_list.include("*.java", "*.cfg")
1311     #   file_list.include %w( math.c lib.h *.o )
1312     #
1313     def include(*filenames)
1314       # TODO: check for pending
1315       filenames.each do |fn|
1316         if fn.respond_to? :to_ary
1317           include(*fn.to_ary)
1318         else
1319           @pending_add << fn
1320         end
1321       end
1322       @pending = true
1323       self
1324     end
1325     alias :add :include
1326 
1327     # Register a list of file name patterns that should be excluded from the
1328     # list.  Patterns may be regular expressions, glob patterns or regular
1329     # strings.  In addition, a block given to exclude will remove entries that
1330     # return true when given to the block.
1331     #
1332     # Note that glob patterns are expanded against the file system. If a file
1333     # is explicitly added to a file list, but does not exist in the file
1334     # system, then an glob pattern in the exclude list will not exclude the
1335     # file.
1336     #
1337     # Examples:
1338     #   FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
1339     #   FileList['a.c', 'b.c'].exclude(/^a/)  => ['b.c']
1340     #
1341     # If "a.c" is a file, then ...
1342     #   FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
1343     #
1344     # If "a.c" is not a file, then ...
1345     #   FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
1346     #
1347     def exclude(*patterns, &block)
1348       patterns.each do |pat|
1349         @exclude_patterns << pat
1350       end
1351       if block_given?
1352         @exclude_procs << block
1353       end
1354       resolve_exclude if ! @pending
1355       self
1356     end
1357 
1358 
1359     # Clear all the exclude patterns so that we exclude nothing.
1360     def clear_exclude
1361       @exclude_patterns = []
1362       @exclude_procs = []
1363       calculate_exclude_regexp if ! @pending
1364       self
1365     end
1366 
1367     # Define equality.
1368     def ==(array)
1369       to_ary == array
1370     end
1371 
1372     # Return the internal array object.
1373     def to_a
1374       resolve
1375       @items
1376     end
1377 
1378     # Return the internal array object.
1379     def to_ary
1380       to_a
1381     end
1382 
1383     # Lie about our class.
1384     def is_a?(klass)
1385       klass == Array || super(klass)
1386     end
1387     alias kind_of? is_a?
1388 
1389     # Redefine * to return either a string or a new file list.
1390     def *(other)
1391       result = @items * other
1392       case result
1393       when Array
1394         FileList.new.import(result)
1395       else
1396         result
1397       end
1398     end
1399 
1400     # Resolve all the pending adds now.
1401     def resolve
1402       if @pending
1403         @pending = false
1404         @pending_add.each do |fn| resolve_add(fn) end
1405         @pending_add = []
1406         resolve_exclude
1407       end
1408       self
1409     end
1410 
1411     def calculate_exclude_regexp
1412       ignores = []
1413       @exclude_patterns.each do |pat|
1414         case pat
1415         when Regexp
1416           ignores << pat
1417         when /[*?]/
1418           Dir[pat].each do |p| ignores << p end
1419         else
1420           ignores << Regexp.quote(pat)
1421         end
1422       end
1423       if ignores.empty?
1424         @exclude_re = /^$/
1425       else
1426         re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
1427         @exclude_re = Regexp.new(re_str)
1428       end
1429     end
1430 
1431     def resolve_add(fn)
1432       case fn
1433       when %r{[*?\[\{]}
1434         add_matching(fn)
1435       else
1436         self << fn
1437       end
1438     end
1439     private :resolve_add
1440 
1441     def resolve_exclude
1442       calculate_exclude_regexp
1443       reject! { |fn| exclude?(fn) }
1444       self
1445     end
1446     private :resolve_exclude
1447 
1448     # Return a new FileList with the results of running +sub+ against each
1449     # element of the oringal list.
1450     #
1451     # Example:
1452     #   FileList['a.c', 'b.c'].sub(/\.c$/, '.o')  => ['a.o', 'b.o']
1453     #
1454     def sub(pat, rep)
1455       inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
1456     end
1457 
1458     # Return a new FileList with the results of running +gsub+ against each
1459     # element of the original list.
1460     #
1461     # Example:
1462     #   FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
1463     #      => ['lib\\test\\file', 'x\\y']
1464     #
1465     def gsub(pat, rep)
1466       inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
1467     end
1468 
1469     # Same as +sub+ except that the oringal file list is modified.
1470     def sub!(pat, rep)
1471       each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
1472       self
1473     end
1474 
1475     # Same as +gsub+ except that the original file list is modified.
1476     def gsub!(pat, rep)
1477       each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
1478       self
1479     end
1480 
1481     # Apply the pathmap spec to each of the included file names, returning a
1482     # new file list with the modified paths.  (See String#pathmap for
1483     # details.)
1484     def pathmap(spec=nil)
1485       collect { |fn| fn.pathmap(spec) }
1486     end
1487 
1488     # Return a new FileList with <tt>String#ext</tt> method applied
1489     # to each member of the array.
1490     #
1491     # This method is a shortcut for:
1492     #
1493     #    array.collect { |item| item.ext(newext) }
1494     #
1495     # +ext+ is a user added method for the Array class.
1496     def ext(newext='')
1497       collect { |fn| fn.ext(newext) }
1498     end
1499 
1500 
1501     # Grep each of the files in the filelist using the given pattern. If a
1502     # block is given, call the block on each matching line, passing the file
1503     # name, line number, and the matching line of text.  If no block is given,
1504     # a standard emac style file:linenumber:line message will be printed to
1505     # standard out.
1506     def egrep(pattern, *options)
1507       each do |fn|
1508         open(fn, "rb", *options) do |inf|
1509           count = 0
1510           inf.each do |line|
1511             count += 1
1512             if pattern.match(line)
1513               if block_given?
1514                 yield fn, count, line
1515               else
1516                 puts "#{fn}:#{count}:#{line}"
1517               end
1518             end
1519           end
1520         end
1521       end
1522     end
1523 
1524     # Return a new file list that only contains file names from the current
1525     # file list that exist on the file system.
1526     def existing
1527       select { |fn| File.exist?(fn) }
1528     end
1529 
1530     # Modify the current file list so that it contains only file name that
1531     # exist on the file system.
1532     def existing!
1533       resolve
1534       @items = @items.select { |fn| File.exist?(fn) }
1535       self
1536     end
1537 
1538     # FileList version of partition.  Needed because the nested arrays should
1539     # be FileLists in this version.
1540     def partition(&block)       # :nodoc:
1541       resolve
1542       result = @items.partition(&block)
1543       [
1544         FileList.new.import(result[0]),
1545         FileList.new.import(result[1]),
1546       ]
1547     end
1548 
1549     # Convert a FileList to a string by joining all elements with a space.
1550     def to_s
1551       resolve
1552       self.join(' ')
1553     end
1554 
1555     # Add matching glob patterns.
1556     def add_matching(pattern)
1557       Dir[pattern].each do |fn|
1558         self << fn unless exclude?(fn)
1559       end
1560     end
1561     private :add_matching
1562 
1563     # Should the given file name be excluded?
1564     def exclude?(fn)
1565       calculate_exclude_regexp unless @exclude_re
1566       fn =~ @exclude_re || @exclude_procs.any? { |p| p.call(fn) }
1567     end
1568 
1569     DEFAULT_IGNORE_PATTERNS = [
1570       /(^|[\/\\])CVS([\/\\]|$)/,
1571       /(^|[\/\\])\.svn([\/\\]|$)/,
1572       /\.bak$/,
1573       /~$/
1574     ]
1575     DEFAULT_IGNORE_PROCS = [
1576       proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
1577     ]
1578 #    @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1579 
1580     def import(array)
1581       @items = array
1582       self
1583     end
1584 
1585     class << self
1586       # Create a new file list including the files listed. Similar to:
1587       #
1588       #   FileList.new(*args)
1589       def [](*args)
1590         new(*args)
1591       end
1592     end
1593   end # FileList
1594 end
1595 
1596 module Rake
1597   class << self
1598 
1599     # Yield each file or directory component.
1600     def each_dir_parent(dir)    # :nodoc:
1601       old_length = nil
1602       while dir != '.' && dir.length != old_length
1603         yield(dir)
1604         old_length = dir.length
1605         dir = File.dirname(dir)
1606       end
1607     end
1608   end
1609 end # module Rake
1610 
1611 # Alias FileList to be available at the top level.
1612 FileList = Rake::FileList
1613 
1614 #############################################################################
1615 module Rake
1616 
1617   # Default Rakefile loader used by +import+.
1618   class DefaultLoader
1619     def load(fn)
1620       Kernel.load(File.expand_path(fn))
1621     end
1622   end
1623 
1624   # EarlyTime is a fake timestamp that occurs _before_ any other time value.
1625   class EarlyTime
1626     include Comparable
1627     include Singleton
1628 
1629     def <=>(other)
1630       -1
1631     end
1632 
1633     def to_s
1634       "<EARLY TIME>"
1635     end
1636   end
1637 
1638   EARLY = EarlyTime.instance
1639 end # module Rake
1640 
1641 #############################################################################
1642 # Extensions to time to allow comparisons with an early time class.
1643 #
1644 class Time
1645   alias rake_original_time_compare :<=>
1646   def <=>(other)
1647     if Rake::EarlyTime === other
1648       - other.<=>(self)
1649     else
1650       rake_original_time_compare(other)
1651     end
1652   end
1653 end # class Time
1654 
1655 module Rake
1656 
1657   ####################################################################
1658   # The NameSpace class will lookup task names in the the scope
1659   # defined by a +namespace+ command.
1660   #
1661   class NameSpace
1662 
1663     # Create a namespace lookup object using the given task manager
1664     # and the list of scopes.
1665     def initialize(task_manager, scope_list)
1666       @task_manager = task_manager
1667       @scope = scope_list.dup
1668     end
1669 
1670     # Lookup a task named +name+ in the namespace.
1671     def [](name)
1672       @task_manager.lookup(name, @scope)
1673     end
1674 
1675     # Return the list of tasks defined in this and nested namespaces.
1676     def tasks
1677       @task_manager.tasks_in_scope(@scope)
1678     end
1679   end # NameSpace
1680 
1681 
1682   ####################################################################
1683   # The TaskManager module is a mixin for managing tasks.
1684   module TaskManager
1685     # Track the last comment made in the Rakefile.
1686     attr_accessor :last_description
1687     alias :last_comment :last_description    # Backwards compatibility
1688 
1689     def initialize
1690       super
1691       @tasks = Hash.new
1692       @rules = Array.new
1693       @scope = Array.new
1694       @last_description = nil
1695     end
1696 
1697     def create_rule(*args, &block)
1698       pattern, arg_names, deps = resolve_args(args)
1699       pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
1700       @rules << [pattern, deps, block]
1701     end
1702 
1703     def define_task(task_class, *args, &block)
1704       task_name, arg_names, deps = resolve_args(args)
1705       task_name = task_class.scope_name(@scope, task_name)
1706       deps = [deps] unless deps.respond_to?(:to_ary)
1707       deps = deps.collect {|d| d.to_s }
1708       task = intern(task_class, task_name)
1709       task.set_arg_names(arg_names) unless arg_names.empty?
1710       task.add_description(@last_description)
1711       @last_description = nil
1712       task.enhance(deps, &block)
1713       task
1714     end
1715 
1716     # Lookup a task.  Return an existing task if found, otherwise
1717     # create a task of the current type.
1718     def intern(task_class, task_name)
1719       @tasks[task_name.to_s] ||= task_class.new(task_name, self)
1720     end
1721 
1722     # Find a matching task for +task_name+.
1723     def [](task_name, scopes=nil)
1724       task_name = task_name.to_s
1725       self.lookup(task_name, scopes) or
1726         enhance_with_matching_rule(task_name) or
1727         synthesize_file_task(task_name) or
1728         fail "Don't know how to build task '#{task_name}'"
1729     end
1730 
1731     def synthesize_file_task(task_name)
1732       return nil unless File.exist?(task_name)
1733       define_task(Rake::FileTask, task_name)
1734     end
1735 
1736     # Resolve the arguments for a task/rule.  Returns a triplet of
1737     # [task_name, arg_name_list, prerequisites].
1738     def resolve_args(args)
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
1788       else
1789         task_name = args.shift
1790         arg_names = key
1791         deps = value
1792       end
1793       deps = [deps] unless deps.respond_to?(:to_ary)
1794       [task_name, arg_names, deps]
1795     end
1796     private :resolve_args_with_dependencies
1797     
1798     # If a rule can be found that matches the task name, enhance the
1799     # task with the prerequisites and actions from the rule.  Set the
1800     # source attribute of the task appropriately for the rule.  Return
1801     # the enhanced task or nil of no rule was found.
1802     def enhance_with_matching_rule(task_name, level=0)
1803       fail Rake::RuleRecursionOverflowError,
1804         "Rule Recursion Too Deep" if level >= 16
1805       @rules.each do |pattern, extensions, block|
1806         if md = pattern.match(task_name)
1807           task = attempt_rule(task_name, extensions, block, level)
1808           return task if task
1809         end
1810       end
1811       nil
1812     rescue Rake::RuleRecursionOverflowError => ex
1813       ex.add_target(task_name)
1814       fail ex
1815     end
1816 
1817     # List of all defined tasks in this application.
1818     def tasks
1819       @tasks.values.sort_by { |t| t.name }
1820     end
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 
1831     # Clear all tasks in this application.
1832     def clear
1833       @tasks.clear
1834       @rules.clear
1835     end
1836 
1837     # Lookup a task, using scope and the scope hints in the task name.
1838     # This method performs straight lookups without trying to
1839     # synthesize file tasks or rules.  Special scope names (e.g. '^')
1840     # are recognized.  If no scope argument is supplied, use the
1841     # current scope.  Return nil if the task cannot be found.
1842     def lookup(task_name, initial_scope=nil)
1843       initial_scope ||= @scope
1844       task_name = task_name.to_s
1845       if task_name =~ /^rake:/
1846         scopes = []
1847         task_name = task_name.sub(/^rake:/, '')
1848       elsif task_name =~ /^(\^+)/
1849         scopes = initial_scope[0, initial_scope.size - $1.size]
1850         task_name = task_name.sub(/^(\^+)/, '')
1851       else
1852         scopes = initial_scope
1853       end
1854       lookup_in_scope(task_name, scopes)
1855     end
1856 
1857     # Lookup the task name
1858     def lookup_in_scope(name, scope)
1859       n = scope.size
1860       while n >= 0
1861         tn = (scope[0,n] + [name]).join(':')
1862         task = @tasks[tn]
1863         return task if task
1864         n -= 1
1865       end
1866       nil
1867     end
1868     private :lookup_in_scope
1869 
1870     # Return the list of scope names currently active in the task
1871     # manager.
1872     def current_scope
1873       @scope.dup
1874     end
1875 
1876     # Evaluate the block in a nested namespace named +name+.  Create
1877     # an anonymous namespace if +name+ is nil.
1878     def in_namespace(name)
1879       name ||= generate_name
1880       @scope.push(name)
1881       ns = NameSpace.new(self, @scope)
1882       yield(ns)
1883       ns
1884     ensure
1885       @scope.pop
1886     end
1887 
1888     private
1889 
1890     # Generate an anonymous namespace name.
1891     def generate_name
1892       @seed ||= 0
1893       @seed += 1
1894       "_anon_#{@seed}"
1895     end
1896 
1897     def trace_rule(level, message)
1898       puts "#{"    "*level}#{message}" if Rake.application.options.trace_rules
1899     end
1900 
1901     # Attempt to create a rule given the list of prerequisites.
1902     def attempt_rule(task_name, extensions, block, level)
1903       sources = make_sources(task_name, extensions)
1904       prereqs = sources.collect { |source|
1905         trace_rule level, "Attempting Rule #{task_name} => #{source}"
1906         if File.exist?(source) || Rake::Task.task_defined?(source)
1907           trace_rule level, "(#{task_name} => #{source} ... EXIST)"
1908           source
1909         elsif parent = enhance_with_matching_rule(source, level+1)
1910           trace_rule level, "(#{task_name} => #{source} ... ENHANCE)"
1911           parent.name
1912         else
1913           trace_rule level, "(#{task_name} => #{source} ... FAIL)"
1914           return nil
1915         end
1916       }
1917       task = FileTask.define_task({task_name => prereqs}, &block)
1918       task.sources = prereqs
1919       task
1920     end
1921 
1922     # Make a list of sources from the list of file name extensions /
1923     # translation procs.
1924     def make_sources(task_name, extensions)
1925       extensions.collect { |ext|
1926         case ext
1927         when /%/
1928           task_name.pathmap(ext)
1929         when %r{/}
1930           ext
1931         when /^\./
1932           task_name.ext(ext)
1933         when String
1934           ext
1935         when Proc
1936           if ext.arity == 1
1937             ext.call(task_name)
1938           else
1939             ext.call
1940           end
1941         else
1942           fail "Don't know how to handle rule dependent: #{ext.inspect}"
1943         end
1944       }.flatten
1945     end
1946 
1947   end # TaskManager
1948 
1949   ######################################################################
1950   # Rake main application object.  When invoking +rake+ from the
1951   # command line, a Rake::Application object is created and run.
1952   #
1953   class Application
1954     include TaskManager
1955 
1956     # The name of the application (typically 'rake')
1957     attr_reader :name
1958 
1959     # The original directory where rake was invoked.
1960     attr_reader :original_dir
1961 
1962     # Name of the actual rakefile used.
1963     attr_reader :rakefile
1964 
1965     # List of the top level task names (task names from the command line).
1966     attr_reader :top_level_tasks
1967 
1968     DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
1969 
1970     # Initialize a Rake::Application object.
1971     def initialize
1972       super
1973       @name = 'rake'
1974       @rakefiles = DEFAULT_RAKEFILES.dup
1975       @rakefile = nil
1976       @pending_imports = []
1977       @imported = []
1978       @loaders = {}
1979       @default_loader = Rake::DefaultLoader.new
1980       @original_dir = Dir.pwd
1981       @top_level_tasks = []
1982       add_loader('rb', DefaultLoader.new)
1983       add_loader('rf', DefaultLoader.new)
1984       add_loader('rake', DefaultLoader.new)
1985       @tty_output = STDOUT.tty?
1986     end
1987 
1988     # Run the Rake application.  The run method performs the following three steps:
1989     #
1990     # * Initialize the command line options (+init+).
1991     # * Define the tasks (+load_rakefile+).
1992     # * Run the top level tasks (+run_tasks+).
1993     #
1994     # If you wish to build a custom rake command, you should call +init+ on your
1995     # application.  The define any tasks.  Finally, call +top_level+ to run your top
1996     # level tasks.
1997     def run
1998       standard_exception_handling do
1999         init
2000         load_rakefile
2001         top_level
2002       end
2003     end
2004 
2005     # Initialize the command line parameters and app name.
2006     def init(app_name='rake')
2007       standard_exception_handling do
2008         @name = app_name
2009         handle_options
2010         collect_tasks
2011       end
2012     end
2013 
2014     # Find the rakefile and then load it and any pending imports.
2015     def load_rakefile
2016       standard_exception_handling do
2017         raw_load_rakefile
2018       end
2019     end
2020 
2021     # Run the top level tasks of a Rake application.
2022     def top_level
2023       standard_exception_handling do
2024         if options.show_tasks
2025           display_tasks_and_comments
2026         elsif options.show_prereqs
2027           display_prerequisites
2028         else
2029           top_level_tasks.each { |task_name| invoke_task(task_name) }
2030         end
2031       end
2032     end
2033 
2034     # Add a loader to handle imported files ending in the extension
2035     # +ext+.
2036     def add_loader(ext, loader)
2037       ext = ".#{ext}" unless ext =~ /^\./
2038       @loaders[ext] = loader
2039     end
2040 
2041     # Application options from the command line
2042     def options
2043       @options ||= OpenStruct.new
2044     end
2045 
2046     # private ----------------------------------------------------------------
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 
2065     # Provide standard execption handling for the given block.
2066     def standard_exception_handling
2067       begin
2068         yield
2069       rescue SystemExit => ex
2070         # Exit silently with current status
2071         raise
2072       rescue OptionParser::InvalidOption => ex
2073         # Exit silently
2074         exit(false)
2075       rescue Exception => ex
2076         # Exit with error message
2077         $stderr.puts "#{name} aborted!"
2078         $stderr.puts ex.message
2079         if options.trace
2080           $stderr.puts ex.backtrace.join("\n")
2081         else
2082           $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
2083           $stderr.puts "(See full trace by running task with --trace)"
2084         end
2085         exit(false)
2086       end
2087     end
2088 
2089     # True if one of the files in RAKEFILES is in the current directory.
2090     # If a match is found, it is copied into @rakefile.
2091     def have_rakefile
2092       @rakefiles.each do |fn|
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
2098         end
2099       end
2100       return nil
2101     end
2102 
2103     # True if we are outputting to TTY, false otherwise
2104     def tty_output?
2105       @tty_output
2106     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
2111     end
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.
2120     def display_tasks_and_comments
2121       displayable_tasks = tasks.select { |t|
2122         t.comment && t.name =~ options.show_task_pattern
2123       }
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
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
2168     end
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 
2182     # Display the tasks and prerequisites
2183     def display_prerequisites
2184       tasks.each do |t|
2185         puts "#{name} #{t.name}"
2186         t.prerequisites.each { |pre| puts "    #{pre}" }
2187       end
2188     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       ]
2307     end
2308 
2309     # Read and handle the command line options.
2310     def handle_options
2311       options.rakelib = ['rakelib']
2312 
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!
2325 
2326       # If class namespaces are requested, set the global options
2327       # according to the values in the options structure.
2328       if options.classic_namespace
2329         $show_tasks = options.show_tasks
2330         $show_prereqs = options.show_prereqs
2331         $trace = options.trace
2332         $dryrun = options.dryrun
2333         $silent = options.silent
2334       end
2335     end
2336 
2337     # Similar to the regular Ruby +require+ command, but will check
2338     # for *.rake files in addition to *.rb files.
2339     def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
2340       return false if loaded.include?(file_name)
2341       paths.each do |path|
2342         fn = file_name + ".rake"
2343         full_path = File.join(path, fn)
2344         if File.exist?(full_path)
2345           load full_path
2346           loaded << fn
2347           return true
2348         end
2349       end
2350       fail LoadError, "Can't find #{file_name}"
2351     end
2352 
2353     def find_rakefile_location
2354       here = Dir.pwd
2355       while ! (fn = have_rakefile)
2356         Dir.chdir("..")
2357         if Dir.pwd == here || options.nosearch
2358           return nil
2359         end
2360         here = Dir.pwd
2361       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
2389       end
2390       load_imports
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
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 
2422     # Collect the list of tasks on the command line.  If no tasks are
2423     # given, return a list containing only the default task.
2424     # Environmental assignments are processed at this time as well.
2425     def collect_tasks
2426       @top_level_tasks = []
2427       ARGV.each do |arg|
2428         if arg =~ /^(\w+)=(.*)$/
2429           ENV[$1] = $2
2430         else
2431           @top_level_tasks << arg unless arg =~ /^-/
2432         end
2433       end
2434       @top_level_tasks.push("default") if @top_level_tasks.size == 0
2435     end
2436 
2437     # Add a file to the list of files to be imported.
2438     def add_import(fn)
2439       @pending_imports << fn
2440     end
2441 
2442     # Load the pending list of imported files.
2443     def load_imports
2444       while fn = @pending_imports.shift
2445         next if @imported.member?(fn)
2446         if fn_task = lookup(fn)
2447           fn_task.invoke
2448         end
2449         ext = File.extname(fn)
2450         loader = @loaders[ext] || @default_loader
2451         loader.load(fn)
2452         @imported << fn
2453       end
2454     end
2455 
2456     # Warn about deprecated use of top level constant names.
2457     def const_warning(const_name)
2458       @const_warning ||= false
2459       if ! @const_warning
2460         $stderr.puts %{WARNING: Deprecated reference to top-level constant '#{const_name}' } +
2461           %{found at: #{rakefile_location}} # '
2462         $stderr.puts %{    Use --classic-namespace on rake command}
2463         $stderr.puts %{    or 'require "rake/classic_namespace"' in Rakefile}
2464       end
2465       @const_warning = true
2466     end
2467 
2468     def rakefile_location
2469       begin
2470         fail
2471       rescue RuntimeError => ex
2472         ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
2473       end
2474     end
2475   end
2476 end
2477 
2478 
2479 class Module
2480   # Rename the original handler to make it available.
2481   alias :rake_original_const_missing :const_missing
2482 
2483   # Check for deprecated uses of top level (i.e. in Object) uses of
2484   # Rake class names.  If someone tries to reference the constant
2485   # name, display a warning and return the proper object.  Using the
2486   # --classic-namespace command line option will define these
2487   # constants in Object and avoid this handler.
2488   def const_missing(const_name)
2489     case const_name
2490     when :Task
2491       Rake.application.const_warning(const_name)
2492       Rake::Task
2493     when :FileTask
2494       Rake.application.const_warning(const_name)
2495       Rake::FileTask
2496     when :FileCreationTask
2497       Rake.application.const_warning(const_name)
2498       Rake::FileCreationTask
2499     when :RakeApp
2500       Rake.application.const_warning(const_name)
2501       Rake::Application
2502     else
2503       rake_original_const_missing(const_name)
2504     end
2505   end
2506 end

Generated on Mon May 10 23:40:27 -0700 2010 with rcov 0.9.8