* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / lib / rake.rb
blob147d05c53191eae114c8de09b6473a379d372eba
1 #!/usr/bin/env ruby
3 #--
5 # Copyright (c) 2003, 2004, 2005, 2006, 2007  Jim Weirich
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:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
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 #++
26 # = Rake -- Ruby Make
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.
32 RAKEVERSION = '0.8.0'
34 require 'rbconfig'
35 require 'getoptlong'
36 require 'fileutils'
37 require 'singleton'
38 require 'thread'
39 require 'ostruct'
41 ######################################################################
42 # Rake extensions to Module.
44 class Module
45   # Check for an existing method in the current class before extending.  IF
46   # the method already exists, then a warning is printed and the extension is
47   # not added.  Otherwise the block is yielded and any definitions in the
48   # block will take effect.
49   #
50   # Usage:
51   #
52   #   class String
53   #     rake_extension("xyz") do
54   #       def xyz
55   #         ...
56   #       end
57   #     end
58   #   end
59   #
60   def rake_extension(method)
61     if instance_methods.include?(method.to_s) || instance_methods.include?(method.to_sym)
62       $stderr.puts "WARNING: Possible conflict with Rake extension: #{self}##{method} already exists"
63     else
64       yield
65     end
66   end
67 end # module Module
70 ######################################################################
71 # User defined methods to be added to String.
73 class String
74   rake_extension("ext") do
75     # Replace the file extension with +newext+.  If there is no extension on
76     # the string, append the new extension to the end.  If the new extension
77     # is not given, or is the empty string, remove any existing extension.
78     #
79     # +ext+ is a user added method for the String class.
80     def ext(newext='')
81       return self.dup if ['.', '..'].include? self
82       if newext != ''
83         newext = (newext =~ /^\./) ? newext : ("." + newext)
84       end
85       dup.sub!(%r(([^/\\])\.[^./\\]*$)) { $1 + newext } || self + newext
86     end
87   end
89   rake_extension("pathmap") do
90     # Explode a path into individual components.  Used by +pathmap+.
91     def pathmap_explode
92       head, tail = File.split(self)
93       return [self] if head == self
94       return [tail] if head == '.' || tail == '/'
95       return [head, tail] if head == '/'
96       return head.pathmap_explode + [tail]
97     end
98     protected :pathmap_explode
100     # Extract a partial path from the path.  Include +n+ directories from the
101     # front end (left hand side) if +n+ is positive.  Include |+n+|
102     # directories from the back end (right hand side) if +n+ is negative.
103     def pathmap_partial(n)
104       dirs = File.dirname(self).pathmap_explode
105       partial_dirs =
106         if n > 0
107           dirs[0...n]
108         elsif n < 0
109           dirs.reverse[0...-n].reverse
110         else
111           "."
112         end
113       File.join(partial_dirs)
114     end
115     protected :pathmap_partial
116       
117     # Preform the pathmap replacement operations on the given path. The
118     # patterns take the form 'pat1,rep1;pat2,rep2...'.
119     def pathmap_replace(patterns, &block)
120       result = self
121       patterns.split(';').each do |pair|
122         pattern, replacement = pair.split(',')
123         pattern = Regexp.new(pattern)
124         if replacement == '*' && block_given?
125           result = result.sub(pattern, &block)
126         elsif replacement
127           result = result.sub(pattern, replacement)
128         else
129           result = result.sub(pattern, '')
130         end
131       end
132       result
133     end
134     protected :pathmap_replace
136     # Map the path according to the given specification.  The specification
137     # controls the details of the mapping.  The following special patterns are
138     # recognized:
139     #
140     # * <b>%p</b> -- The complete path.
141     # * <b>%f</b> -- The base file name of the path, with its file extension,
142     #   but without any directories.
143     # * <b>%n</b> -- The file name of the path without its file extension.
144     # * <b>%d</b> -- The directory list of the path.
145     # * <b>%x</b> -- The file extension of the path.  An empty string if there
146     #   is no extension.
147     # * <b>%X</b> -- Everything *but* the file extension.
148     # * <b>%s</b> -- The alternate file separator if defined, otherwise use
149     #   the standard file separator.
150     # * <b>%%</b> -- A percent sign.
151     #
152     # The %d specifier can also have a numeric prefix (e.g. '%2d'). If the
153     # number is positive, only return (up to) +n+ directories in the path,
154     # starting from the left hand side.  If +n+ is negative, return (up to)
155     # |+n+| directories from the right hand side of the path.
156     #
157     # Examples:
158     #
159     #   'a/b/c/d/file.txt'.pathmap("%2d")   => 'a/b'
160     #   'a/b/c/d/file.txt'.pathmap("%-2d")  => 'c/d'
161     #
162     # Also the %d, %p, $f, $n, %x, and %X operators can take a
163     # pattern/replacement argument to perform simple string substitutions on a
164     # particular part of the path.  The pattern and replacement are separated
165     # by a comma and are enclosed by curly braces.  The replacement spec comes
166     # after the % character but before the operator letter.  (e.g.
167     # "%{old,new}d").  Muliple replacement specs should be separated by
168     # semi-colons (e.g. "%{old,new;src,bin}d").
169     #
170     # Regular expressions may be used for the pattern, and back refs may be
171     # used in the replacement text.  Curly braces, commas and semi-colons are
172     # excluded from both the pattern and replacement text (let's keep parsing
173     # reasonable).
174     #
175     # For example:
176     #
177     #    "src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")
178     #
179     # returns:
180     #
181     #    "bin/org/onestepback/proj/A.class"
182     #
183     # If the replacement text is '*', then a block may be provided to perform
184     # some arbitrary calculation for the replacement.
185     #
186     # For example:
187     #
188     #   "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext|
189     #      ext.downcase
190     #   }
191     #
192     # Returns:
193     #
194     #  "/path/to/file.txt"
195     #
196     def pathmap(spec=nil, &block)
197       return self if spec.nil?
198       result = ''
199       spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
200         case frag
201         when '%f'
202           result << File.basename(self)
203         when '%n'
204           result << File.basename(self).ext
205         when '%d'
206           result << File.dirname(self)
207         when '%x'
208           result << $1 if self =~ /[^\/](\.[^.]+)$/
209         when '%X'
210           if self =~ /^(.*[^\/])(\.[^.]+)$/
211             result << $1
212           else
213             result << self
214           end
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
239 ##############################################################################
240 module Rake
242   # --------------------------------------------------------------------------
243   # Rake module singleton methods.
244   #
245   class << self
246     # Current Rake Application
247     def application
248       @application ||= Rake::Application.new
249     end
251     # Set the current Rake application object.
252     def application=(app)
253       @application = app
254     end
256     # Return the original directory where the Rake application was started.
257     def original_dir
258       application.original_dir
259     end
261   end
263   # ##########################################################################
264   # Mixin for creating easily cloned objects.
265   #
266   module Cloneable
267     # Clone an object by making a new object and setting all the instance
268     # variables to the same values.
269     def clone
270       sibling = self.class.new
271       instance_variables.each do |ivar|
272         value = self.instance_variable_get(ivar)
273         new_value = value.clone rescue value
274         sibling.instance_variable_set(ivar, new_value)
275       end
276       sibling
277     end
278     alias dup clone
279   end
281   ####################################################################
282   # TaskAguments manage the arguments passed to a task.
283   #
284   class TaskArguments
285     include Enumerable
287     attr_reader :names
289     def initialize(names, values, parent=nil)
290       @names = names
291       @parent = parent
292       @hash = {}
293       names.each_with_index { |name, i|
294         @hash[name.to_sym] = values[i]
295       }
296     end
298     # Create a new argument scope using the prerequisite argument
299     # names.
300     def new_scope(names)
301       values = names.collect { |n| self[n] }
302       self.class.new(names, values, self)
303     end
305     # Find an argument value by name or index.
306     def [](index)
307       lookup(index.to_sym)
308     end
310     def each(&block)
311       @hash.each(&block)
312     end
314     def method_missing(sym, *args, &block)
315       lookup(sym.to_sym)
316     end
318     def to_hash
319       @hash
320     end
322     def to_s
323       @hash.inspect
324     end
326     def inspect
327       to_s
328     end
329     
330     protected
331     
332     def lookup(name)
333       if @hash.has_key?(name)
334         @hash[name]
335       elsif ENV.has_key?(name.to_s)
336         ENV[name.to_s]
337       elsif ENV.has_key?(name.to_s.upcase)
338         ENV[name.to_s.upcase]
339       elsif @parent
340         @parent.lookup(name)
341       end
342     end
343   end
345   ####################################################################
346   # InvocationChain tracks the chain of task invocations to detect
347   # circular dependencies.
348   class InvocationChain
349     def initialize(value, tail)
350       @value = value
351       @tail = tail
352     end
354     def member?(obj)
355       @value == obj || @tail.member?(obj)
356     end
358     def append(value)
359       if member?(value)
360         fail RuntimeError, "Circular dependency detected: #{to_s} => #{value}"
361       end
362       self.class.new(value, self)
363     end
365     def to_s
366       "#{prefix}#{@value}"
367     end
369     def self.append(value, chain)
370       chain.append(value)
371     end
373     private
375     def prefix
376       "#{@tail.to_s} => "
377     end
379     class EmptyInvocationChain
380       def member?(obj)
381         false
382       end
383       def append(value)
384         InvocationChain.new(value, self)
385       end
386       def to_s
387         "TOP"
388       end
389     end
391     EMPTY = EmptyInvocationChain.new
393   end # class InvocationChain
395 end # module Rake
397 module Rake
399   # #########################################################################
400   # A Task is the basic unit of work in a Rakefile.  Tasks have associated
401   # actions (possibly more than one) and a list of prerequisites.  When
402   # invoked, a task will first ensure that all of its prerequisites have an
403   # opportunity to run and then it will execute its own actions.
404   #
405   # Tasks are not usually created directly using the new method, but rather
406   # use the +file+ and +task+ convenience methods.
407   #
408   class Task
409     # List of prerequisites for a task.
410     attr_reader :prerequisites
412     # Application owning this task.
413     attr_accessor :application
415     # Comment for this task.  Restricted to a single line of no more than 50
416     # characters.
417     attr_reader :comment
419     # Full text of the (possibly multi-line) comment.
420     attr_reader :full_comment
422     # Array of nested namespaces names used for task lookup by this task.
423     attr_reader :scope
425     # Return task name
426     def to_s
427       name
428     end
430     def inspect
431       "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
432     end
434     # List of sources for task.
435     attr_writer :sources
436     def sources
437       @sources ||= []
438     end
440     # First source from a rule (nil if no sources)
441     def source
442       @sources.first if defined?(@sources)
443     end
445     # Create a task named +task_name+ with no actions or prerequisites. Use
446     # +enhance+ to add actions and prerequisites.
447     def initialize(task_name, app)
448       @name = task_name.to_s
449       @prerequisites = FileList[]
450       @actions = []
451       @already_invoked = false
452       @full_comment = nil
453       @comment = nil
454       @lock = Mutex.new
455       @application = app
456       @scope = app.current_scope
457       @arg_names = nil
458     end
460     # Enhance a task with prerequisites or actions.  Returns self.
461     def enhance(deps=nil, &block)
462       @prerequisites |= deps if deps
463       @actions << block if block_given?
464       self
465     end
467     # Name of the task, including any namespace qualifiers.
468     def name
469       @name.to_s
470     end
472     # Name of task with argument list description.
473     def name_with_args # :nodoc:
474       if arg_description
475         "#{name}#{arg_description}"
476       else
477         name
478       end
479     end
481     # Argument description (nil if none).
482     def arg_description # :nodoc:
483       @arg_names ? "[#{(arg_names || []).join(',')}]" : nil
484     end
486     # Name of arguments for this task.
487     def arg_names
488       @arg_names || []
489     end
491     # Invoke the task if it is needed.  Prerequites are invoked first.
492     def invoke(*args)
493       task_args = TaskArguments.new(arg_names, args)
494       invoke_with_call_chain(task_args, InvocationChain::EMPTY)
495     end
497     # Same as invoke, but explicitly pass a call chain to detect
498     # circular dependencies.
499     def invoke_with_call_chain(task_args, invocation_chain)
500       new_chain = InvocationChain.append(self, invocation_chain)
501       @lock.synchronize do
502         if application.options.trace
503           puts "** Invoke #{name} #{format_trace_flags}"
504         end
505         return if @already_invoked
506         @already_invoked = true
507         invoke_prerequisites(task_args, new_chain)
508         execute(task_args) if needed?
509       end
510     end
511     protected :invoke_with_call_chain
513     # Invoke all the prerequisites of a task.
514     def invoke_prerequisites(task_args, invocation_chain)
515       @prerequisites.each { |n|
516         prereq = application[n, @scope]
517         prereq_args = task_args.new_scope(prereq.arg_names)
518         prereq.invoke_with_call_chain(prereq_args, invocation_chain)
519       }
520     end
522     # Format the trace flags for display.
523     def format_trace_flags
524       flags = []
525       flags << "first_time" unless @already_invoked
526       flags << "not_needed" unless needed?
527       flags.empty? ? "" : "(" + flags.join(", ") + ")"
528     end
529     private :format_trace_flags
531     # Execute the actions associated with this task.
532     def execute(args)
533       if application.options.dryrun
534         puts "** Execute (dry run) #{name}"
535         return
536       end
537       if application.options.trace
538         puts "** Execute #{name}"
539       end
540       application.enhance_with_matching_rule(name) if @actions.empty?
541       @actions.each do |act|
542         case act.arity
543         when 1
544           act.call(self)
545         else
546           act.call(self, args)
547         end
548       end
549     end
551     # Is this task needed?
552     def needed?
553       true
554     end
556     # Timestamp for this task.  Basic tasks return the current time for their
557     # time stamp.  Other tasks can be more sophisticated.
558     def timestamp
559       @prerequisites.collect { |p| application[p].timestamp }.max || Time.now
560     end
562     # Add a description to the task.  The description can consist of an option
563     # argument list (enclosed brackets) and an optional comment.
564     def add_description(description)
565       return if ! description
566       comment = description.strip
567       add_comment(comment) if comment && ! comment.empty?
568     end
570     # Writing to the comment attribute is the same as adding a description.
571     def comment=(description)
572       add_description(description)
573     end
575     # Add a comment to the task.  If a comment alread exists, separate
576     # the new comment with " / ".
577     def add_comment(comment)
578       if @full_comment
579         @full_comment << " / "
580       else
581         @full_comment = ''
582       end
583       @full_comment << comment
584       if @full_comment =~ /\A([^.]+?\.)( |$)/
585         @comment = $1
586       else
587         @comment = @full_comment
588       end
589     end
590     private :add_comment
592     # Set the names of the arguments for this task. +args+ should be
593     # an array of symbols, one for each argument name.
594     def set_arg_names(args)
595       @arg_names = args.map { |a| a.to_sym }
596     end
598     # Return a string describing the internal state of a task.  Useful for
599     # debugging.
600     def investigation
601       result = "------------------------------\n"
602       result << "Investigating #{name}\n"
603       result << "class: #{self.class}\n"
604       result <<  "task needed: #{needed?}\n"
605       result <<  "timestamp: #{timestamp}\n"
606       result << "pre-requisites: \n"
607       prereqs = @prerequisites.collect {|name| application[name]}
608       prereqs.sort! {|a,b| a.timestamp <=> b.timestamp}
609       prereqs.each do |p|
610         result << "--#{p.name} (#{p.timestamp})\n"
611       end
612       latest_prereq = @prerequisites.collect{|n| application[n].timestamp}.max
613       result <<  "latest-prerequisite time: #{latest_prereq}\n"
614       result << "................................\n\n"
615       return result
616     end
618     # ----------------------------------------------------------------
619     # Rake Module Methods
620     #
621     class << self
623       # Clear the task list.  This cause rake to immediately forget all the
624       # tasks that have been assigned.  (Normally used in the unit tests.)
625       def clear
626         Rake.application.clear
627       end
629       # List of all defined tasks.
630       def tasks
631         Rake.application.tasks
632       end
634       # Return a task with the given name.  If the task is not currently
635       # known, try to synthesize one from the defined rules.  If no rules are
636       # found, but an existing file matches the task name, assume it is a file
637       # task with no dependencies or actions.
638       def [](task_name)
639         Rake.application[task_name]
640       end
642       # TRUE if the task name is already defined.
643       def task_defined?(task_name)
644         Rake.application.lookup(task_name) != nil
645       end
647       # Define a task given +args+ and an option block.  If a rule with the
648       # given name already exists, the prerequisites and actions are added to
649       # the existing task.  Returns the defined task.
650       def define_task(*args, &block)
651         Rake.application.define_task(self, *args, &block)
652       end
654       # Define a rule for synthesizing tasks.
655       def create_rule(*args, &block)
656         Rake.application.create_rule(*args, &block)
657       end
659       # Apply the scope to the task name according to the rules for
660       # this kind of task.  Generic tasks will accept the scope as
661       # part of the name.
662       def scope_name(scope, task_name)
663         (scope + [task_name]).join(':')
664       end
666     end # class << Rake::Task
667   end # class Rake::Task
670   # #########################################################################
671   # A FileTask is a task that includes time based dependencies.  If any of a
672   # FileTask's prerequisites have a timestamp that is later than the file
673   # represented by this task, then the file must be rebuilt (using the
674   # supplied actions).
675   #
676   class FileTask < Task
678     # Is this file task needed?  Yes if it doesn't exist, or if its time stamp
679     # is out of date.
680     def needed?
681       return true unless File.exist?(name)
682       return true if out_of_date?(timestamp)
683       false
684     end
686     # Time stamp for file task.
687     def timestamp
688       if File.exist?(name)
689         File.mtime(name.to_s)
690       else
691         Rake::EARLY
692       end
693     end
695     private
697     # Are there any prerequisites with a later time than the given time stamp?
698     def out_of_date?(stamp)
699       @prerequisites.any? { |n| application[n].timestamp > stamp}
700     end
702     # ----------------------------------------------------------------
703     # Task class methods.
704     #
705     class << self
706       # Apply the scope to the task name according to the rules for this kind
707       # of task.  File based tasks ignore the scope when creating the name.
708       def scope_name(scope, task_name)
709         task_name
710       end
711     end
712   end # class Rake::FileTask
714   # #########################################################################
715   # A FileCreationTask is a file task that when used as a dependency will be
716   # needed if and only if the file has not been created.  Once created, it is
717   # not re-triggered if any of its dependencies are newer, nor does trigger
718   # any rebuilds of tasks that depend on it whenever it is updated.
719   #
720   class FileCreationTask < FileTask
721     # Is this file task needed?  Yes if it doesn't exist.
722     def needed?
723       ! File.exist?(name)
724     end
726     # Time stamp for file creation task.  This time stamp is earlier
727     # than any other time stamp.
728     def timestamp
729       Rake::EARLY
730     end
731   end
733   # #########################################################################
734   # Same as a regular task, but the immediate prerequisites are done in
735   # parallel using Ruby threads.
736   #
737   class MultiTask < Task
738     def invoke_prerequisites(args, invocation_chain)
739       threads = @prerequisites.collect { |p|
740         Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
741       }
742       threads.each { |t| t.join }
743     end
744   end
745 end # module Rake
747 # ###########################################################################
748 # Task Definition Functions ...
750 # Declare a basic task.
752 # Example:
753 #   task :clobber => [:clean] do
754 #     rm_rf "html"
755 #   end
757 def task(*args, &block)
758   Rake::Task.define_task(*args, &block)
762 # Declare a file task.
764 # Example:
765 #   file "config.cfg" => ["config.template"] do
766 #     open("config.cfg", "w") do |outfile|
767 #       open("config.template") do |infile|
768 #         while line = infile.gets
769 #           outfile.puts line
770 #         end
771 #       end
772 #     end
773 #  end
775 def file(args, &block)
776   Rake::FileTask.define_task(args, &block)
779 # Declare a file creation task.
780 # (Mainly used for the directory command).
781 def file_create(args, &block)
782   Rake::FileCreationTask.define_task(args, &block)
785 # Declare a set of files tasks to create the given directories on demand.
787 # Example:
788 #   directory "testdata/doc"
790 def directory(dir)
791   Rake.each_dir_parent(dir) do |d|
792     file_create d do |t|
793       mkdir_p t.name if ! File.exist?(t.name)
794     end
795   end
798 # Declare a task that performs its prerequisites in parallel. Multitasks does
799 # *not* guarantee that its prerequisites will execute in any given order
800 # (which is obvious when you think about it)
802 # Example:
803 #   multitask :deploy => [:deploy_gem, :deploy_rdoc]
805 def multitask(args, &block)
806   Rake::MultiTask.define_task(args, &block)
809 # Create a new rake namespace and use it for evaluating the given block.
810 # Returns a NameSpace object that can be used to lookup tasks defined in the
811 # namespace.
813 # E.g.
815 #   ns = namespace "nested" do
816 #     task :run
817 #   end
818 #   task_run = ns[:run] # find :run in the given namespace.
820 def namespace(name=nil, &block)
821   Rake.application.in_namespace(name, &block)
824 # Declare a rule for auto-tasks.
826 # Example:
827 #  rule '.o' => '.c' do |t|
828 #    sh %{cc -o #{t.name} #{t.source}}
829 #  end
831 def rule(*args, &block)
832   Rake::Task.create_rule(*args, &block)
835 # Describe the next rake task.
837 # Example:
838 #   desc "Run the Unit Tests"
839 #   task :test => [:build]
840 #     runtests
841 #   end
843 def desc(description)
844   Rake.application.last_description = description
847 # Import the partial Rakefiles +fn+.  Imported files are loaded _after_ the
848 # current file is completely loaded.  This allows the import statement to
849 # appear anywhere in the importing file, and yet allowing the imported files
850 # to depend on objects defined in the importing file.
852 # A common use of the import statement is to include files containing
853 # dependency declarations.
855 # See also the --rakelibdir command line option.
857 # Example:
858 #   import ".depend", "my_rules"
860 def import(*fns)
861   fns.each do |fn|
862     Rake.application.add_import(fn)
863   end
866 # ###########################################################################
867 # This a FileUtils extension that defines several additional commands to be
868 # added to the FileUtils utility functions.
870 module FileUtils
871   RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
873   OPT_TABLE['sh']  = %w(noop verbose)
874   OPT_TABLE['ruby'] = %w(noop verbose)
876   # Run the system command +cmd+. If multiple arguments are given the command
877   # is not run with the shell (same semantics as Kernel::exec and
878   # Kernel::system).
879   #
880   # Example:
881   #   sh %{ls -ltr}
882   #
883   #   sh 'ls', 'file with spaces'
884   #
885   #   # check exit status after command runs
886   #   sh %{grep pattern file} do |ok, res|
887   #     if ! ok
888   #       puts "pattern not found (status = #{res.exitstatus})"
889   #     end
890   #   end
891   #
892   def sh(*cmd, &block)
893     options = (Hash === cmd.last) ? cmd.pop : {}
894     unless block_given?
895       show_command = cmd.join(" ")
896       show_command = show_command[0,42] + "..."
897       # TODO code application logic heref show_command.length > 45
898       block = lambda { |ok, status|
899         ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
900       }
901     end
902     rake_check_options options, :noop, :verbose
903     rake_output_message cmd.join(" ") if options[:verbose]
904     unless options[:noop]
905       res = system(*cmd)
906       block.call(res, $?)
907     end
908   end
910   # Run a Ruby interpreter with the given arguments.
911   #
912   # Example:
913   #   ruby %{-pe '$_.upcase!' <README}
914   #
915   def ruby(*args,&block)
916     options = (Hash === args.last) ? args.pop : {}
917     if args.length > 1 then
918       sh(*([RUBY] + args + [options]), &block)
919     else
920       sh("#{RUBY} #{args.first}", options, &block)
921     end
922   end
924   LN_SUPPORTED = [true]
926   #  Attempt to do a normal file link, but fall back to a copy if the link
927   #  fails.
928   def safe_ln(*args)
929     unless LN_SUPPORTED[0]
930       cp(*args)
931     else
932       begin
933         ln(*args)
934       rescue StandardError, NotImplementedError => ex
935         LN_SUPPORTED[0] = false
936         cp(*args)
937       end
938     end
939   end
941   # Split a file path into individual directory names.
942   #
943   # Example:
944   #   split_all("a/b/c") =>  ['a', 'b', 'c']
945   #
946   def split_all(path)
947     head, tail = File.split(path)
948     return [tail] if head == '.' || tail == '/'
949     return [head, tail] if head == '/'
950     return split_all(head) + [tail]
951   end
954 # ###########################################################################
955 # RakeFileUtils provides a custom version of the FileUtils methods that
956 # respond to the <tt>verbose</tt> and <tt>nowrite</tt> commands.
958 module RakeFileUtils
959   include FileUtils
961   class << self
962     attr_accessor :verbose_flag, :nowrite_flag
963   end
964   RakeFileUtils.verbose_flag = true
965   RakeFileUtils.nowrite_flag = false
967   $fileutils_verbose = true
968   $fileutils_nowrite = false
970   FileUtils::OPT_TABLE.each do |name, opts|
971     default_options = []
972     if opts.include?('verbose')
973       default_options << ':verbose => RakeFileUtils.verbose_flag'
974     end
975     if opts.include?('noop')
976       default_options << ':noop => RakeFileUtils.nowrite_flag'
977     end
979     next if default_options.empty?
980     module_eval(<<-EOS, __FILE__, __LINE__ + 1)
981     def #{name}( *args, &block )
982       super(
983         *rake_merge_option(args,
984           #{default_options.join(', ')}
985           ), &block)
986     end
987     EOS
988   end
990   # Get/set the verbose flag controlling output from the FileUtils utilities.
991   # If verbose is true, then the utility method is echoed to standard output.
992   #
993   # Examples:
994   #    verbose              # return the current value of the verbose flag
995   #    verbose(v)           # set the verbose flag to _v_.
996   #    verbose(v) { code }  # Execute code with the verbose flag set temporarily to _v_.
997   #                         # Return to the original value when code is done.
998   def verbose(value=nil)
999     oldvalue = RakeFileUtils.verbose_flag
1000     RakeFileUtils.verbose_flag = value unless value.nil?
1001     if block_given?
1002       begin
1003         yield
1004       ensure
1005         RakeFileUtils.verbose_flag = oldvalue
1006       end
1007     end
1008     RakeFileUtils.verbose_flag
1009   end
1011   # Get/set the nowrite flag controlling output from the FileUtils utilities.
1012   # If verbose is true, then the utility method is echoed to standard output.
1013   #
1014   # Examples:
1015   #    nowrite              # return the current value of the nowrite flag
1016   #    nowrite(v)           # set the nowrite flag to _v_.
1017   #    nowrite(v) { code }  # Execute code with the nowrite flag set temporarily to _v_.
1018   #                         # Return to the original value when code is done.
1019   def nowrite(value=nil)
1020     oldvalue = RakeFileUtils.nowrite_flag
1021     RakeFileUtils.nowrite_flag = value unless value.nil?
1022     if block_given?
1023       begin
1024         yield
1025       ensure
1026         RakeFileUtils.nowrite_flag = oldvalue
1027       end
1028     end
1029     oldvalue
1030   end
1032   # Use this function to prevent potentially destructive ruby code from
1033   # running when the :nowrite flag is set.
1034   #
1035   # Example:
1036   #
1037   #   when_writing("Building Project") do
1038   #     project.build
1039   #   end
1040   #
1041   # The following code will build the project under normal conditions. If the
1042   # nowrite(true) flag is set, then the example will print:
1043   #      DRYRUN: Building Project
1044   # instead of actually building the project.
1045   #
1046   def when_writing(msg=nil)
1047     if RakeFileUtils.nowrite_flag
1048       puts "DRYRUN: #{msg}" if msg
1049     else
1050       yield
1051     end
1052   end
1054   # Merge the given options with the default values.
1055   def rake_merge_option(args, defaults)
1056     if Hash === args.last
1057       defaults.update(args.last)
1058       args.pop
1059     end
1060     args.push defaults
1061     args
1062   end
1063   private :rake_merge_option
1065   # Send the message to the default rake output (which is $stderr).
1066   def rake_output_message(message)
1067     $stderr.puts(message)
1068   end
1069   private :rake_output_message
1071   # Check that the options do not contain options not listed in +optdecl+.  An
1072   # ArgumentError exception is thrown if non-declared options are found.
1073   def rake_check_options(options, *optdecl)
1074     h = options.dup
1075     optdecl.each do |name|
1076       h.delete name
1077     end
1078     raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
1079   end
1080   private :rake_check_options
1082   extend self
1085 # ###########################################################################
1086 # Include the FileUtils file manipulation functions in the top level module,
1087 # but mark them private so that they don't unintentionally define methods on
1088 # other objects.
1090 include RakeFileUtils
1091 private(*FileUtils.instance_methods(false))
1092 private(*RakeFileUtils.instance_methods(false))
1094 ######################################################################
1095 module Rake
1097   class RuleRecursionOverflowError < StandardError
1098     def initialize(*args)
1099       super
1100       @targets = []
1101     end
1103     def add_target(target)
1104       @targets << target
1105     end
1107     def message
1108       super + ": [" + @targets.reverse.join(' => ') + "]"
1109     end
1110   end
1112   # #########################################################################
1113   # A FileList is essentially an array with a few helper methods defined to
1114   # make file manipulation a bit easier.
1115   #
1116   # FileLists are lazy.  When given a list of glob patterns for possible files
1117   # to be included in the file list, instead of searching the file structures
1118   # to find the files, a FileList holds the pattern for latter use.
1119   #
1120   # This allows us to define a number of FileList to match any number of
1121   # files, but only search out the actual files when then FileList itself is
1122   # actually used.  The key is that the first time an element of the
1123   # FileList/Array is requested, the pending patterns are resolved into a real
1124   # list of file names.
1125   #
1126   class FileList
1128     include Cloneable
1130     # == Method Delegation
1131     #
1132     # The lazy evaluation magic of FileLists happens by implementing all the
1133     # array specific methods to call +resolve+ before delegating the heavy
1134     # lifting to an embedded array object (@items).
1135     #
1136     # In addition, there are two kinds of delegation calls.  The regular kind
1137     # delegates to the @items array and returns the result directly.  Well,
1138     # almost directly.  It checks if the returned value is the @items object
1139     # itself, and if so will return the FileList object instead.
1140     #
1141     # The second kind of delegation call is used in methods that normally
1142     # return a new Array object.  We want to capture the return value of these
1143     # methods and wrap them in a new FileList object.  We enumerate these
1144     # methods in the +SPECIAL_RETURN+ list below.
1146     # List of array methods (that are not in +Object+) that need to be
1147     # delegated.
1148     ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
1150     # List of additional methods that must be delegated.
1151     MUST_DEFINE = %w[to_a inspect]
1153     # List of methods that should not be delegated here (we define special
1154     # versions of them explicitly below).
1155     MUST_NOT_DEFINE = %w[to_a to_ary partition *]
1157     # List of delegated methods that return new array values which need
1158     # wrapping.
1159     SPECIAL_RETURN = %w[
1160       map collect sort sort_by select find_all reject grep
1161       compact flatten uniq values_at
1162       + - & |
1163     ]
1165     DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
1167     # Now do the delegation.
1168     DELEGATING_METHODS.each_with_index do |sym, i|
1169       if SPECIAL_RETURN.include?(sym)
1170         ln = __LINE__+1
1171         class_eval %{
1172           def #{sym}(*args, &block)
1173             resolve
1174             result = @items.send(:#{sym}, *args, &block)
1175             FileList.new.import(result)
1176           end
1177         }, __FILE__, ln
1178       else
1179         ln = __LINE__+1
1180         class_eval %{
1181           def #{sym}(*args, &block)
1182             resolve
1183             result = @items.send(:#{sym}, *args, &block)
1184             result.object_id == @items.object_id ? self : result
1185           end
1186         }, __FILE__, ln
1187       end
1188     end
1190     # Create a file list from the globbable patterns given.  If you wish to
1191     # perform multiple includes or excludes at object build time, use the
1192     # "yield self" pattern.
1193     #
1194     # Example:
1195     #   file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
1196     #
1197     #   pkg_files = FileList.new('lib/**/*') do |fl|
1198     #     fl.exclude(/\bCVS\b/)
1199     #   end
1200     #
1201     def initialize(*patterns)
1202       @pending_add = []
1203       @pending = false
1204       @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1205       @exclude_procs = DEFAULT_IGNORE_PROCS.dup
1206       @exclude_re = nil
1207       @items = []
1208       patterns.each { |pattern| include(pattern) }
1209       yield self if block_given?
1210     end
1212     # Add file names defined by glob patterns to the file list.  If an array
1213     # is given, add each element of the array.
1214     #
1215     # Example:
1216     #   file_list.include("*.java", "*.cfg")
1217     #   file_list.include %w( math.c lib.h *.o )
1218     #
1219     def include(*filenames)
1220       # TODO: check for pending
1221       filenames.each do |fn|
1222         if fn.respond_to? :to_ary
1223           include(*fn.to_ary)
1224         else
1225           @pending_add << fn
1226         end
1227       end
1228       @pending = true
1229       self
1230     end
1231     alias :add :include
1233     # Register a list of file name patterns that should be excluded from the
1234     # list.  Patterns may be regular expressions, glob patterns or regular
1235     # strings.  In addition, a block given to exclude will remove entries that
1236     # return true when given to the block.
1237     #
1238     # Note that glob patterns are expanded against the file system. If a file
1239     # is explicitly added to a file list, but does not exist in the file
1240     # system, then an glob pattern in the exclude list will not exclude the
1241     # file.
1242     #
1243     # Examples:
1244     #   FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
1245     #   FileList['a.c', 'b.c'].exclude(/^a/)  => ['b.c']
1246     #
1247     # If "a.c" is a file, then ...
1248     #   FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
1249     #
1250     # If "a.c" is not a file, then ...
1251     #   FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
1252     #
1253     def exclude(*patterns, &block)
1254       patterns.each do |pat|
1255         @exclude_patterns << pat
1256       end
1257       if block_given?
1258         @exclude_procs << block
1259       end
1260       resolve_exclude if ! @pending
1261       self
1262     end
1265     # Clear all the exclude patterns so that we exclude nothing.
1266     def clear_exclude
1267       @exclude_patterns = []
1268       @exclude_procs = []
1269       calculate_exclude_regexp if ! @pending
1270       self
1271     end
1273     # Define equality.
1274     def ==(array)
1275       to_ary == array
1276     end
1278     # Return the internal array object.
1279     def to_a
1280       resolve
1281       @items
1282     end
1284     # Return the internal array object.
1285     def to_ary
1286       to_a
1287     end
1289     # Lie about our class.
1290     def is_a?(klass)
1291       klass == Array || super(klass)
1292     end
1293     alias kind_of? is_a?
1295     # Redefine * to return either a string or a new file list.
1296     def *(other)
1297       result = @items * other
1298       case result
1299       when Array
1300         FileList.new.import(result)
1301       else
1302         result
1303       end
1304     end
1306     # Resolve all the pending adds now.
1307     def resolve
1308       if @pending
1309         @pending = false
1310         @pending_add.each do |fn| resolve_add(fn) end
1311         @pending_add = []
1312         resolve_exclude
1313       end
1314       self
1315     end
1317     def calculate_exclude_regexp
1318       ignores = []
1319       @exclude_patterns.each do |pat|
1320         case pat
1321         when Regexp
1322           ignores << pat
1323         when /[*?]/
1324           Dir[pat].each do |p| ignores << p end
1325         else
1326           ignores << Regexp.quote(pat)
1327         end
1328       end
1329       if ignores.empty?
1330         @exclude_re = /^$/
1331       else
1332         re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
1333         @exclude_re = Regexp.new(re_str)
1334       end
1335     end
1337     def resolve_add(fn)
1338       case fn
1339       when %r{[*?\[\{]}
1340         add_matching(fn)
1341       else
1342         self << fn
1343       end
1344     end
1345     private :resolve_add
1347     def resolve_exclude
1348       calculate_exclude_regexp
1349       reject! { |fn| exclude?(fn) }
1350       self
1351     end
1352     private :resolve_exclude
1354     # Return a new FileList with the results of running +sub+ against each
1355     # element of the original list.
1356     #
1357     # Example:
1358     #   FileList['a.c', 'b.c'].sub(/\.c$/, '.o')  => ['a.o', 'b.o']
1359     #
1360     def sub(pat, rep)
1361       inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
1362     end
1364     # Return a new FileList with the results of running +gsub+ against each
1365     # element of the original list.
1366     #
1367     # Example:
1368     #   FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
1369     #      => ['lib\\test\\file', 'x\\y']
1370     #
1371     def gsub(pat, rep)
1372       inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
1373     end
1375     # Same as +sub+ except that the oringal file list is modified.
1376     def sub!(pat, rep)
1377       each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
1378       self
1379     end
1381     # Same as +gsub+ except that the original file list is modified.
1382     def gsub!(pat, rep)
1383       each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
1384       self
1385     end
1387     # Apply the pathmap spec to each of the included file names, returning a
1388     # new file list with the modified paths.  (See String#pathmap for
1389     # details.)
1390     def pathmap(spec=nil)
1391       collect { |fn| fn.pathmap(spec) }
1392     end
1394     # Return a new array with <tt>String#ext</tt> method applied to each
1395     # member of the array.
1396     #
1397     # This method is a shortcut for:
1398     #
1399     #    array.collect { |item| item.ext(newext) }
1400     #
1401     # +ext+ is a user added method for the Array class.
1402     def ext(newext='')
1403       collect { |fn| fn.ext(newext) }
1404     end
1407     # Grep each of the files in the filelist using the given pattern. If a
1408     # block is given, call the block on each matching line, passing the file
1409     # name, line number, and the matching line of text.  If no block is given,
1410     # a standard emac style file:linenumber:line message will be printed to
1411     # standard out.
1412     def egrep(pattern)
1413       each do |fn|
1414         open(fn) do |inf|
1415           count = 0
1416           inf.each do |line|
1417             count += 1
1418             if pattern.match(line)
1419               if block_given?
1420                 yield fn, count, line
1421               else
1422                 puts "#{fn}:#{count}:#{line}"
1423               end
1424             end
1425           end
1426         end
1427       end
1428     end
1430     # Return a new file list that only contains file names from the current
1431     # file list that exist on the file system.
1432     def existing
1433       select { |fn| File.exist?(fn) }
1434     end
1436     # Modify the current file list so that it contains only file name that
1437     # exist on the file system.
1438     def existing!
1439       resolve
1440       @items = @items.select { |fn| File.exist?(fn) }
1441       self
1442     end
1444     # FileList version of partition.  Needed because the nested arrays should
1445     # be FileLists in this version.
1446     def partition(&block)       # :nodoc:
1447       resolve
1448       result = @items.partition(&block)
1449       [
1450         FileList.new.import(result[0]),
1451         FileList.new.import(result[1]),
1452       ]
1453     end
1455     # Convert a FileList to a string by joining all elements with a space.
1456     def to_s
1457       resolve
1458       self.join(' ')
1459     end
1461     # Add matching glob patterns.
1462     def add_matching(pattern)
1463       Dir[pattern].each do |fn|
1464         self << fn unless exclude?(fn)
1465       end
1466     end
1467     private :add_matching
1469     # Should the given file name be excluded?
1470     def exclude?(fn)
1471       calculate_exclude_regexp unless @exclude_re
1472       fn =~ @exclude_re || @exclude_procs.any? { |p| p.call(fn) }
1473     end
1475     DEFAULT_IGNORE_PATTERNS = [
1476       /(^|[\/\\])CVS([\/\\]|$)/,
1477       /(^|[\/\\])\.svn([\/\\]|$)/,
1478       /\.bak$/,
1479       /~$/
1480     ]
1481     DEFAULT_IGNORE_PROCS = [
1482       proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
1483     ]
1484 #    @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1486     def import(array)
1487       @items = array
1488       self
1489     end
1491     class << self
1492       # Create a new file list including the files listed. Similar to:
1493       #
1494       #   FileList.new(*args)
1495       def [](*args)
1496         new(*args)
1497       end
1498     end
1499   end # FileList
1502 module Rake
1503   class << self
1505     # Yield each file or directory component.
1506     def each_dir_parent(dir)
1507       old_length = nil
1508       while dir != '.' && dir.length != old_length
1509         yield(dir)
1510         old_length = dir.length
1511         dir = File.dirname(dir)
1512       end
1513     end
1514   end
1515 end # module Rake
1517 # Alias FileList to be available at the top level.
1518 FileList = Rake::FileList
1520 # ###########################################################################
1521 module Rake
1523   # Default Rakefile loader used by +import+.
1524   class DefaultLoader
1525     def load(fn)
1526       Kernel.load(File.expand_path(fn))
1527     end
1528   end
1530   # EarlyTime is a fake timestamp that occurs _before_ any other time value.
1531   class EarlyTime
1532     include Comparable
1533     include Singleton
1535     def <=>(other)
1536       -1
1537     end
1539     def to_s
1540       "<EARLY TIME>"
1541     end
1542   end
1544   EARLY = EarlyTime.instance
1545 end # module Rake
1547 # ###########################################################################
1548 # Extensions to time to allow comparisons with an early time class.
1550 class Time
1551   alias rake_original_time_compare :<=>
1552   def <=>(other)
1553     if Rake::EarlyTime === other
1554       - other.<=>(self)
1555     else
1556       rake_original_time_compare(other)
1557     end
1558   end
1559 end # class Time
1561 module Rake
1563   ####################################################################
1564   # The NameSpace class will lookup task names in the the scope
1565   # defined by a +namespace+ command.
1566   #
1567   class NameSpace
1569     # Create a namespace lookup object using the given task manager
1570     # and the list of scopes.
1571     def initialize(task_manager, scope_list)
1572       @task_manager = task_manager
1573       @scope = scope_list.dup
1574     end
1576     # Lookup a task named +name+ in the namespace.
1577     def [](name)
1578       @task_manager.lookup(name, @scope)
1579     end
1581     # Return the list of tasks defined in this namespace.
1582     def tasks
1583       @task_manager.tasks
1584     end
1585   end # NameSpace
1588   ####################################################################
1589   # The TaskManager module is a mixin for managing tasks.
1590   module TaskManager
1591     # Track the last comment made in the Rakefile.
1592     attr_accessor :last_description
1593     alias :last_comment :last_description    # Backwards compatibility
1595     def initialize
1596       super
1597       @tasks = Hash.new
1598       @rules = Array.new
1599       @scope = Array.new
1600       @last_description = nil
1601     end
1603     def create_rule(*args, &block)
1604       pattern, arg_names, deps = resolve_args(args)
1605       pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
1606       @rules << [pattern, deps, block]
1607     end
1609     def define_task(task_class, *args, &block)
1610       task_name, arg_names, deps = resolve_args(args)
1611       task_name = task_class.scope_name(@scope, task_name)
1612       deps = [deps] unless deps.respond_to?(:to_ary)
1613       deps = deps.collect {|d| d.to_s }
1614       task = intern(task_class, task_name)
1615       task.set_arg_names(arg_names) unless arg_names.empty?
1616       task.add_description(@last_description)
1617       @last_description = nil
1618       task.enhance(deps, &block)
1619       task
1620     end
1622     # Lookup a task.  Return an existing task if found, otherwise
1623     # create a task of the current type.
1624     def intern(task_class, task_name)
1625       @tasks[task_name.to_s] ||= task_class.new(task_name, self)
1626     end
1628     # Find a matching task for +task_name+.
1629     def [](task_name, scopes=nil)
1630       task_name = task_name.to_s
1631       self.lookup(task_name, scopes) or
1632         enhance_with_matching_rule(task_name) or
1633         synthesize_file_task(task_name) or
1634         fail "Don't know how to build task '#{task_name}'"
1635     end
1637     def synthesize_file_task(task_name)
1638       return nil unless File.exist?(task_name)
1639       define_task(Rake::FileTask, task_name)
1640     end
1642     # Resolve the arguments for a task/rule.  Returns a triplet of
1643     # [task_name, arg_name_list, prerequisites].
1644     def resolve_args(args)
1645       task_name = args.shift
1646       arg_names = args #.map { |a| a.to_sym }
1647       needs = []
1648       if task_name.is_a?(Hash)
1649         hash = task_name
1650         task_name = hash.keys[0]
1651         needs = hash[task_name]
1652       end
1653       if arg_names.last.is_a?(Hash)
1654         hash = arg_names.pop
1655         needs = hash[:needs]
1656         fail "Unrecognized keys in task hash: #{hash.keys.inspect}" if hash.size > 1
1657       end
1658       needs = [needs] unless needs.respond_to?(:to_ary)
1659       [task_name, arg_names, needs]
1660     end
1662     # If a rule can be found that matches the task name, enhance the
1663     # task with the prerequisites and actions from the rule.  Set the
1664     # source attribute of the task appropriately for the rule.  Return
1665     # the enhanced task or nil of no rule was found.
1666     def enhance_with_matching_rule(task_name, level=0)
1667       fail Rake::RuleRecursionOverflowError,
1668         "Rule Recursion Too Deep" if level >= 16
1669       @rules.each do |pattern, extensions, block|
1670         if md = pattern.match(task_name)
1671           task = attempt_rule(task_name, extensions, block, level)
1672           return task if task
1673         end
1674       end
1675       nil
1676     rescue Rake::RuleRecursionOverflowError => ex
1677       ex.add_target(task_name)
1678       fail ex
1679     end
1681     # List of all defined tasks in this application.
1682     def tasks
1683       @tasks.values.sort_by { |t| t.name }
1684     end
1686     # Clear all tasks in this application.
1687     def clear
1688       @tasks.clear
1689       @rules.clear
1690     end
1692     # Lookup a task, using scope and the scope hints in the task name.
1693     # This method performs straight lookups without trying to
1694     # synthesize file tasks or rules.  Special scope names (e.g. '^')
1695     # are recognized.  If no scope argument is supplied, use the
1696     # current scope.  Return nil if the task cannot be found.
1697     def lookup(task_name, initial_scope=nil)
1698       initial_scope ||= @scope
1699       task_name = task_name.to_s
1700       if task_name =~ /^rake:/
1701         scopes = []
1702         task_name = task_name.sub(/^rake:/, '')
1703       elsif task_name =~ /^(\^+)/
1704         scopes = initial_scope[0, initial_scope.size - $1.size]
1705         task_name = task_name.sub(/^(\^+)/, '')
1706       else
1707         scopes = initial_scope
1708       end
1709       lookup_in_scope(task_name, scopes)
1710     end
1712     # Lookup the task name
1713     def lookup_in_scope(name, scope)
1714       n = scope.size
1715       while n >= 0
1716         tn = (scope[0,n] + [name]).join(':')
1717         task = @tasks[tn]
1718         return task if task
1719         n -= 1
1720       end
1721       nil
1722     end
1723     private :lookup_in_scope
1725     # Return the list of scope names currently active in the task
1726     # manager.
1727     def current_scope
1728       @scope.dup
1729     end
1731     # Evaluate the block in a nested namespace named +name+.  Create
1732     # an anonymous namespace if +name+ is nil.
1733     def in_namespace(name)
1734       name ||= generate_name
1735       @scope.push(name)
1736       ns = NameSpace.new(self, @scope)
1737       yield(ns)
1738       ns
1739     ensure
1740       @scope.pop
1741     end
1743     private
1745     # Generate an anonymous namespace name.
1746     def generate_name
1747       @seed ||= 0
1748       @seed += 1
1749       "_anon_#{@seed}"
1750     end
1752     # Attempt to create a rule given the list of prerequisites.
1753     def attempt_rule(task_name, extensions, block, level)
1754       sources = make_sources(task_name, extensions)
1755       prereqs = sources.collect { |source|
1756         if File.exist?(source) || Rake::Task.task_defined?(source)
1757           source
1758         elsif parent = enhance_with_matching_rule(sources.first, level+1)
1759           parent.name
1760         else
1761           return nil
1762         end
1763       }
1764       task = FileTask.define_task({task_name => prereqs}, &block)
1765       task.sources = prereqs
1766       task
1767     end
1769     # Make a list of sources from the list of file name extensions /
1770     # translation procs.
1771     def make_sources(task_name, extensions)
1772       extensions.collect { |ext|
1773         case ext
1774         when /%/
1775           task_name.pathmap(ext)
1776         when %r{/}
1777           ext
1778         when /^\./
1779           task_name.ext(ext)
1780         when String
1781           ext
1782         when Proc
1783           if ext.arity == 1
1784             ext.call(task_name)
1785           else
1786             ext.call
1787           end
1788         else
1789           fail "Don't know how to handle rule dependent: #{ext.inspect}"
1790         end
1791       }.flatten
1792     end
1794   end # TaskManager
1796   ######################################################################
1797   # Rake main application object.  When invoking +rake+ from the
1798   # command line, a Rake::Application object is created and run.
1799   #
1800   class Application
1801     include TaskManager
1803     # The name of the application (typically 'rake')
1804     attr_reader :name
1806     # The original directory where rake was invoked.
1807     attr_reader :original_dir
1809     # Name of the actual rakefile used.
1810     attr_reader :rakefile
1812     # List of the top level task names (task names from the command line).
1813     attr_reader :top_level_tasks
1815     DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
1817     OPTIONS = [     # :nodoc:
1818       ['--classic-namespace', '-C', GetoptLong::NO_ARGUMENT,
1819         "Put Task and FileTask in the top level namespace"],
1820       ['--describe',  '-D', GetoptLong::OPTIONAL_ARGUMENT,
1821         "Describe the tasks (matching optional PATTERN), then exit."],
1822       ['--rakefile', '-f', GetoptLong::OPTIONAL_ARGUMENT,
1823         "Use FILE as the rakefile."],
1824       ['--help',     '-h', '-H', GetoptLong::NO_ARGUMENT,
1825         "Display this help message."],
1826       ['--libdir',   '-I', GetoptLong::REQUIRED_ARGUMENT,
1827         "Include LIBDIR in the search path for required modules."],
1828       ['--dry-run',  '-n', GetoptLong::NO_ARGUMENT,
1829         "Do a dry run without executing actions."],
1830       ['--nosearch', '-N', GetoptLong::NO_ARGUMENT,
1831         "Do not search parent directories for the Rakefile."],
1832       ['--prereqs',  '-P', GetoptLong::NO_ARGUMENT,
1833         "Display the tasks and dependencies, then exit."],
1834       ['--quiet',    '-q', GetoptLong::NO_ARGUMENT,
1835         "Do not log messages to standard output."],
1836       ['--require',  '-r', GetoptLong::REQUIRED_ARGUMENT,
1837         "Require MODULE before executing rakefile."],
1838       ['--rakelibdir', '-R', GetoptLong::REQUIRED_ARGUMENT,
1839         "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')"],
1840       ['--silent',   '-s', GetoptLong::NO_ARGUMENT,
1841         "Like --quiet, but also suppresses the 'in directory' announcement."],
1842       ['--tasks',    '-T', GetoptLong::OPTIONAL_ARGUMENT,
1843         "Display the tasks (matching optional PATTERN) with descriptions, then exit."],
1844       ['--trace',    '-t', GetoptLong::NO_ARGUMENT,
1845         "Turn on invoke/execute tracing, enable full backtrace."],
1846       ['--verbose',  '-v', GetoptLong::NO_ARGUMENT,
1847         "Log message to standard output (default)."],
1848       ['--version',  '-V', GetoptLong::NO_ARGUMENT,
1849         "Display the program version."],
1850     ]
1852     # Initialize a Rake::Application object.
1853     def initialize
1854       super
1855       @name = 'rake'
1856       @rakefiles = DEFAULT_RAKEFILES.dup
1857       @rakefile = nil
1858       @pending_imports = []
1859       @imported = []
1860       @loaders = {}
1861       @default_loader = Rake::DefaultLoader.new
1862       @original_dir = Dir.pwd
1863       @top_level_tasks = []
1864       add_loader('rf', DefaultLoader.new)
1865       add_loader('rake', DefaultLoader.new)
1866     end
1868     # Run the Rake application.  The run method performs the following three steps:
1869     #
1870     # * Initialize the command line options (+init+).
1871     # * Define the tasks (+load_rakefile+).
1872     # * Run the top level tasks (+run_tasks+).
1873     #
1874     # If you wish to build a custom rake command, you should call +init+ on your
1875     # application.  The define any tasks.  Finally, call +top_level+ to run your top
1876     # level tasks.
1877     def run
1878       standard_exception_handling do
1879         init
1880         load_rakefile
1881         top_level
1882       end
1883     end
1885     # Initialize the command line parameters and app name.
1886     def init(app_name='rake')
1887       standard_exception_handling do
1888         @name = app_name
1889         handle_options
1890         collect_tasks
1891       end
1892     end
1894     # Find the rakefile and then load it and any pending imports.
1895     def load_rakefile
1896       standard_exception_handling do
1897         raw_load_rakefile
1898       end
1899     end
1901     # Run the top level tasks of a Rake application.
1902     def top_level
1903       standard_exception_handling do
1904         if options.show_tasks
1905           display_tasks_and_comments
1906         elsif options.show_prereqs
1907           display_prerequisites
1908         else
1909           top_level_tasks.each { |task_name| invoke_task(task_name) }
1910         end
1911       end
1912     end
1914     # Add a loader to handle imported files ending in the extension
1915     # +ext+.
1916     def add_loader(ext, loader)
1917       ext = ".#{ext}" unless ext =~ /^\./
1918       @loaders[ext] = loader
1919     end
1921     # Application options from the command line
1922     def options
1923       @options ||= OpenStruct.new
1924     end
1926     # private ----------------------------------------------------------------
1928     def invoke_task(task_string)
1929       name, args = parse_task_string(task_string)
1930       t = self[name]
1931       t.invoke(*args)
1932     end
1934     def parse_task_string(string)
1935       if string =~ /^([^\[]+)(\[(.*)\])$/
1936         name = $1
1937         args = $3.split(/\s*,\s*/)
1938       else
1939         name = string
1940         args = []
1941       end
1942       [name, args]
1943     end
1945     # Provide standard exception handling for the given block.
1946     def standard_exception_handling
1947       begin
1948         yield
1949       rescue SystemExit => ex
1950         # Exit silently with current status
1951         exit(ex.status)
1952       rescue SystemExit, GetoptLong::InvalidOption => ex
1953         # Exit silently
1954         exit(1)
1955       rescue Exception => ex
1956         # Exit with error message
1957         $stderr.puts "rake aborted!"
1958         $stderr.puts ex.message
1959         if options.trace
1960           $stderr.puts ex.backtrace.join("\n")
1961         else
1962           $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
1963           $stderr.puts "(See full trace by running task with --trace)"
1964         end
1965         exit(1)
1966       end
1967     end
1969     # True if one of the files in RAKEFILES is in the current directory.
1970     # If a match is found, it is copied into @rakefile.
1971     def have_rakefile
1972       @rakefiles.each do |fn|
1973         if File.exist?(fn) || fn == ''
1974           @rakefile = fn
1975           return true
1976         end
1977       end
1978       return false
1979     end
1981     # Display the rake command line help.
1982     def help
1983       puts "rake [-f rakefile] {options} targets..."
1984       puts
1985       puts "Options are ..."
1986       puts
1987       OPTIONS.sort.each do |long, short, mode, desc|
1988         if mode == GetoptLong::REQUIRED_ARGUMENT
1989           if desc =~ /\b([A-Z]{2,})\b/
1990             long = long + "=#{$1}"
1991           end
1992         end
1993         printf "  %-20s (%s)\n", long, short
1994         printf "      %s\n", desc
1995       end
1996     end
1998     # Display the tasks and dependencies.
1999     def display_tasks_and_comments
2000       displayable_tasks = tasks.select { |t|
2001         t.comment && t.name =~ options.show_task_pattern
2002       }
2003       if options.full_description
2004         displayable_tasks.each do |t|
2005           puts "rake #{t.name_with_args}"
2006           t.full_comment.split("\n").each do |line|
2007             puts "    #{line}"
2008           end
2009           puts
2010         end
2011       else
2012         width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
2013         max_column = 80 - name.size - width - 7
2014         displayable_tasks.each do |t|
2015           printf "#{name} %-#{width}s  # %s\n",
2016             t.name_with_args, truncate(t.comment, max_column)
2017         end
2018       end
2019     end
2021     def truncate(string, width)
2022       if string.length <= width
2023         string
2024       else
2025         string[0, width-3] + "..."
2026       end
2027     end
2029     # Display the tasks and prerequisites
2030     def display_prerequisites
2031       tasks.each do |t|
2032         puts "rake #{t.name}"
2033         t.prerequisites.each { |pre| puts "    #{pre}" }
2034       end
2035     end
2037     # Return a list of the command line options supported by the
2038     # program.
2039     def command_line_options
2040       OPTIONS.collect { |lst| lst[0..-2] }
2041     end
2043     # Do the option defined by +opt+ and +value+.
2044     def do_option(opt, value)
2045       case opt
2046       when '--describe'
2047         options.show_tasks = true
2048         options.show_task_pattern = Regexp.new(value || '.')
2049         options.full_description = true
2050       when '--dry-run'
2051         verbose(true)
2052         nowrite(true)
2053         options.dryrun = true
2054         options.trace = true
2055       when '--help'
2056         help
2057         exit
2058       when '--libdir'
2059         $:.push(value)
2060       when '--nosearch'
2061         options.nosearch = true
2062       when '--prereqs'
2063         options.show_prereqs = true
2064       when '--quiet'
2065         verbose(false)
2066       when '--rakefile'
2067         @rakefiles.clear
2068         @rakefiles << value
2069       when '--rakelibdir'
2070         options.rakelib = value.split(':')
2071       when '--require'
2072         begin
2073           require value
2074         rescue LoadError => ex
2075           begin
2076             rake_require value
2077           rescue LoadError => ex2
2078             raise ex
2079           end
2080         end
2081       when '--silent'
2082         verbose(false)
2083         options.silent = true
2084       when '--tasks'
2085         options.show_tasks = true
2086         options.show_task_pattern = Regexp.new(value || '.')
2087         options.full_description = false
2088       when '--trace'
2089         options.trace = true
2090         verbose(true)
2091       when '--verbose'
2092         verbose(true)
2093       when '--version'
2094         puts "rake, version #{RAKEVERSION}"
2095         exit
2096       when '--classic-namespace'
2097         require 'rake/classic_namespace'
2098         options.classic_namespace = true
2099       end
2100     end
2102     # Read and handle the command line options.
2103     def handle_options
2104       options.rakelib = ['rakelib']
2106       opts = GetoptLong.new(*command_line_options)
2107       opts.each { |opt, value| do_option(opt, value) }
2109       # If class namespaces are requested, set the global options
2110       # according to the values in the options structure.
2111       if options.classic_namespace
2112         $show_tasks = options.show_tasks
2113         $show_prereqs = options.show_prereqs
2114         $trace = options.trace
2115         $dryrun = options.dryrun
2116         $silent = options.silent
2117       end
2118     rescue NoMethodError => ex
2119       raise GetoptLong::InvalidOption, "While parsing options, error = #{ex.class}:#{ex.message}"
2120     end
2122     # Similar to the regular Ruby +require+ command, but will check
2123     # for .rake files in addition to .rb files.
2124     def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
2125       return false if loaded.include?(file_name)
2126       paths.each do |path|
2127         fn = file_name + ".rake"
2128         full_path = File.join(path, fn)
2129         if File.exist?(full_path)
2130           load full_path
2131           loaded << fn
2132           return true
2133         end
2134       end
2135       fail LoadError, "Can't find #{file_name}"
2136     end
2138     def raw_load_rakefile # :nodoc:
2139       here = Dir.pwd
2140       while ! have_rakefile
2141         Dir.chdir("..")
2142         if Dir.pwd == here || options.nosearch
2143           fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})"
2144         end
2145         here = Dir.pwd
2146       end
2147       puts "(in #{Dir.pwd})" unless options.silent
2148       $rakefile = @rakefile
2149       load File.expand_path(@rakefile) if @rakefile != ''
2150       options.rakelib.each do |rlib|
2151         Dir["#{rlib}/*.rake"].each do |name| add_import name end
2152       end
2153       load_imports
2154     end
2156     # Collect the list of tasks on the command line.  If no tasks are
2157     # given, return a list containing only the default task.
2158     # Environmental assignments are processed at this time as well.
2159     def collect_tasks
2160       @top_level_tasks = []
2161       ARGV.each do |arg|
2162         if arg =~ /^(\w+)=(.*)$/
2163           ENV[$1] = $2
2164         else
2165           @top_level_tasks << arg
2166         end
2167       end
2168       @top_level_tasks.push("default") if @top_level_tasks.size == 0
2169     end
2171     # Add a file to the list of files to be imported.
2172     def add_import(fn)
2173       @pending_imports << fn
2174     end
2176     # Load the pending list of imported files.
2177     def load_imports
2178       while fn = @pending_imports.shift
2179         next if @imported.member?(fn)
2180         if fn_task = lookup(fn)
2181           fn_task.invoke
2182         end
2183         ext = File.extname(fn)
2184         loader = @loaders[ext] || @default_loader
2185         loader.load(fn)
2186         @imported << fn
2187       end
2188     end
2190     # Warn about deprecated use of top level constant names.
2191     def const_warning(const_name)
2192       @const_warning ||= false
2193       if ! @const_warning
2194         $stderr.puts %{WARNING: Deprecated reference to top-level constant '#{const_name}' } +
2195           %{found at: #{rakefile_location}} # '
2196         $stderr.puts %{    Use --classic-namespace on rake command}
2197         $stderr.puts %{    or 'require "rake/classic_namespace"' in Rakefile}
2198       end
2199       @const_warning = true
2200     end
2202     def rakefile_location
2203       begin
2204         fail
2205       rescue RuntimeError => ex
2206         ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
2207       end
2208     end
2209   end
2213 class Module
2214   # Rename the original handler to make it available.
2215   alias :rake_original_const_missing :const_missing
2217   # Check for deprecated uses of top level (i.e. in Object) uses of
2218   # Rake class names.  If someone tries to reference the constant
2219   # name, display a warning and return the proper object.  Using the
2220   # --classic-namespace command line option will define these
2221   # constants in Object and avoid this handler.
2222   def const_missing(const_name)
2223     case const_name
2224     when :Task
2225       Rake.application.const_warning(const_name)
2226       Rake::Task
2227     when :FileTask
2228       Rake.application.const_warning(const_name)
2229       Rake::FileTask
2230     when :FileCreationTask
2231       Rake.application.const_warning(const_name)
2232       Rake::FileCreationTask
2233     when :RakeApp
2234       Rake.application.const_warning(const_name)
2235       Rake::Application
2236     else
2237       rake_original_const_missing(const_name)
2238     end
2239   end