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
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.
41
######################################################################
42
# Rake extensions to 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.
53
# rake_extension("xyz") do
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"
70
######################################################################
71
# User defined methods to be added to String.
74
rake_extension("ext") do
75
# Replace the file extension with +newext+. If there is no extenson 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.
79
# +ext+ is a user added method for the String class.
81
return self.dup if ['.', '..'].include? self
83
newext = (newext =~ /^\./) ? newext : ("." + newext)
85
dup.sub!(%r(([^/\\])\.[^./\\]*$)) { $1 + newext } || self + newext
89
rake_extension("pathmap") do
90
# Explode a path into individual components. Used by +pathmap+.
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]
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
109
dirs.reverse[0...-n].reverse
113
File.join(partial_dirs)
115
protected :pathmap_partial
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)
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)
127
result = result.sub(pattern, replacement)
129
result = result.sub(pattern, '')
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
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
147
# * <b>%X</b> -- Everything *but* the file extension.
148
# * <b>%s</b> -- The alternate file separater if defined, otherwise use
149
# the standard file separator.
150
# * <b>%%</b> -- A percent sign.
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.
159
# 'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b'
160
# 'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d'
162
# Also the %d, %p, $f, $n, %x, and %X operators can take a
163
# pattern/replacement argument to perform simple string substititions on a
164
# particular part of the path. The pattern and replacement are speparated
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").
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
177
# "src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")
181
# "bin/org/onestepback/proj/A.class"
183
# If the replacement text is '*', then a block may be provided to perform
184
# some arbitrary calculation for the replacement.
188
# "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext|
194
# "/path/to/file.txt"
196
def pathmap(spec=nil, &block)
197
return self if spec.nil?
199
spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
202
result << File.basename(self)
204
result << File.basename(self).ext
206
result << File.dirname(self)
208
result << $1 if self =~ /[^\/](\.[^.]+)$/
210
if self =~ /^(.*[^\/])(\.[^.]+)$/
218
result << (File::ALT_SEPARATOR || File::SEPARATOR)
224
result << pathmap_partial($1.to_i)
225
when /^%\{([^}]*)\}(\d*[dpfnxX])/
226
patterns, operator = $1, $2
227
result << pathmap('%' + operator).pathmap_replace(patterns, &block)
229
fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'"
239
##############################################################################
242
# --------------------------------------------------------------------------
243
# Rake module singleton methods.
246
# Current Rake Application
248
@application ||= Rake::Application.new
251
# Set the current Rake application object.
252
def application=(app)
256
# Return the original directory where the Rake application was started.
258
application.original_dir
263
# ##########################################################################
264
# Mixin for creating easily cloned objects.
267
# Clone an object by making a new object and setting all the instance
268
# variables to the same values.
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)
281
####################################################################
282
# TaskAguments manage the arguments passed to a task.
289
def initialize(names, values, parent=nil)
293
names.each_with_index { |name, i|
294
@hash[name.to_sym] = values[i]
298
# Create a new argument scope using the prerequisite argument
301
values = names.collect { |n| self[n] }
302
self.class.new(names, values, self)
305
# Find an argument value by name or index.
314
def method_missing(sym, *args, &block)
333
if @hash.has_key?(name)
335
elsif ENV.has_key?(name.to_s)
337
elsif ENV.has_key?(name.to_s.upcase)
338
ENV[name.to_s.upcase]
345
####################################################################
346
# InvocationChain tracks the chain of task invocations to detect
347
# circular dependencies.
348
class InvocationChain
349
def initialize(value, tail)
355
@value == obj || @tail.member?(obj)
360
fail RuntimeError, "Circular dependency detected: #{to_s} => #{value}"
362
self.class.new(value, self)
369
def self.append(value, chain)
379
class EmptyInvocationChain
384
InvocationChain.new(value, self)
391
EMPTY = EmptyInvocationChain.new
393
end # class InvocationChain
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.
405
# Tasks are not usually created directly using the new method, but rather
406
# use the +file+ and +task+ convenience methods.
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
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.
431
"<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
434
# List of sources for task.
440
# First source from a rule (nil if no sources)
442
@sources.first if defined?(@sources)
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[]
451
@already_invoked = false
456
@scope = app.current_scope
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?
467
# Name of the task, including any namespace qualifiers.
472
# Name of task with argument list description.
473
def name_with_args # :nodoc:
475
"#{name}#{arg_description}"
481
# Argument description (nil if none).
482
def arg_description # :nodoc:
483
@arg_names ? "[#{(arg_names || []).join(',')}]" : nil
486
# Name of arguments for this task.
491
# Invoke the task if it is needed. Prerequites are invoked first.
493
task_args = TaskArguments.new(arg_names, args)
494
invoke_with_call_chain(task_args, InvocationChain::EMPTY)
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)
502
if application.options.trace
503
puts "** Invoke #{name} #{format_trace_flags}"
505
return if @already_invoked
506
@already_invoked = true
507
invoke_prerequisites(task_args, new_chain)
508
execute(task_args) if needed?
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)
522
# Format the trace flags for display.
523
def format_trace_flags
525
flags << "first_time" unless @already_invoked
526
flags << "not_needed" unless needed?
527
flags.empty? ? "" : "(" + flags.join(", ") + ")"
529
private :format_trace_flags
531
# Execute the actions associated with this task.
533
if application.options.dryrun
534
puts "** Execute (dry run) #{name}"
537
if application.options.trace
538
puts "** Execute #{name}"
540
application.enhance_with_matching_rule(name) if @actions.empty?
541
@actions.each do |act|
551
# Is this task needed?
556
# Timestamp for this task. Basic tasks return the current time for their
557
# time stamp. Other tasks can be more sophisticated.
559
@prerequisites.collect { |p| application[p].timestamp }.max || Time.now
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?
570
# Writing to the comment attribute is the same as adding a description.
571
def comment=(description)
572
add_description(description)
575
# Add a comment to the task. If a comment alread exists, separate
576
# the new comment with " / ".
577
def add_comment(comment)
579
@full_comment << " / "
583
@full_comment << comment
584
if @full_comment =~ /\A([^.]+?\.)( |$)/
587
@comment = @full_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 }
598
# Return a string describing the internal state of a task. Useful for
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}
610
result << "--#{p.name} (#{p.timestamp})\n"
612
latest_prereq = @prerequisites.collect{|n| application[n].timestamp}.max
613
result << "latest-prerequisite time: #{latest_prereq}\n"
614
result << "................................\n\n"
618
# ----------------------------------------------------------------
619
# Rake Module Methods
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.)
626
Rake.application.clear
629
# List of all defined tasks.
631
Rake.application.tasks
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.
639
Rake.application[task_name]
642
# TRUE if the task name is already defined.
643
def task_defined?(task_name)
644
Rake.application.lookup(task_name) != nil
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)
654
# Define a rule for synthesizing tasks.
655
def create_rule(*args, &block)
656
Rake.application.create_rule(*args, &block)
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
662
def scope_name(scope, task_name)
663
(scope + [task_name]).join(':')
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
676
class FileTask < Task
678
# Is this file task needed? Yes if it doesn't exist, or if its time stamp
681
return true unless File.exist?(name)
682
return true if out_of_date?(timestamp)
686
# Time stamp for file task.
689
File.mtime(name.to_s)
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}
702
# ----------------------------------------------------------------
703
# Task class methods.
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)
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.
720
class FileCreationTask < FileTask
721
# Is this file task needed? Yes if it doesn't exist.
726
# Time stamp for file creation task. This time stamp is earlier
727
# than any other time stamp.
733
# #########################################################################
734
# Same as a regular task, but the immediate prerequisites are done in
735
# parallel using Ruby threads.
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) }
742
threads.each { |t| t.join }
747
# ###########################################################################
748
# Task Definition Functions ...
750
# Declare a basic task.
753
# task :clobber => [:clean] do
757
def task(*args, &block)
758
Rake::Task.define_task(*args, &block)
762
# Declare a file task.
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
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.
788
# directory "testdata/doc"
791
Rake.each_dir_parent(dir) do |d|
793
mkdir_p t.name if ! File.exist?(t.name)
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)
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
815
# ns = namespace "nested" do
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.
827
# rule '.o' => '.c' do |t|
828
# sh %{cc -o #{t.name} #{t.source}}
831
def rule(*args, &block)
832
Rake::Task.create_rule(*args, &block)
835
# Describe the next rake task.
838
# desc "Run the Unit Tests"
839
# task :test => [:build]
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.
858
# import ".depend", "my_rules"
862
Rake.application.add_import(fn)
866
# ###########################################################################
867
# This a FileUtils extension that defines several additional commands to be
868
# added to the FileUtils utility functions.
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
883
# sh 'ls', 'file with spaces'
885
# # check exit status after command runs
886
# sh %{grep pattern file} do |ok, res|
888
# puts "pattern not found (status = #{res.exitstatus})"
893
options = (Hash === cmd.last) ? cmd.pop : {}
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}]"
902
rake_check_options options, :noop, :verbose
903
rake_output_message cmd.join(" ") if options[:verbose]
904
unless options[:noop]
910
# Run a Ruby interpreter with the given arguments.
913
# ruby %{-pe '$_.upcase!' <README}
915
def ruby(*args,&block)
916
options = (Hash === args.last) ? args.pop : {}
917
if args.length > 1 then
918
sh(*([RUBY] + args + [options]), &block)
920
sh("#{RUBY} #{args.first}", options, &block)
924
LN_SUPPORTED = [true]
926
# Attempt to do a normal file link, but fall back to a copy if the link
929
unless LN_SUPPORTED[0]
934
rescue StandardError, NotImplementedError => ex
935
LN_SUPPORTED[0] = false
941
# Split a file path into individual directory names.
944
# split_all("a/b/c") => ['a', 'b', 'c']
947
head, tail = File.split(path)
948
return [tail] if head == '.' || tail == '/'
949
return [head, tail] if head == '/'
950
return split_all(head) + [tail]
954
# ###########################################################################
955
# RakeFileUtils provides a custom version of the FileUtils methods that
956
# respond to the <tt>verbose</tt> and <tt>nowrite</tt> commands.
962
attr_accessor :verbose_flag, :nowrite_flag
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|
972
if opts.include?('verbose')
973
default_options << ':verbose => RakeFileUtils.verbose_flag'
975
if opts.include?('noop')
976
default_options << ':noop => RakeFileUtils.nowrite_flag'
979
next if default_options.empty?
980
module_eval(<<-EOS, __FILE__, __LINE__ + 1)
981
def #{name}( *args, &block )
983
*rake_merge_option(args,
984
#{default_options.join(', ')}
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.
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?
1005
RakeFileUtils.verbose_flag = oldvalue
1008
RakeFileUtils.verbose_flag
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.
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?
1026
RakeFileUtils.nowrite_flag = oldvalue
1032
# Use this function to prevent protentially destructive ruby code from
1033
# running when the :nowrite flag is set.
1037
# when_writing("Building Project") do
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.
1046
def when_writing(msg=nil)
1047
if RakeFileUtils.nowrite_flag
1048
puts "DRYRUN: #{msg}" if msg
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)
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)
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)
1075
optdecl.each do |name|
1078
raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
1080
private :rake_check_options
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
1090
include RakeFileUtils
1091
private(*FileUtils.instance_methods(false))
1092
private(*RakeFileUtils.instance_methods(false))
1094
######################################################################
1097
class RuleRecursionOverflowError < StandardError
1098
def initialize(*args)
1103
def add_target(target)
1108
super + ": [" + @targets.reverse.join(' => ') + "]"
1112
# #########################################################################
1113
# A FileList is essentially an array with a few helper methods defined to
1114
# make file manipulation a bit easier.
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.
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.
1130
# == Method Delegation
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).
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.
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
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
1159
SPECIAL_RETURN = %w[
1160
map collect sort sort_by select find_all reject grep
1161
compact flatten uniq values_at
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)
1172
def #{sym}(*args, &block)
1174
result = @items.send(:#{sym}, *args, &block)
1175
FileList.new.import(result)
1181
def #{sym}(*args, &block)
1183
result = @items.send(:#{sym}, *args, &block)
1184
result.object_id == @items.object_id ? self : result
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.
1195
# file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
1197
# pkg_files = FileList.new('lib/**/*') do |fl|
1198
# fl.exclude(/\bCVS\b/)
1201
def initialize(*patterns)
1204
@exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1205
@exclude_procs = DEFAULT_IGNORE_PROCS.dup
1208
patterns.each { |pattern| include(pattern) }
1209
yield self if block_given?
1212
# Add file names defined by glob patterns to the file list. If an array
1213
# is given, add each element of the array.
1216
# file_list.include("*.java", "*.cfg")
1217
# file_list.include %w( math.c lib.h *.o )
1219
def include(*filenames)
1220
# TODO: check for pending
1221
filenames.each do |fn|
1222
if fn.respond_to? :to_ary
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.
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
1244
# FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
1245
# FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
1247
# If "a.c" is a file, then ...
1248
# FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
1250
# If "a.c" is not a file, then ...
1251
# FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
1253
def exclude(*patterns, &block)
1254
patterns.each do |pat|
1255
@exclude_patterns << pat
1258
@exclude_procs << block
1260
resolve_exclude if ! @pending
1265
# Clear all the exclude patterns so that we exclude nothing.
1267
@exclude_patterns = []
1269
calculate_exclude_regexp if ! @pending
1278
# Return the internal array object.
1284
# Return the internal array object.
1289
# Lie about our class.
1291
klass == Array || super(klass)
1293
alias kind_of? is_a?
1295
# Redefine * to return either a string or a new file list.
1297
result = @items * other
1300
FileList.new.import(result)
1306
# Resolve all the pending adds now.
1310
@pending_add.each do |fn| resolve_add(fn) end
1317
def calculate_exclude_regexp
1319
@exclude_patterns.each do |pat|
1324
Dir[pat].each do |p| ignores << p end
1326
ignores << Regexp.quote(pat)
1332
re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
1333
@exclude_re = Regexp.new(re_str)
1345
private :resolve_add
1348
calculate_exclude_regexp
1349
reject! { |fn| exclude?(fn) }
1352
private :resolve_exclude
1354
# Return a new FileList with the results of running +sub+ against each
1355
# element of the oringal list.
1358
# FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o']
1361
inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
1364
# Return a new FileList with the results of running +gsub+ against each
1365
# element of the original list.
1368
# FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
1369
# => ['lib\\test\\file', 'x\\y']
1372
inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
1375
# Same as +sub+ except that the oringal file list is modified.
1377
each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
1381
# Same as +gsub+ except that the original file list is modified.
1383
each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
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
1390
def pathmap(spec=nil)
1391
collect { |fn| fn.pathmap(spec) }
1394
# Return a new array with <tt>String#ext</tt> method applied to each
1395
# member of the array.
1397
# This method is a shortcut for:
1399
# array.collect { |item| item.ext(newext) }
1401
# +ext+ is a user added method for the Array class.
1403
collect { |fn| fn.ext(newext) }
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
1418
if pattern.match(line)
1420
yield fn, count, line
1422
puts "#{fn}:#{count}:#{line}"
1430
# Return a new file list that only contains file names from the current
1431
# file list that exist on the file system.
1433
select { |fn| File.exist?(fn) }
1436
# Modify the current file list so that it contains only file name that
1437
# exist on the file system.
1440
@items = @items.select { |fn| File.exist?(fn) }
1444
# FileList version of partition. Needed because the nested arrays should
1445
# be FileLists in this version.
1446
def partition(&block) # :nodoc:
1448
result = @items.partition(&block)
1450
FileList.new.import(result[0]),
1451
FileList.new.import(result[1]),
1455
# Convert a FileList to a string by joining all elements with a space.
1461
# Add matching glob patterns.
1462
def add_matching(pattern)
1463
Dir[pattern].each do |fn|
1464
self << fn unless exclude?(fn)
1467
private :add_matching
1469
# Should the given file name be excluded?
1471
calculate_exclude_regexp unless @exclude_re
1472
fn =~ @exclude_re || @exclude_procs.any? { |p| p.call(fn) }
1475
DEFAULT_IGNORE_PATTERNS = [
1476
/(^|[\/\\])CVS([\/\\]|$)/,
1477
/(^|[\/\\])\.svn([\/\\]|$)/,
1481
DEFAULT_IGNORE_PROCS = [
1482
proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
1484
# @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1492
# Create a new file list including the files listed. Similar to:
1494
# FileList.new(*args)
1505
# Yield each file or directory component.
1506
def each_dir_parent(dir)
1508
while dir != '.' && dir.length != old_length
1510
old_length = dir.length
1511
dir = File.dirname(dir)
1517
# Alias FileList to be available at the top level.
1518
FileList = Rake::FileList
1520
# ###########################################################################
1523
# Default Rakefile loader used by +import+.
1526
Kernel.load(File.expand_path(fn))
1530
# EarlyTime is a fake timestamp that occurs _before_ any other time value.
1544
EARLY = EarlyTime.instance
1547
# ###########################################################################
1548
# Extensions to time to allow comparisons with an early time class.
1551
alias rake_original_time_compare :<=>
1553
if Rake::EarlyTime === other
1556
rake_original_time_compare(other)
1563
####################################################################
1564
# The NameSpace class will lookup task names in the the scope
1565
# defined by a +namespace+ command.
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
1576
# Lookup a task named +name+ in the namespace.
1578
@task_manager.lookup(name, @scope)
1581
# Return the list of tasks defined in this namespace.
1588
####################################################################
1589
# The TaskManager module is a mixin for managing tasks.
1591
# Track the last comment made in the Rakefile.
1592
attr_accessor :last_description
1593
alias :last_comment :last_description # Backwards compatibility
1600
@last_description = nil
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]
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)
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)
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}'"
1637
def synthesize_file_task(task_name)
1638
return nil unless File.exist?(task_name)
1639
define_task(Rake::FileTask, task_name)
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 }
1648
if task_name.is_a?(Hash)
1650
task_name = hash.keys[0]
1651
needs = hash[task_name]
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
1658
needs = [needs] unless needs.respond_to?(:to_ary)
1659
[task_name, arg_names, needs]
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)
1676
rescue Rake::RuleRecursionOverflowError => ex
1677
ex.add_target(task_name)
1681
# List of all defined tasks in this application.
1683
@tasks.values.sort_by { |t| t.name }
1686
# Clear all tasks in this application.
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:/
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(/^(\^+)/, '')
1707
scopes = initial_scope
1709
lookup_in_scope(task_name, scopes)
1712
# Lookup the task name
1713
def lookup_in_scope(name, scope)
1716
tn = (scope[0,n] + [name]).join(':')
1723
private :lookup_in_scope
1725
# Return the list of scope names currently active in the task
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
1736
ns = NameSpace.new(self, @scope)
1745
# Generate an anonymous namespace name.
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)
1758
elsif parent = enhance_with_matching_rule(sources.first, level+1)
1764
task = FileTask.define_task({task_name => prereqs}, &block)
1765
task.sources = prereqs
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|
1775
task_name.pathmap(ext)
1789
fail "Don't know how to handle rule dependent: #{ext.inspect}"
1796
######################################################################
1797
# Rake main application object. When invoking +rake+ from the
1798
# command line, a Rake::Application object is created and run.
1803
# The name of the application (typically 'rake')
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."],
1852
# Initialize a Rake::Application object.
1856
@rakefiles = DEFAULT_RAKEFILES.dup
1858
@pending_imports = []
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)
1868
# Run the Rake application. The run method performs the following three steps:
1870
# * Initialize the command line options (+init+).
1871
# * Define the tasks (+load_rakefile+).
1872
# * Run the top level tasks (+run_tasks+).
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
1878
standard_exception_handling do
1885
# Initialize the command line parameters and app name.
1886
def init(app_name='rake')
1887
standard_exception_handling do
1894
# Find the rakefile and then load it and any pending imports.
1896
standard_exception_handling do
1901
# Run the top level tasks of a Rake application.
1903
standard_exception_handling do
1904
if options.show_tasks
1905
display_tasks_and_comments
1906
elsif options.show_prereqs
1907
display_prerequisites
1909
top_level_tasks.each { |task_name| invoke_task(task_name) }
1914
# Add a loader to handle imported files ending in the extension
1916
def add_loader(ext, loader)
1917
ext = ".#{ext}" unless ext =~ /^\./
1918
@loaders[ext] = loader
1921
# Application options from the command line
1923
@options ||= OpenStruct.new
1926
# private ----------------------------------------------------------------
1928
def invoke_task(task_string)
1929
name, args = parse_task_string(task_string)
1934
def parse_task_string(string)
1935
if string =~ /^([^\[]+)(\[(.*)\])$/
1937
args = $3.split(/\s*,\s*/)
1945
# Provide standard execption handling for the given block.
1946
def standard_exception_handling
1949
rescue SystemExit => ex
1950
# Exit silently with current status
1952
rescue SystemExit, GetoptLong::InvalidOption => ex
1955
rescue Exception => ex
1956
# Exit with error message
1957
$stderr.puts "rake aborted!"
1958
$stderr.puts ex.message
1960
$stderr.puts ex.backtrace.join("\n")
1962
$stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
1963
$stderr.puts "(See full trace by running task with --trace)"
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.
1972
@rakefiles.each do |fn|
1973
if File.exist?(fn) || fn == ''
1981
# Display the rake command line help.
1983
puts "rake [-f rakefile] {options} targets..."
1985
puts "Options are ..."
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}"
1993
printf " %-20s (%s)\n", long, short
1994
printf " %s\n", desc
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
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|
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)
2021
def truncate(string, width)
2022
if string.length <= width
2025
string[0, width-3] + "..."
2029
# Display the tasks and prerequisites
2030
def display_prerequisites
2032
puts "rake #{t.name}"
2033
t.prerequisites.each { |pre| puts " #{pre}" }
2037
# Return a list of the command line options supported by the
2039
def command_line_options
2040
OPTIONS.collect { |lst| lst[0..-2] }
2043
# Do the option defined by +opt+ and +value+.
2044
def do_option(opt, value)
2047
options.show_tasks = true
2048
options.show_task_pattern = Regexp.new(value || '.')
2049
options.full_description = true
2053
options.dryrun = true
2054
options.trace = true
2061
options.nosearch = true
2063
options.show_prereqs = true
2070
options.rakelib = value.split(':')
2074
rescue LoadError => ex
2077
rescue LoadError => ex2
2083
options.silent = true
2085
options.show_tasks = true
2086
options.show_task_pattern = Regexp.new(value || '.')
2087
options.full_description = false
2089
options.trace = true
2094
puts "rake, version #{RAKEVERSION}"
2096
when '--classic-namespace'
2097
require 'rake/classic_namespace'
2098
options.classic_namespace = true
2102
# Read and handle the command line 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
2118
rescue NoMethodError => ex
2119
raise GetoptLong::InvalidOption, "While parsing options, error = #{ex.class}:#{ex.message}"
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)
2135
fail LoadError, "Can't find #{file_name}"
2138
def raw_load_rakefile # :nodoc:
2140
while ! have_rakefile
2142
if Dir.pwd == here || options.nosearch
2143
fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})"
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
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.
2160
@top_level_tasks = []
2162
if arg =~ /^(\w+)=(.*)$/
2165
@top_level_tasks << arg
2168
@top_level_tasks.push("default") if @top_level_tasks.size == 0
2171
# Add a file to the list of files to be imported.
2173
@pending_imports << fn
2176
# Load the pending list of imported files.
2178
while fn = @pending_imports.shift
2179
next if @imported.member?(fn)
2180
if fn_task = lookup(fn)
2183
ext = File.extname(fn)
2184
loader = @loaders[ext] || @default_loader
2190
# Warn about deprecated use of top level constant names.
2191
def const_warning(const_name)
2192
@const_warning ||= false
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}
2199
@const_warning = true
2202
def rakefile_location
2205
rescue RuntimeError => ex
2206
ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
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)
2225
Rake.application.const_warning(const_name)
2228
Rake.application.const_warning(const_name)
2230
when :FileCreationTask
2231
Rake.application.const_warning(const_name)
2232
Rake::FileCreationTask
2234
Rake.application.const_warning(const_name)
2237
rake_original_const_missing(const_name)