summaryrefslogtreecommitdiff
path: root/ruby_2_2/lib/rake
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-12-14 15:09:35 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-12-14 15:09:35 +0000
commit1a74fa4b04da04bd2bb33103dd3cf431438df38e (patch)
treef4a1d6c2961339e0c1d653c0f8427a53315080f0 /ruby_2_2/lib/rake
parenta5b755e50e2d9aabf28ba24bf58644ca22b01a4f (diff)
add tag v2_2_9
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v2_2_9@61257 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ruby_2_2/lib/rake')
-rw-r--r--ruby_2_2/lib/rake/alt_system.rb110
-rw-r--r--ruby_2_2/lib/rake/application.rb790
-rw-r--r--ruby_2_2/lib/rake/backtrace.rb23
-rw-r--r--ruby_2_2/lib/rake/clean.rb76
-rw-r--r--ruby_2_2/lib/rake/cloneable.rb16
-rw-r--r--ruby_2_2/lib/rake/contrib/.document1
-rw-r--r--ruby_2_2/lib/rake/contrib/compositepublisher.rb21
-rw-r--r--ruby_2_2/lib/rake/contrib/ftptools.rb137
-rw-r--r--ruby_2_2/lib/rake/contrib/publisher.rb81
-rw-r--r--ruby_2_2/lib/rake/contrib/rubyforgepublisher.rb18
-rw-r--r--ruby_2_2/lib/rake/contrib/sshpublisher.rb61
-rw-r--r--ruby_2_2/lib/rake/contrib/sys.rb4
-rw-r--r--ruby_2_2/lib/rake/cpu_counter.rb125
-rw-r--r--ruby_2_2/lib/rake/default_loader.rb14
-rw-r--r--ruby_2_2/lib/rake/dsl_definition.rb201
-rw-r--r--ruby_2_2/lib/rake/early_time.rb21
-rw-r--r--ruby_2_2/lib/rake/ext/core.rb25
-rw-r--r--ruby_2_2/lib/rake/ext/module.rb2
-rw-r--r--ruby_2_2/lib/rake/ext/pathname.rb25
-rw-r--r--ruby_2_2/lib/rake/ext/string.rb173
-rw-r--r--ruby_2_2/lib/rake/ext/time.rb16
-rw-r--r--ruby_2_2/lib/rake/file_creation_task.rb24
-rw-r--r--ruby_2_2/lib/rake/file_list.rb428
-rw-r--r--ruby_2_2/lib/rake/file_task.rb46
-rw-r--r--ruby_2_2/lib/rake/file_utils.rb128
-rw-r--r--ruby_2_2/lib/rake/file_utils_ext.rb144
-rw-r--r--ruby_2_2/lib/rake/gempackagetask.rb4
-rw-r--r--ruby_2_2/lib/rake/invocation_chain.rb56
-rw-r--r--ruby_2_2/lib/rake/invocation_exception_mixin.rb16
-rw-r--r--ruby_2_2/lib/rake/late_time.rb17
-rw-r--r--ruby_2_2/lib/rake/linked_list.rb103
-rw-r--r--ruby_2_2/lib/rake/loaders/makefile.rb40
-rw-r--r--ruby_2_2/lib/rake/multi_task.rb13
-rw-r--r--ruby_2_2/lib/rake/name_space.rb38
-rw-r--r--ruby_2_2/lib/rake/packagetask.rb199
-rw-r--r--ruby_2_2/lib/rake/pathmap.rb3
-rw-r--r--ruby_2_2/lib/rake/phony.rb15
-rw-r--r--ruby_2_2/lib/rake/private_reader.rb20
-rw-r--r--ruby_2_2/lib/rake/promise.rb99
-rw-r--r--ruby_2_2/lib/rake/pseudo_status.rb29
-rw-r--r--ruby_2_2/lib/rake/rake_module.rb38
-rw-r--r--ruby_2_2/lib/rake/rake_test_loader.rb22
-rw-r--r--ruby_2_2/lib/rake/rdoctask.rb4
-rw-r--r--ruby_2_2/lib/rake/ruby182_test_unit_fix.rb29
-rw-r--r--ruby_2_2/lib/rake/rule_recursion_overflow_error.rb20
-rw-r--r--ruby_2_2/lib/rake/runtest.rb27
-rw-r--r--ruby_2_2/lib/rake/scope.rb42
-rw-r--r--ruby_2_2/lib/rake/task.rb383
-rw-r--r--ruby_2_2/lib/rake/task_argument_error.rb7
-rw-r--r--ruby_2_2/lib/rake/task_arguments.rb98
-rw-r--r--ruby_2_2/lib/rake/task_manager.rb310
-rw-r--r--ruby_2_2/lib/rake/tasklib.rb24
-rw-r--r--ruby_2_2/lib/rake/testtask.rb212
-rw-r--r--ruby_2_2/lib/rake/thread_history_display.rb48
-rw-r--r--ruby_2_2/lib/rake/thread_pool.rb164
-rw-r--r--ruby_2_2/lib/rake/trace_output.rb22
-rw-r--r--ruby_2_2/lib/rake/version.rb7
-rw-r--r--ruby_2_2/lib/rake/win32.rb56
58 files changed, 4875 insertions, 0 deletions
diff --git a/ruby_2_2/lib/rake/alt_system.rb b/ruby_2_2/lib/rake/alt_system.rb
new file mode 100644
index 0000000000..aa7b7791b6
--- /dev/null
+++ b/ruby_2_2/lib/rake/alt_system.rb
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2008 James M. Lawrence
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+require 'rbconfig'
+
+##
+# Alternate implementations of system() and backticks `` on Windows
+# for ruby-1.8 and earlier.
+#--
+# TODO: Remove in Rake 11
+
+module Rake::AltSystem # :nodoc: all
+ WINDOWS = RbConfig::CONFIG["host_os"] =~
+ %r!(msdos|mswin|djgpp|mingw|[Ww]indows)!
+
+ class << self
+ def define_module_function(name, &block)
+ define_method(name, &block)
+ module_function(name)
+ end
+ end
+
+ if WINDOWS && RUBY_VERSION < "1.9.0"
+ RUNNABLE_EXTS = %w[com exe bat cmd]
+ RUNNABLE_PATTERN = %r!\.(#{RUNNABLE_EXTS.join('|')})\Z!i
+
+ define_module_function :kernel_system, &Kernel.method(:system)
+ define_module_function :kernel_backticks, &Kernel.method(:'`')
+
+ module_function
+
+ def repair_command(cmd)
+ "call " + (
+ if cmd =~ %r!\A\s*\".*?\"!
+ # already quoted
+ cmd
+ elsif match = cmd.match(%r!\A\s*(\S+)!)
+ if match[1] =~ %r!/!
+ # avoid x/y.bat interpretation as x with option /y
+ %Q!"#{match[1]}"! + match.post_match
+ else
+ # a shell command will fail if quoted
+ cmd
+ end
+ else
+ # empty or whitespace
+ cmd
+ end
+ )
+ end
+
+ def find_runnable(file)
+ if file =~ RUNNABLE_PATTERN
+ file
+ else
+ RUNNABLE_EXTS.each { |ext|
+ test = "#{file}.#{ext}"
+ return test if File.exist?(test)
+ }
+ nil
+ end
+ end
+
+ def system(cmd, *args)
+ repaired = (
+ if args.empty?
+ [repair_command(cmd)]
+ elsif runnable = find_runnable(cmd)
+ [File.expand_path(runnable), *args]
+ else
+ # non-existent file
+ [cmd, *args]
+ end
+ )
+ kernel_system(*repaired)
+ end
+
+ def backticks(cmd)
+ kernel_backticks(repair_command(cmd))
+ end
+
+ define_module_function :'`', &method(:backticks)
+ else
+ # Non-Windows or ruby-1.9+: same as Kernel versions
+ define_module_function :system, &Kernel.method(:system)
+ define_module_function :backticks, &Kernel.method(:'`')
+ define_module_function :'`', &Kernel.method(:'`')
+ end
+end
diff --git a/ruby_2_2/lib/rake/application.rb b/ruby_2_2/lib/rake/application.rb
new file mode 100644
index 0000000000..bd72a2efae
--- /dev/null
+++ b/ruby_2_2/lib/rake/application.rb
@@ -0,0 +1,790 @@
+require 'shellwords'
+require 'optparse'
+
+require 'rake/task_manager'
+require 'rake/file_list'
+require 'rake/thread_pool'
+require 'rake/thread_history_display'
+require 'rake/trace_output'
+require 'rake/win32'
+
+module Rake
+
+ CommandLineOptionError = Class.new(StandardError)
+
+ ##
+ # Rake main application object. When invoking +rake+ from the
+ # command line, a Rake::Application object is created and run.
+
+ class Application
+ include TaskManager
+ include TraceOutput
+
+ # The name of the application (typically 'rake')
+ attr_reader :name
+
+ # The original directory where rake was invoked.
+ attr_reader :original_dir
+
+ # Name of the actual rakefile used.
+ attr_reader :rakefile
+
+ # Number of columns on the terminal
+ attr_accessor :terminal_columns
+
+ # List of the top level task names (task names from the command line).
+ attr_reader :top_level_tasks
+
+ DEFAULT_RAKEFILES = [
+ 'rakefile',
+ 'Rakefile',
+ 'rakefile.rb',
+ 'Rakefile.rb'
+ ].freeze
+
+ # Initialize a Rake::Application object.
+ def initialize
+ super
+ @name = 'rake'
+ @rakefiles = DEFAULT_RAKEFILES.dup
+ @rakefile = nil
+ @pending_imports = []
+ @imported = []
+ @loaders = {}
+ @default_loader = Rake::DefaultLoader.new
+ @original_dir = Dir.pwd
+ @top_level_tasks = []
+ add_loader('rb', DefaultLoader.new)
+ add_loader('rf', DefaultLoader.new)
+ add_loader('rake', DefaultLoader.new)
+ @tty_output = STDOUT.tty?
+ @terminal_columns = ENV['RAKE_COLUMNS'].to_i
+ end
+
+ # Run the Rake application. The run method performs the following
+ # three steps:
+ #
+ # * Initialize the command line options (+init+).
+ # * Define the tasks (+load_rakefile+).
+ # * Run the top level tasks (+top_level+).
+ #
+ # If you wish to build a custom rake command, you should call
+ # +init+ on your application. Then define any tasks. Finally,
+ # call +top_level+ to run your top level tasks.
+ def run
+ standard_exception_handling do
+ init
+ load_rakefile
+ top_level
+ end
+ end
+
+ # Initialize the command line parameters and app name.
+ def init(app_name='rake')
+ standard_exception_handling do
+ @name = app_name
+ args = handle_options
+ collect_command_line_tasks(args)
+ end
+ end
+
+ # Find the rakefile and then load it and any pending imports.
+ def load_rakefile
+ standard_exception_handling do
+ raw_load_rakefile
+ end
+ end
+
+ # Run the top level tasks of a Rake application.
+ def top_level
+ run_with_threads do
+ if options.show_tasks
+ display_tasks_and_comments
+ elsif options.show_prereqs
+ display_prerequisites
+ else
+ top_level_tasks.each { |task_name| invoke_task(task_name) }
+ end
+ end
+ end
+
+ # Run the given block with the thread startup and shutdown.
+ def run_with_threads
+ thread_pool.gather_history if options.job_stats == :history
+
+ yield
+
+ thread_pool.join
+ if options.job_stats
+ stats = thread_pool.statistics
+ puts "Maximum active threads: #{stats[:max_active_threads]} + main"
+ puts "Total threads in play: #{stats[:total_threads_in_play]} + main"
+ end
+ ThreadHistoryDisplay.new(thread_pool.history).show if
+ options.job_stats == :history
+ end
+
+ # Add a loader to handle imported files ending in the extension
+ # +ext+.
+ def add_loader(ext, loader)
+ ext = ".#{ext}" unless ext =~ /^\./
+ @loaders[ext] = loader
+ end
+
+ # Application options from the command line
+ def options
+ @options ||= OpenStruct.new
+ end
+
+ # Return the thread pool used for multithreaded processing.
+ def thread_pool # :nodoc:
+ @thread_pool ||= ThreadPool.new(options.thread_pool_size || Rake.suggested_thread_count-1)
+ end
+
+ # internal ----------------------------------------------------------------
+
+ # Invokes a task with arguments that are extracted from +task_string+
+ def invoke_task(task_string) # :nodoc:
+ name, args = parse_task_string(task_string)
+ t = self[name]
+ t.invoke(*args)
+ end
+
+ def parse_task_string(string) # :nodoc:
+ /^([^\[]+)(?:\[(.*)\])$/ =~ string.to_s
+
+ name = $1
+ remaining_args = $2
+
+ return string, [] unless name
+ return name, [] if remaining_args.empty?
+
+ args = []
+
+ begin
+ /((?:[^\\,]|\\.)*?)\s*(?:,\s*(.*))?$/ =~ remaining_args
+
+ remaining_args = $2
+ args << $1.gsub(/\\(.)/, '\1')
+ end while remaining_args
+
+ return name, args
+ end
+
+ # Provide standard exception handling for the given block.
+ def standard_exception_handling # :nodoc:
+ yield
+ rescue SystemExit
+ # Exit silently with current status
+ raise
+ rescue OptionParser::InvalidOption => ex
+ $stderr.puts ex.message
+ exit(false)
+ rescue Exception => ex
+ # Exit with error message
+ display_error_message(ex)
+ exit_because_of_exception(ex)
+ end
+
+ # Exit the program because of an unhandle exception.
+ # (may be overridden by subclasses)
+ def exit_because_of_exception(ex) # :nodoc:
+ exit(false)
+ end
+
+ # Display the error message that caused the exception.
+ def display_error_message(ex) # :nodoc:
+ trace "#{name} aborted!"
+ display_exception_details(ex)
+ trace "Tasks: #{ex.chain}" if has_chain?(ex)
+ trace "(See full trace by running task with --trace)" unless
+ options.backtrace
+ end
+
+ def display_exception_details(ex) # :nodoc:
+ seen = Thread.current[:rake_display_exception_details_seen] ||= []
+ return if seen.include? ex
+ seen << ex
+
+ display_exception_message_details(ex)
+ display_exception_backtrace(ex)
+ display_exception_details(ex.cause) if has_cause?(ex)
+ end
+
+ def has_cause?(ex) # :nodoc:
+ ex.respond_to?(:cause) && ex.cause
+ end
+
+ def display_exception_message_details(ex) # :nodoc:
+ if ex.instance_of?(RuntimeError)
+ trace ex.message
+ else
+ trace "#{ex.class.name}: #{ex.message}"
+ end
+ end
+
+ def display_exception_backtrace(ex) # :nodoc:
+ if options.backtrace
+ trace ex.backtrace.join("\n")
+ else
+ trace Backtrace.collapse(ex.backtrace).join("\n")
+ end
+ end
+
+ # Warn about deprecated usage.
+ #
+ # Example:
+ # Rake.application.deprecate("import", "Rake.import", caller.first)
+ #
+ def deprecate(old_usage, new_usage, call_site) # :nodoc:
+ unless options.ignore_deprecate
+ $stderr.puts "WARNING: '#{old_usage}' is deprecated. " +
+ "Please use '#{new_usage}' instead.\n" +
+ " at #{call_site}"
+ end
+ end
+
+ # Does the exception have a task invocation chain?
+ def has_chain?(exception) # :nodoc:
+ exception.respond_to?(:chain) && exception.chain
+ end
+ private :has_chain?
+
+ # True if one of the files in RAKEFILES is in the current directory.
+ # If a match is found, it is copied into @rakefile.
+ def have_rakefile # :nodoc:
+ @rakefiles.each do |fn|
+ if File.exist?(fn)
+ others = FileList.glob(fn, File::FNM_CASEFOLD)
+ return others.size == 1 ? others.first : fn
+ elsif fn == ''
+ return fn
+ end
+ end
+ return nil
+ end
+
+ # True if we are outputting to TTY, false otherwise
+ def tty_output? # :nodoc:
+ @tty_output
+ end
+
+ # Override the detected TTY output state (mostly for testing)
+ def tty_output=(tty_output_state) # :nodoc:
+ @tty_output = tty_output_state
+ end
+
+ # We will truncate output if we are outputting to a TTY or if we've been
+ # given an explicit column width to honor
+ def truncate_output? # :nodoc:
+ tty_output? || @terminal_columns.nonzero?
+ end
+
+ # Display the tasks and comments.
+ def display_tasks_and_comments # :nodoc:
+ displayable_tasks = tasks.select { |t|
+ (options.show_all_tasks || t.comment) &&
+ t.name =~ options.show_task_pattern
+ }
+ case options.show_tasks
+ when :tasks
+ width = displayable_tasks.map { |t| t.name_with_args.length }.max || 10
+ if truncate_output?
+ max_column = terminal_width - name.size - width - 7
+ else
+ max_column = nil
+ end
+
+ displayable_tasks.each do |t|
+ printf("#{name} %-#{width}s # %s\n",
+ t.name_with_args,
+ max_column ? truncate(t.comment, max_column) : t.comment)
+ end
+ when :describe
+ displayable_tasks.each do |t|
+ puts "#{name} #{t.name_with_args}"
+ comment = t.full_comment || ""
+ comment.split("\n").each do |line|
+ puts " #{line}"
+ end
+ puts
+ end
+ when :lines
+ displayable_tasks.each do |t|
+ t.locations.each do |loc|
+ printf "#{name} %-30s %s\n", t.name_with_args, loc
+ end
+ end
+ else
+ fail "Unknown show task mode: '#{options.show_tasks}'"
+ end
+ end
+
+ def terminal_width # :nodoc:
+ if @terminal_columns.nonzero?
+ result = @terminal_columns
+ else
+ result = unix? ? dynamic_width : 80
+ end
+ (result < 10) ? 80 : result
+ rescue
+ 80
+ end
+
+ # Calculate the dynamic width of the
+ def dynamic_width # :nodoc:
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
+ end
+
+ def dynamic_width_stty # :nodoc:
+ %x{stty size 2>/dev/null}.split[1].to_i
+ end
+
+ def dynamic_width_tput # :nodoc:
+ %x{tput cols 2>/dev/null}.to_i
+ end
+
+ def unix? # :nodoc:
+ RbConfig::CONFIG['host_os'] =~
+ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
+ end
+
+ def windows? # :nodoc:
+ Win32.windows?
+ end
+
+ def truncate(string, width) # :nodoc:
+ if string.nil?
+ ""
+ elsif string.length <= width
+ string
+ else
+ (string[0, width - 3] || "") + "..."
+ end
+ end
+
+ # Display the tasks and prerequisites
+ def display_prerequisites # :nodoc:
+ tasks.each do |t|
+ puts "#{name} #{t.name}"
+ t.prerequisites.each { |pre| puts " #{pre}" }
+ end
+ end
+
+ def trace(*strings) # :nodoc:
+ options.trace_output ||= $stderr
+ trace_on(options.trace_output, *strings)
+ end
+
+ def sort_options(options) # :nodoc:
+ options.sort_by { |opt|
+ opt.select { |o| o =~ /^-/ }.map { |o| o.downcase }.sort.reverse
+ }
+ end
+ private :sort_options
+
+ # A list of all the standard options used in rake, suitable for
+ # passing to OptionParser.
+ def standard_rake_options # :nodoc:
+ sort_options(
+ [
+ ['--all', '-A',
+ "Show all tasks, even uncommented ones (in combination with -T or -D)",
+ lambda { |value|
+ options.show_all_tasks = value
+ }
+ ],
+ ['--backtrace=[OUT]',
+ "Enable full backtrace. OUT can be stderr (default) or stdout.",
+ lambda { |value|
+ options.backtrace = true
+ select_trace_output(options, 'backtrace', value)
+ }
+ ],
+ ['--build-all', '-B',
+ "Build all prerequisites, including those which are up-to-date.",
+ lambda { |value|
+ options.build_all = true
+ }
+ ],
+ ['--comments',
+ "Show commented tasks only",
+ lambda { |value|
+ options.show_all_tasks = !value
+ }
+ ],
+ ['--describe', '-D [PATTERN]',
+ "Describe the tasks (matching optional PATTERN), then exit.",
+ lambda { |value|
+ select_tasks_to_show(options, :describe, value)
+ }
+ ],
+ ['--dry-run', '-n',
+ "Do a dry run without executing actions.",
+ lambda { |value|
+ Rake.verbose(true)
+ Rake.nowrite(true)
+ options.dryrun = true
+ options.trace = true
+ }
+ ],
+ ['--execute', '-e CODE',
+ "Execute some Ruby code and exit.",
+ lambda { |value|
+ eval(value)
+ exit
+ }
+ ],
+ ['--execute-print', '-p CODE',
+ "Execute some Ruby code, print the result, then exit.",
+ lambda { |value|
+ puts eval(value)
+ exit
+ }
+ ],
+ ['--execute-continue', '-E CODE',
+ "Execute some Ruby code, " +
+ "then continue with normal task processing.",
+ lambda { |value| eval(value) }
+ ],
+ ['--jobs', '-j [NUMBER]',
+ "Specifies the maximum number of tasks to execute in parallel. " +
+ "(default is number of CPU cores + 4)",
+ lambda { |value|
+ if value.nil? || value == ''
+ value = FIXNUM_MAX
+ elsif value =~ /^\d+$/
+ value = value.to_i
+ else
+ value = Rake.suggested_thread_count
+ end
+ value = 1 if value < 1
+ options.thread_pool_size = value - 1
+ }
+ ],
+ ['--job-stats [LEVEL]',
+ "Display job statistics. " +
+ "LEVEL=history displays a complete job list",
+ lambda { |value|
+ if value =~ /^history/i
+ options.job_stats = :history
+ else
+ options.job_stats = true
+ end
+ }
+ ],
+ ['--libdir', '-I LIBDIR',
+ "Include LIBDIR in the search path for required modules.",
+ lambda { |value| $:.push(value) }
+ ],
+ ['--multitask', '-m',
+ "Treat all tasks as multitasks.",
+ lambda { |value| options.always_multitask = true }
+ ],
+ ['--no-search', '--nosearch',
+ '-N', "Do not search parent directories for the Rakefile.",
+ lambda { |value| options.nosearch = true }
+ ],
+ ['--prereqs', '-P',
+ "Display the tasks and dependencies, then exit.",
+ lambda { |value| options.show_prereqs = true }
+ ],
+ ['--quiet', '-q',
+ "Do not log messages to standard output.",
+ lambda { |value| Rake.verbose(false) }
+ ],
+ ['--rakefile', '-f [FILENAME]',
+ "Use FILENAME as the rakefile to search for.",
+ lambda { |value|
+ value ||= ''
+ @rakefiles.clear
+ @rakefiles << value
+ }
+ ],
+ ['--rakelibdir', '--rakelib', '-R RAKELIBDIR',
+ "Auto-import any .rake files in RAKELIBDIR. " +
+ "(default is 'rakelib')",
+ lambda { |value|
+ options.rakelib = value.split(File::PATH_SEPARATOR)
+ }
+ ],
+ ['--require', '-r MODULE',
+ "Require MODULE before executing rakefile.",
+ lambda { |value|
+ begin
+ require value
+ rescue LoadError => ex
+ begin
+ rake_require value
+ rescue LoadError
+ raise ex
+ end
+ end
+ }
+ ],
+ ['--rules',
+ "Trace the rules resolution.",
+ lambda { |value| options.trace_rules = true }
+ ],
+ ['--silent', '-s',
+ "Like --quiet, but also suppresses the " +
+ "'in directory' announcement.",
+ lambda { |value|
+ Rake.verbose(false)
+ options.silent = true
+ }
+ ],
+ ['--suppress-backtrace PATTERN',
+ "Suppress backtrace lines matching regexp PATTERN. " +
+ "Ignored if --trace is on.",
+ lambda { |value|
+ options.suppress_backtrace_pattern = Regexp.new(value)
+ }
+ ],
+ ['--system', '-g',
+ "Using system wide (global) rakefiles " +
+ "(usually '~/.rake/*.rake').",
+ lambda { |value| options.load_system = true }
+ ],
+ ['--no-system', '--nosystem', '-G',
+ "Use standard project Rakefile search paths, " +
+ "ignore system wide rakefiles.",
+ lambda { |value| options.ignore_system = true }
+ ],
+ ['--tasks', '-T [PATTERN]',
+ "Display the tasks (matching optional PATTERN) " +
+ "with descriptions, then exit.",
+ lambda { |value|
+ select_tasks_to_show(options, :tasks, value)
+ }
+ ],
+ ['--trace=[OUT]', '-t',
+ "Turn on invoke/execute tracing, enable full backtrace. " +
+ "OUT can be stderr (default) or stdout.",
+ lambda { |value|
+ options.trace = true
+ options.backtrace = true
+ select_trace_output(options, 'trace', value)
+ Rake.verbose(true)
+ }
+ ],
+ ['--verbose', '-v',
+ "Log message to standard output.",
+ lambda { |value| Rake.verbose(true) }
+ ],
+ ['--version', '-V',
+ "Display the program version.",
+ lambda { |value|
+ puts "rake, version #{RAKEVERSION}"
+ exit
+ }
+ ],
+ ['--where', '-W [PATTERN]',
+ "Describe the tasks (matching optional PATTERN), then exit.",
+ lambda { |value|
+ select_tasks_to_show(options, :lines, value)
+ options.show_all_tasks = true
+ }
+ ],
+ ['--no-deprecation-warnings', '-X',
+ "Disable the deprecation warnings.",
+ lambda { |value|
+ options.ignore_deprecate = true
+ }
+ ],
+ ])
+ end
+
+ def select_tasks_to_show(options, show_tasks, value) # :nodoc:
+ options.show_tasks = show_tasks
+ options.show_task_pattern = Regexp.new(value || '')
+ Rake::TaskManager.record_task_metadata = true
+ end
+ private :select_tasks_to_show
+
+ def select_trace_output(options, trace_option, value) # :nodoc:
+ value = value.strip unless value.nil?
+ case value
+ when 'stdout'
+ options.trace_output = $stdout
+ when 'stderr', nil
+ options.trace_output = $stderr
+ else
+ fail CommandLineOptionError,
+ "Unrecognized --#{trace_option} option '#{value}'"
+ end
+ end
+ private :select_trace_output
+
+ # Read and handle the command line options. Returns the command line
+ # arguments that we didn't understand, which should (in theory) be just
+ # task names and env vars.
+ def handle_options # :nodoc:
+ options.rakelib = ['rakelib']
+ options.trace_output = $stderr
+
+ OptionParser.new do |opts|
+ opts.banner = "#{Rake.application.name} [-f rakefile] {options} targets..."
+ opts.separator ""
+ opts.separator "Options are ..."
+
+ opts.on_tail("-h", "--help", "-H", "Display this help message.") do
+ puts opts
+ exit
+ end
+
+ standard_rake_options.each { |args| opts.on(*args) }
+ opts.environment('RAKEOPT')
+ end.parse(ARGV)
+ end
+
+ # Similar to the regular Ruby +require+ command, but will check
+ # for *.rake files in addition to *.rb files.
+ def rake_require(file_name, paths=$LOAD_PATH, loaded=$") # :nodoc:
+ fn = file_name + ".rake"
+ return false if loaded.include?(fn)
+ paths.each do |path|
+ full_path = File.join(path, fn)
+ if File.exist?(full_path)
+ Rake.load_rakefile(full_path)
+ loaded << fn
+ return true
+ end
+ end
+ fail LoadError, "Can't find #{file_name}"
+ end
+
+ def find_rakefile_location # :nodoc:
+ here = Dir.pwd
+ until (fn = have_rakefile)
+ Dir.chdir("..")
+ return nil if Dir.pwd == here || options.nosearch
+ here = Dir.pwd
+ end
+ [fn, here]
+ ensure
+ Dir.chdir(Rake.original_dir)
+ end
+
+ def print_rakefile_directory(location) # :nodoc:
+ $stderr.puts "(in #{Dir.pwd})" unless
+ options.silent or original_dir == location
+ end
+
+ def raw_load_rakefile # :nodoc:
+ rakefile, location = find_rakefile_location
+ if (! options.ignore_system) &&
+ (options.load_system || rakefile.nil?) &&
+ system_dir && File.directory?(system_dir)
+ print_rakefile_directory(location)
+ glob("#{system_dir}/*.rake") do |name|
+ add_import name
+ end
+ else
+ fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if
+ rakefile.nil?
+ @rakefile = rakefile
+ Dir.chdir(location)
+ print_rakefile_directory(location)
+ Rake.load_rakefile(File.expand_path(@rakefile)) if
+ @rakefile && @rakefile != ''
+ options.rakelib.each do |rlib|
+ glob("#{rlib}/*.rake") do |name|
+ add_import name
+ end
+ end
+ end
+ load_imports
+ end
+
+ def glob(path, &block) # :nodoc:
+ FileList.glob(path.gsub("\\", '/')).each(&block)
+ end
+ private :glob
+
+ # The directory path containing the system wide rakefiles.
+ def system_dir # :nodoc:
+ @system_dir ||=
+ begin
+ if ENV['RAKE_SYSTEM']
+ ENV['RAKE_SYSTEM']
+ else
+ standard_system_dir
+ end
+ end
+ end
+
+ # The standard directory containing system wide rake files.
+ if Win32.windows?
+ def standard_system_dir #:nodoc:
+ Win32.win32_system_dir
+ end
+ else
+ def standard_system_dir #:nodoc:
+ File.join(File.expand_path('~'), '.rake')
+ end
+ end
+ private :standard_system_dir
+
+ # Collect the list of tasks on the command line. If no tasks are
+ # given, return a list containing only the default task.
+ # Environmental assignments are processed at this time as well.
+ #
+ # `args` is the list of arguments to peruse to get the list of tasks.
+ # It should be the command line that was given to rake, less any
+ # recognised command-line options, which OptionParser.parse will
+ # have taken care of already.
+ def collect_command_line_tasks(args) # :nodoc:
+ @top_level_tasks = []
+ args.each do |arg|
+ if arg =~ /^(\w+)=(.*)$/m
+ ENV[$1] = $2
+ else
+ @top_level_tasks << arg unless arg =~ /^-/
+ end
+ end
+ @top_level_tasks.push(default_task_name) if @top_level_tasks.empty?
+ end
+
+ # Default task name ("default").
+ # (May be overridden by subclasses)
+ def default_task_name # :nodoc:
+ "default"
+ end
+
+ # Add a file to the list of files to be imported.
+ def add_import(fn) # :nodoc:
+ @pending_imports << fn
+ end
+
+ # Load the pending list of imported files.
+ def load_imports # :nodoc:
+ while fn = @pending_imports.shift
+ next if @imported.member?(fn)
+ fn_task = lookup(fn) and fn_task.invoke
+ ext = File.extname(fn)
+ loader = @loaders[ext] || @default_loader
+ loader.load(fn)
+ if fn_task = lookup(fn) and fn_task.needed?
+ fn_task.reenable
+ fn_task.invoke
+ loader.load(fn)
+ end
+ @imported << fn
+ end
+ end
+
+ def rakefile_location(backtrace=caller) # :nodoc:
+ backtrace.map { |t| t[/([^:]+):/, 1] }
+
+ re = /^#{@rakefile}$/
+ re = /#{re.source}/i if windows?
+
+ backtrace.find { |str| str =~ re } || ''
+ end
+
+ private
+ FIXNUM_MAX = (2**(0.size * 8 - 2) - 1) # :nodoc:
+
+ end
+end
diff --git a/ruby_2_2/lib/rake/backtrace.rb b/ruby_2_2/lib/rake/backtrace.rb
new file mode 100644
index 0000000000..dc18773436
--- /dev/null
+++ b/ruby_2_2/lib/rake/backtrace.rb
@@ -0,0 +1,23 @@
+module Rake
+ module Backtrace # :nodoc: all
+ SYS_KEYS = RbConfig::CONFIG.keys.grep(/(?:[a-z]prefix|libdir)\z/)
+ SYS_PATHS = RbConfig::CONFIG.values_at(*SYS_KEYS).uniq +
+ [ File.join(File.dirname(__FILE__), "..") ]
+
+ SUPPRESSED_PATHS = SYS_PATHS.
+ map { |s| s.gsub("\\", "/") }.
+ map { |f| File.expand_path(f) }.
+ reject { |s| s.nil? || s =~ /^ *$/ }
+ SUPPRESSED_PATHS_RE = SUPPRESSED_PATHS.map { |f| Regexp.quote(f) }.join("|")
+ SUPPRESSED_PATHS_RE << "|^org\\/jruby\\/\\w+\\.java" if
+ Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
+
+ SUPPRESS_PATTERN = %r!(\A(#{SUPPRESSED_PATHS_RE})|bin/rake:\d+)!i
+
+ def self.collapse(backtrace)
+ pattern = Rake.application.options.suppress_backtrace_pattern ||
+ SUPPRESS_PATTERN
+ backtrace.reject { |elem| elem =~ pattern }
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/clean.rb b/ruby_2_2/lib/rake/clean.rb
new file mode 100644
index 0000000000..a49cd44167
--- /dev/null
+++ b/ruby_2_2/lib/rake/clean.rb
@@ -0,0 +1,76 @@
+# The 'rake/clean' file defines two file lists (CLEAN and CLOBBER) and
+# two rake tasks (:clean and :clobber).
+#
+# [:clean] Clean up the project by deleting scratch files and backup
+# files. Add files to the CLEAN file list to have the :clean
+# target handle them.
+#
+# [:clobber] Clobber all generated and non-source files in a project.
+# The task depends on :clean, so all the clean files will
+# be deleted as well as files in the CLOBBER file list.
+# The intent of this task is to return a project to its
+# pristine, just unpacked state.
+
+require 'rake'
+
+# :stopdoc:
+
+module Rake
+ module Cleaner
+ extend FileUtils
+
+ module_function
+
+ def cleanup_files(file_names)
+ file_names.each do |file_name|
+ cleanup(file_name)
+ end
+ end
+
+ def cleanup(file_name, opts={})
+ begin
+ rm_r file_name, opts
+ rescue StandardError => ex
+ puts "Failed to remove #{file_name}: #{ex}" unless file_already_gone?(file_name)
+ end
+ end
+
+ def file_already_gone?(file_name)
+ return false if File.exist?(file_name)
+
+ path = file_name
+ prev = nil
+
+ while path = File.dirname(path)
+ return false if cant_be_deleted?(path)
+ break if [prev, "."].include?(path)
+ prev = path
+ end
+ true
+ end
+ private_class_method :file_already_gone?
+
+ def cant_be_deleted?(path_name)
+ File.exist?(path_name) &&
+ (!File.readable?(path_name) || !File.executable?(path_name))
+ end
+ private_class_method :cant_be_deleted?
+ end
+end
+
+CLEAN = ::Rake::FileList["**/*~", "**/*.bak", "**/core"]
+CLEAN.clear_exclude.exclude { |fn|
+ fn.pathmap("%f").downcase == 'core' && File.directory?(fn)
+}
+
+desc "Remove any temporary products."
+task :clean do
+ Rake::Cleaner.cleanup_files(CLEAN)
+end
+
+CLOBBER = ::Rake::FileList.new
+
+desc "Remove any generated file."
+task :clobber => [:clean] do
+ Rake::Cleaner.cleanup_files(CLOBBER)
+end
diff --git a/ruby_2_2/lib/rake/cloneable.rb b/ruby_2_2/lib/rake/cloneable.rb
new file mode 100644
index 0000000000..d53645f2f3
--- /dev/null
+++ b/ruby_2_2/lib/rake/cloneable.rb
@@ -0,0 +1,16 @@
+module Rake
+ ##
+ # Mixin for creating easily cloned objects.
+
+ module Cloneable # :nodoc:
+ # The hook that is invoked by 'clone' and 'dup' methods.
+ def initialize_copy(source)
+ super
+ source.instance_variables.each do |var|
+ src_value = source.instance_variable_get(var)
+ value = src_value.clone rescue src_value
+ instance_variable_set(var, value)
+ end
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/contrib/.document b/ruby_2_2/lib/rake/contrib/.document
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/ruby_2_2/lib/rake/contrib/.document
@@ -0,0 +1 @@
+
diff --git a/ruby_2_2/lib/rake/contrib/compositepublisher.rb b/ruby_2_2/lib/rake/contrib/compositepublisher.rb
new file mode 100644
index 0000000000..69952a0808
--- /dev/null
+++ b/ruby_2_2/lib/rake/contrib/compositepublisher.rb
@@ -0,0 +1,21 @@
+module Rake
+
+ # Manage several publishers as a single entity.
+ class CompositePublisher
+ def initialize
+ @publishers = []
+ end
+
+ # Add a publisher to the composite.
+ def add(pub)
+ @publishers << pub
+ end
+
+ # Upload all the individual publishers.
+ def upload
+ @publishers.each { |p| p.upload }
+ end
+ end
+
+end
+
diff --git a/ruby_2_2/lib/rake/contrib/ftptools.rb b/ruby_2_2/lib/rake/contrib/ftptools.rb
new file mode 100644
index 0000000000..b178523bc6
--- /dev/null
+++ b/ruby_2_2/lib/rake/contrib/ftptools.rb
@@ -0,0 +1,137 @@
+# = Tools for FTP uploading.
+#
+# This file is still under development and is not released for general
+# use.
+
+require 'date'
+require 'net/ftp'
+require 'rake/file_list'
+
+module Rake # :nodoc:
+
+ class FtpFile # :nodoc: all
+ attr_reader :name, :size, :owner, :group, :time
+
+ def self.date
+ @date_class ||= Date
+ end
+
+ def self.time
+ @time_class ||= Time
+ end
+
+ def initialize(path, entry)
+ @path = path
+ @mode, _, @owner, @group, size, d1, d2, d3, @name = entry.split(' ')
+ @size = size.to_i
+ @time = determine_time(d1, d2, d3)
+ end
+
+ def path
+ File.join(@path, @name)
+ end
+
+ def directory?
+ @mode[0] == ?d
+ end
+
+ def mode
+ parse_mode(@mode)
+ end
+
+ def symlink?
+ @mode[0] == ?l
+ end
+
+ private # --------------------------------------------------------
+
+ def parse_mode(m)
+ result = 0
+ (1..9).each do |i|
+ result = 2 * result + ((m[i] == ?-) ? 0 : 1)
+ end
+ result
+ end
+
+ def determine_time(d1, d2, d3)
+ now = self.class.time.now
+ if /:/ !~ d3
+ result = Time.parse("#{d1} #{d2} #{d3}")
+ else
+ result = Time.parse("#{d1} #{d2} #{now.year} #{d3}")
+ result = Time.parse("#{d1} #{d2} #{now.year - 1} #{d3}") if
+ result > now
+ end
+ result
+ end
+ end
+
+ ##
+ # Manage the uploading of files to an FTP account.
+ class FtpUploader # :nodoc:
+
+ # Log uploads to standard output when true.
+ attr_accessor :verbose
+
+ class << FtpUploader
+ # Create an uploader and pass it to the given block as +up+.
+ # When the block is complete, close the uploader.
+ def connect(path, host, account, password)
+ up = self.new(path, host, account, password)
+ begin
+ yield(up)
+ ensure
+ up.close
+ end
+ end
+ end
+
+ # Create an FTP uploader targeting the directory +path+ on +host+
+ # using the given account and password. +path+ will be the root
+ # path of the uploader.
+ def initialize(path, host, account, password)
+ @created = Hash.new
+ @path = path
+ @ftp = Net::FTP.new(host, account, password)
+ makedirs(@path)
+ @ftp.chdir(@path)
+ end
+
+ # Create the directory +path+ in the uploader root path.
+ def makedirs(path)
+ route = []
+ File.split(path).each do |dir|
+ route << dir
+ current_dir = File.join(route)
+ if @created[current_dir].nil?
+ @created[current_dir] = true
+ $stderr.puts "Creating Directory #{current_dir}" if @verbose
+ @ftp.mkdir(current_dir) rescue nil
+ end
+ end
+ end
+
+ # Upload all files matching +wildcard+ to the uploader's root
+ # path.
+ def upload_files(wildcard)
+ FileList.glob(wildcard).each do |fn|
+ upload(fn)
+ end
+ end
+
+ # Close the uploader.
+ def close
+ @ftp.close
+ end
+
+ private # --------------------------------------------------------
+
+ # Upload a single file to the uploader's root path.
+ def upload(file)
+ $stderr.puts "Uploading #{file}" if @verbose
+ dir = File.dirname(file)
+ makedirs(dir)
+ @ftp.putbinaryfile(file, file) unless File.directory?(file)
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/contrib/publisher.rb b/ruby_2_2/lib/rake/contrib/publisher.rb
new file mode 100644
index 0000000000..f4ee1abf86
--- /dev/null
+++ b/ruby_2_2/lib/rake/contrib/publisher.rb
@@ -0,0 +1,81 @@
+# Copyright 2003-2010 by Jim Weirich (jim.weirich@gmail.com)
+# All rights reserved.
+
+# :stopdoc:
+
+# Configuration information about an upload host system.
+# name :: Name of host system.
+# webdir :: Base directory for the web information for the
+# application. The application name (APP) is appended to
+# this directory before using.
+# pkgdir :: Directory on the host system where packages can be
+# placed.
+HostInfo = Struct.new(:name, :webdir, :pkgdir)
+
+# :startdoc:
+
+# TODO: Move to contrib/sshpublisher
+#--
+# Manage several publishers as a single entity.
+class CompositePublisher # :nodoc:
+ def initialize
+ @publishers = []
+ end
+
+ # Add a publisher to the composite.
+ def add(pub)
+ @publishers << pub
+ end
+
+ # Upload all the individual publishers.
+ def upload
+ @publishers.each { |p| p.upload }
+ end
+end
+
+# TODO: Remove in Rake 11, duplicated
+#--
+# Publish an entire directory to an existing remote directory using
+# SSH.
+class SshDirPublisher # :nodoc: all
+ def initialize(host, remote_dir, local_dir)
+ @host = host
+ @remote_dir = remote_dir
+ @local_dir = local_dir
+ end
+
+ def upload
+ run %{scp -rq #{@local_dir}/* #{@host}:#{@remote_dir}}
+ end
+end
+
+# TODO: Remove in Rake 11, duplicated
+#--
+# Publish an entire directory to a fresh remote directory using SSH.
+class SshFreshDirPublisher < SshDirPublisher # :nodoc: all
+ def upload
+ run %{ssh #{@host} rm -rf #{@remote_dir}} rescue nil
+ run %{ssh #{@host} mkdir #{@remote_dir}}
+ super
+ end
+end
+
+# TODO: Remove in Rake 11, duplicated
+#--
+# Publish a list of files to an existing remote directory.
+class SshFilePublisher # :nodoc: all
+ # Create a publisher using the give host information.
+ def initialize(host, remote_dir, local_dir, *files)
+ @host = host
+ @remote_dir = remote_dir
+ @local_dir = local_dir
+ @files = files
+ end
+
+ # Upload the local directory to the remote directory.
+ def upload
+ @files.each do |fn|
+ run %{scp -q #{@local_dir}/#{fn} #{@host}:#{@remote_dir}}
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/contrib/rubyforgepublisher.rb b/ruby_2_2/lib/rake/contrib/rubyforgepublisher.rb
new file mode 100644
index 0000000000..00889ad7b9
--- /dev/null
+++ b/ruby_2_2/lib/rake/contrib/rubyforgepublisher.rb
@@ -0,0 +1,18 @@
+# TODO: Remove in Rake 11
+
+require 'rake/contrib/sshpublisher'
+
+module Rake
+
+ class RubyForgePublisher < SshDirPublisher # :nodoc: all
+ attr_reader :project, :proj_id, :user
+
+ def initialize(projname, user)
+ super(
+ "#{user}@rubyforge.org",
+ "/var/www/gforge-projects/#{projname}",
+ "html")
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/contrib/sshpublisher.rb b/ruby_2_2/lib/rake/contrib/sshpublisher.rb
new file mode 100644
index 0000000000..64f577017c
--- /dev/null
+++ b/ruby_2_2/lib/rake/contrib/sshpublisher.rb
@@ -0,0 +1,61 @@
+require 'rake/dsl_definition'
+require 'rake/contrib/compositepublisher'
+
+module Rake
+
+ # Publish an entire directory to an existing remote directory using
+ # SSH.
+ class SshDirPublisher
+ include Rake::DSL
+
+ # Creates an SSH publisher which will scp all files in +local_dir+ to
+ # +remote_dir+ on +host+
+
+ def initialize(host, remote_dir, local_dir)
+ @host = host
+ @remote_dir = remote_dir
+ @local_dir = local_dir
+ end
+
+ # Uploads the files
+
+ def upload
+ sh "scp", "-rq", "#{@local_dir}/*", "#{@host}:#{@remote_dir}"
+ end
+ end
+
+ # Publish an entire directory to a fresh remote directory using SSH.
+ class SshFreshDirPublisher < SshDirPublisher
+
+ # Uploads the files after removing the existing remote directory.
+
+ def upload
+ sh "ssh", @host, "rm", "-rf", @remote_dir rescue nil
+ sh "ssh", @host, "mkdir", @remote_dir
+ super
+ end
+ end
+
+ # Publish a list of files to an existing remote directory.
+ class SshFilePublisher
+ include Rake::DSL
+
+ # Creates an SSH publisher which will scp all +files+ in +local_dir+ to
+ # +remote_dir+ on +host+.
+
+ def initialize(host, remote_dir, local_dir, *files)
+ @host = host
+ @remote_dir = remote_dir
+ @local_dir = local_dir
+ @files = files
+ end
+
+ # Uploads the files
+
+ def upload
+ @files.each do |fn|
+ sh "scp", "-q", "#{@local_dir}/#{fn}", "#{@host}:#{@remote_dir}"
+ end
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/contrib/sys.rb b/ruby_2_2/lib/rake/contrib/sys.rb
new file mode 100644
index 0000000000..8d4c735434
--- /dev/null
+++ b/ruby_2_2/lib/rake/contrib/sys.rb
@@ -0,0 +1,4 @@
+# TODO: Remove in Rake 11
+
+fail "ERROR: 'rake/contrib/sys' is obsolete and no longer supported. " +
+ "Use 'FileUtils' instead."
diff --git a/ruby_2_2/lib/rake/cpu_counter.rb b/ruby_2_2/lib/rake/cpu_counter.rb
new file mode 100644
index 0000000000..f29778ed5d
--- /dev/null
+++ b/ruby_2_2/lib/rake/cpu_counter.rb
@@ -0,0 +1,125 @@
+module Rake
+
+ # Based on a script at:
+ # http://stackoverflow.com/questions/891537/ruby-detect-number-of-cpus-installed
+ class CpuCounter # :nodoc: all
+ def self.count
+ new.count_with_default
+ end
+
+ def count_with_default(default=4)
+ count || default
+ rescue StandardError
+ default
+ end
+
+ begin
+ require 'etc'
+ rescue LoadError
+ else
+ if Etc.respond_to?(:nprocessors)
+ def count
+ return Etc.nprocessors
+ end
+ end
+ end
+ end
+end
+
+unless Rake::CpuCounter.method_defined?(:count)
+ Rake::CpuCounter.class_eval <<-'end;', __FILE__, __LINE__+1
+ require 'rbconfig'
+
+ # TODO: replace with IO.popen using array-style arguments in Rake 11
+ require 'open3'
+
+ def count
+ if defined?(Java::Java)
+ count_via_java_runtime
+ else
+ case RbConfig::CONFIG['host_os']
+ when /darwin9/
+ count_via_hwprefs_cpu_count
+ when /darwin/
+ count_via_hwprefs_thread_count || count_via_sysctl
+ when /linux/
+ count_via_cpuinfo
+ when /bsd/
+ count_via_sysctl
+ when /mswin|mingw/
+ count_via_win32
+ else
+ # Try everything
+ count_via_win32 ||
+ count_via_sysctl ||
+ count_via_hwprefs_thread_count ||
+ count_via_hwprefs_cpu_count ||
+ count_via_cpuinfo
+ end
+ end
+ end
+
+ def count_via_java_runtime
+ Java::Java.lang.Runtime.getRuntime.availableProcessors
+ rescue StandardError
+ nil
+ end
+
+ def count_via_win32
+ require 'win32ole'
+ wmi = WIN32OLE.connect("winmgmts://")
+ cpu = wmi.ExecQuery("select NumberOfCores from Win32_Processor") # TODO count hyper-threaded in this
+ cpu.to_enum.first.NumberOfCores
+ rescue StandardError, LoadError
+ nil
+ end
+
+ def count_via_cpuinfo
+ open('/proc/cpuinfo') { |f| f.readlines }.grep(/processor/).size
+ rescue StandardError
+ nil
+ end
+
+ def count_via_hwprefs_thread_count
+ run 'hwprefs', 'thread_count'
+ end
+
+ def count_via_hwprefs_cpu_count
+ run 'hwprefs', 'cpu_count'
+ end
+
+ def count_via_sysctl
+ run 'sysctl', '-n', 'hw.ncpu'
+ end
+
+ def run(command, *args)
+ cmd = resolve_command(command)
+ if cmd
+ Open3.popen3 cmd, *args do |inn, out, err,|
+ inn.close
+ err.read
+ out.read.to_i
+ end
+ else
+ nil
+ end
+ end
+
+ def resolve_command(command)
+ look_for_command("/usr/sbin", command) ||
+ look_for_command("/sbin", command) ||
+ in_path_command(command)
+ end
+
+ def look_for_command(dir, command)
+ path = File.join(dir, command)
+ File.exist?(path) ? path : nil
+ end
+
+ def in_path_command(command)
+ Open3.popen3 'which', command do |_, out,|
+ out.eof? ? nil : command
+ end
+ end
+ end;
+end
diff --git a/ruby_2_2/lib/rake/default_loader.rb b/ruby_2_2/lib/rake/default_loader.rb
new file mode 100644
index 0000000000..6154408f44
--- /dev/null
+++ b/ruby_2_2/lib/rake/default_loader.rb
@@ -0,0 +1,14 @@
+module Rake
+
+ # Default Rakefile loader used by +import+.
+ class DefaultLoader
+
+ ##
+ # Loads a rakefile into the current application from +fn+
+
+ def load(fn)
+ Rake.load_rakefile(File.expand_path(fn))
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/dsl_definition.rb b/ruby_2_2/lib/rake/dsl_definition.rb
new file mode 100644
index 0000000000..26f4ca828c
--- /dev/null
+++ b/ruby_2_2/lib/rake/dsl_definition.rb
@@ -0,0 +1,201 @@
+# Rake DSL functions.
+require 'rake/file_utils_ext'
+
+module Rake
+
+ ##
+ # DSL is a module that provides #task, #desc, #namespace, etc. Use this
+ # when you'd like to use rake outside the top level scope.
+ #
+ # For a Rakefile you run from the comamnd line this module is automatically
+ # included.
+
+ module DSL
+
+ #--
+ # Include the FileUtils file manipulation functions in the top
+ # level module, but mark them private so that they don't
+ # unintentionally define methods on other objects.
+ #++
+
+ include FileUtilsExt
+ private(*FileUtils.instance_methods(false))
+ private(*FileUtilsExt.instance_methods(false))
+
+ private
+
+ # :call-seq:
+ # task task_name
+ # task task_name: dependencies
+ # task task_name, arguments => dependencies
+ # task task_name, argument[, argument ...], :needs: dependencies
+ #
+ # Declare a basic task. The +task_name+ is always the first argument. If
+ # the task name contains a ":" it is defined in that namespace.
+ #
+ # The +dependencies+ may be a single task name or an Array of task names.
+ # The +argument+ (a single name) or +arguments+ (an Array of names) define
+ # the arguments provided to the task.
+ #
+ # The task, argument and dependency names may be either symbols or
+ # strings.
+ #
+ # A task with a single dependency:
+ #
+ # task clobber: %w[clean] do
+ # rm_rf "html"
+ # end
+ #
+ # A task with an argument and a dependency:
+ #
+ # task :package, [:version] => :test do |t, args|
+ # # ...
+ # end
+ #
+ # To invoke this task from the command line:
+ #
+ # $ rake package[1.2.3]
+ #
+ # Alternate definition:
+ #
+ # task :package, :version, needs: :test do |t, args|
+ # # ...
+ # end
+ #
+ def task(*args, &block) # :doc:
+ Rake::Task.define_task(*args, &block)
+ end
+
+ # Declare a file task.
+ #
+ # Example:
+ # file "config.cfg" => ["config.template"] do
+ # open("config.cfg", "w") do |outfile|
+ # open("config.template") do |infile|
+ # while line = infile.gets
+ # outfile.puts line
+ # end
+ # end
+ # end
+ # end
+ #
+ def file(*args, &block) # :doc:
+ Rake::FileTask.define_task(*args, &block)
+ end
+
+ # Declare a file creation task.
+ # (Mainly used for the directory command).
+ def file_create(*args, &block)
+ Rake::FileCreationTask.define_task(*args, &block)
+ end
+
+ # Declare a set of files tasks to create the given directories on
+ # demand.
+ #
+ # Example:
+ # directory "testdata/doc"
+ #
+ def directory(*args, &block) # :doc:
+ result = file_create(*args, &block)
+ dir, _ = *Rake.application.resolve_args(args)
+ dir = Rake.from_pathname(dir)
+ Rake.each_dir_parent(dir) do |d|
+ file_create d do |t|
+ mkdir_p t.name unless File.exist?(t.name)
+ end
+ end
+ result
+ end
+
+ # Declare a task that performs its prerequisites in
+ # parallel. Multitasks does *not* guarantee that its prerequisites
+ # will execute in any given order (which is obvious when you think
+ # about it)
+ #
+ # Example:
+ # multitask deploy: %w[deploy_gem deploy_rdoc]
+ #
+ def multitask(*args, &block) # :doc:
+ Rake::MultiTask.define_task(*args, &block)
+ end
+
+ # Create a new rake namespace and use it for evaluating the given
+ # block. Returns a NameSpace object that can be used to lookup
+ # tasks defined in the namespace.
+ #
+ # Example:
+ #
+ # ns = namespace "nested" do
+ # # the "nested:run" task
+ # task :run
+ # end
+ # task_run = ns[:run] # find :run in the given namespace.
+ #
+ # Tasks can also be defined in a namespace by using a ":" in the task
+ # name:
+ #
+ # task "nested:test" do
+ # # ...
+ # end
+ #
+ def namespace(name=nil, &block) # :doc:
+ name = name.to_s if name.kind_of?(Symbol)
+ name = name.to_str if name.respond_to?(:to_str)
+ unless name.kind_of?(String) || name.nil?
+ raise ArgumentError, "Expected a String or Symbol for a namespace name"
+ end
+ Rake.application.in_namespace(name, &block)
+ end
+
+ # Declare a rule for auto-tasks.
+ #
+ # Example:
+ # rule '.o' => '.c' do |t|
+ # sh 'cc', '-o', t.name, t.source
+ # end
+ #
+ def rule(*args, &block) # :doc:
+ Rake::Task.create_rule(*args, &block)
+ end
+
+ # Describes the next rake task. Duplicate descriptions are discarded.
+ # Descriptions are shown with <code>rake -T</code> (up to the first
+ # sentence) and <code>rake -D</code> (the entire description).
+ #
+ # Example:
+ # desc "Run the Unit Tests"
+ # task test: [:build]
+ # # ... run tests
+ # end
+ #
+ def desc(description) # :doc:
+ Rake.application.last_description = description
+ end
+
+ # Import the partial Rakefiles +fn+. Imported files are loaded
+ # _after_ the current file is completely loaded. This allows the
+ # import statement to appear anywhere in the importing file, and yet
+ # allowing the imported files to depend on objects defined in the
+ # importing file.
+ #
+ # A common use of the import statement is to include files
+ # containing dependency declarations.
+ #
+ # See also the --rakelibdir command line option.
+ #
+ # Example:
+ # import ".depend", "my_rules"
+ #
+ def import(*fns) # :doc:
+ fns.each do |fn|
+ Rake.application.add_import(fn)
+ end
+ end
+ end
+ extend FileUtilsExt
+end
+
+# Extend the main object with the DSL commands. This allows top-level
+# calls to task, etc. to work from a Rakefile without polluting the
+# object inheritance tree.
+self.extend Rake::DSL
diff --git a/ruby_2_2/lib/rake/early_time.rb b/ruby_2_2/lib/rake/early_time.rb
new file mode 100644
index 0000000000..abcb1872b5
--- /dev/null
+++ b/ruby_2_2/lib/rake/early_time.rb
@@ -0,0 +1,21 @@
+module Rake
+
+ # EarlyTime is a fake timestamp that occurs _before_ any other time value.
+ class EarlyTime
+ include Comparable
+ include Singleton
+
+ ##
+ # The EarlyTime always comes before +other+!
+
+ def <=>(other)
+ -1
+ end
+
+ def to_s # :nodoc:
+ "<EARLY TIME>"
+ end
+ end
+
+ EARLY = EarlyTime.instance
+end
diff --git a/ruby_2_2/lib/rake/ext/core.rb b/ruby_2_2/lib/rake/ext/core.rb
new file mode 100644
index 0000000000..7575df15a9
--- /dev/null
+++ b/ruby_2_2/lib/rake/ext/core.rb
@@ -0,0 +1,25 @@
+class Module
+ # Check for an existing method in the current class before extending. If
+ # the method already exists, then a warning is printed and the extension is
+ # not added. Otherwise the block is yielded and any definitions in the
+ # block will take effect.
+ #
+ # Usage:
+ #
+ # class String
+ # rake_extension("xyz") do
+ # def xyz
+ # ...
+ # end
+ # end
+ # end
+ #
+ def rake_extension(method) # :nodoc:
+ if method_defined?(method)
+ $stderr.puts "WARNING: Possible conflict with Rake extension: " +
+ "#{self}##{method} already exists"
+ else
+ yield
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/ext/module.rb b/ruby_2_2/lib/rake/ext/module.rb
new file mode 100644
index 0000000000..3ee155ff6c
--- /dev/null
+++ b/ruby_2_2/lib/rake/ext/module.rb
@@ -0,0 +1,2 @@
+
+# TODO: remove in Rake 11
diff --git a/ruby_2_2/lib/rake/ext/pathname.rb b/ruby_2_2/lib/rake/ext/pathname.rb
new file mode 100644
index 0000000000..49e2cd47ac
--- /dev/null
+++ b/ruby_2_2/lib/rake/ext/pathname.rb
@@ -0,0 +1,25 @@
+require 'rake/ext/core'
+require 'pathname'
+
+class Pathname
+
+ rake_extension("ext") do
+ # Return a new Pathname with <tt>String#ext</tt> applied to it.
+ #
+ # This Pathname extension comes from Rake
+ def ext(newext='')
+ Pathname.new(Rake.from_pathname(self).ext(newext))
+ end
+ end
+
+ rake_extension("pathmap") do
+ # Apply the pathmap spec to the Pathname, returning a
+ # new Pathname with the modified paths. (See String#pathmap for
+ # details.)
+ #
+ # This Pathname extension comes from Rake
+ def pathmap(spec=nil, &block)
+ Pathname.new(Rake.from_pathname(self).pathmap(spec, &block))
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/ext/string.rb b/ruby_2_2/lib/rake/ext/string.rb
new file mode 100644
index 0000000000..b47b055a74
--- /dev/null
+++ b/ruby_2_2/lib/rake/ext/string.rb
@@ -0,0 +1,173 @@
+require 'rake/ext/core'
+
+class String
+
+ rake_extension("ext") do
+ # Replace the file extension with +newext+. If there is no extension on
+ # the string, append the new extension to the end. If the new extension
+ # is not given, or is the empty string, remove any existing extension.
+ #
+ # +ext+ is a user added method for the String class.
+ #
+ # This String extension comes from Rake
+ def ext(newext='')
+ return self.dup if ['.', '..'].include? self
+ newext = (newext =~ /^\./) ? newext : ("." + newext) if newext != ''
+ self.chomp(File.extname(self)) << newext
+ end
+ end
+
+ rake_extension("pathmap") do
+ # Explode a path into individual components. Used by +pathmap+.
+ #
+ # This String extension comes from Rake
+ def pathmap_explode
+ head, tail = File.split(self)
+ return [self] if head == self
+ return [tail] if head == '.' || tail == '/'
+ return [head, tail] if head == '/'
+ return head.pathmap_explode + [tail]
+ end
+ protected :pathmap_explode
+
+ # Extract a partial path from the path. Include +n+ directories from the
+ # front end (left hand side) if +n+ is positive. Include |+n+|
+ # directories from the back end (right hand side) if +n+ is negative.
+ #
+ # This String extension comes from Rake
+ def pathmap_partial(n)
+ dirs = File.dirname(self).pathmap_explode
+ partial_dirs =
+ if n > 0
+ dirs[0...n]
+ elsif n < 0
+ dirs.reverse[0...-n].reverse
+ else
+ "."
+ end
+ File.join(partial_dirs)
+ end
+ protected :pathmap_partial
+
+ # Perform the pathmap replacement operations on the given path. The
+ # patterns take the form 'pat1,rep1;pat2,rep2...'.
+ #
+ # This String extension comes from Rake
+ def pathmap_replace(patterns, &block)
+ result = self
+ patterns.split(';').each do |pair|
+ pattern, replacement = pair.split(',')
+ pattern = Regexp.new(pattern)
+ if replacement == '*' && block_given?
+ result = result.sub(pattern, &block)
+ elsif replacement
+ result = result.sub(pattern, replacement)
+ else
+ result = result.sub(pattern, '')
+ end
+ end
+ result
+ end
+ protected :pathmap_replace
+
+ # Map the path according to the given specification. The specification
+ # controls the details of the mapping. The following special patterns are
+ # recognized:
+ #
+ # <tt>%p</tt> :: The complete path.
+ # <tt>%f</tt> :: The base file name of the path, with its file extension,
+ # but without any directories.
+ # <tt>%n</tt> :: The file name of the path without its file extension.
+ # <tt>%d</tt> :: The directory list of the path.
+ # <tt>%x</tt> :: The file extension of the path. An empty string if there
+ # is no extension.
+ # <tt>%X</tt> :: Everything *but* the file extension.
+ # <tt>%s</tt> :: The alternate file separator if defined, otherwise use #
+ # the standard file separator.
+ # <tt>%%</tt> :: A percent sign.
+ #
+ # The <tt>%d</tt> specifier can also have a numeric prefix (e.g. '%2d').
+ # If the number is positive, only return (up to) +n+ directories in the
+ # path, starting from the left hand side. If +n+ is negative, return (up
+ # to) +n+ directories from the right hand side of the path.
+ #
+ # Examples:
+ #
+ # 'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b'
+ # 'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d'
+ #
+ # Also the <tt>%d</tt>, <tt>%p</tt>, <tt>%f</tt>, <tt>%n</tt>,
+ # <tt>%x</tt>, and <tt>%X</tt> operators can take a pattern/replacement
+ # argument to perform simple string substitutions on a particular part of
+ # the path. The pattern and replacement are separated by a comma and are
+ # enclosed by curly braces. The replacement spec comes after the %
+ # character but before the operator letter. (e.g. "%{old,new}d").
+ # Multiple replacement specs should be separated by semi-colons (e.g.
+ # "%{old,new;src,bin}d").
+ #
+ # Regular expressions may be used for the pattern, and back refs may be
+ # used in the replacement text. Curly braces, commas and semi-colons are
+ # excluded from both the pattern and replacement text (let's keep parsing
+ # reasonable).
+ #
+ # For example:
+ #
+ # "src/org/onestepback/proj/A.java".pathmap("%{^src,class}X.class")
+ #
+ # returns:
+ #
+ # "class/org/onestepback/proj/A.class"
+ #
+ # If the replacement text is '*', then a block may be provided to perform
+ # some arbitrary calculation for the replacement.
+ #
+ # For example:
+ #
+ # "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext|
+ # ext.downcase
+ # }
+ #
+ # Returns:
+ #
+ # "/path/to/file.txt"
+ #
+ # This String extension comes from Rake
+ def pathmap(spec=nil, &block)
+ return self if spec.nil?
+ result = ''
+ spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
+ case frag
+ when '%f'
+ result << File.basename(self)
+ when '%n'
+ result << File.basename(self).ext
+ when '%d'
+ result << File.dirname(self)
+ when '%x'
+ result << File.extname(self)
+ when '%X'
+ result << self.ext
+ when '%p'
+ result << self
+ when '%s'
+ result << (File::ALT_SEPARATOR || File::SEPARATOR)
+ when '%-'
+ # do nothing
+ when '%%'
+ result << "%"
+ when /%(-?\d+)d/
+ result << pathmap_partial($1.to_i)
+ when /^%\{([^}]*)\}(\d*[dpfnxX])/
+ patterns, operator = $1, $2
+ result << pathmap('%' + operator).pathmap_replace(patterns, &block)
+ when /^%/
+ fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'"
+ else
+ result << frag
+ end
+ end
+ result
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/ext/time.rb b/ruby_2_2/lib/rake/ext/time.rb
new file mode 100644
index 0000000000..d3b8cf9dc1
--- /dev/null
+++ b/ruby_2_2/lib/rake/ext/time.rb
@@ -0,0 +1,16 @@
+#--
+# Extensions to time to allow comparisons with early and late time classes.
+
+require 'rake/early_time'
+require 'rake/late_time'
+
+class Time # :nodoc: all
+ alias rake_original_time_compare :<=>
+ def <=>(other)
+ if Rake::EarlyTime === other || Rake::LateTime === other
+ - other.<=>(self)
+ else
+ rake_original_time_compare(other)
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/file_creation_task.rb b/ruby_2_2/lib/rake/file_creation_task.rb
new file mode 100644
index 0000000000..c87e2192bb
--- /dev/null
+++ b/ruby_2_2/lib/rake/file_creation_task.rb
@@ -0,0 +1,24 @@
+require 'rake/file_task'
+require 'rake/early_time'
+
+module Rake
+
+ # A FileCreationTask is a file task that when used as a dependency will be
+ # needed if and only if the file has not been created. Once created, it is
+ # not re-triggered if any of its dependencies are newer, nor does trigger
+ # any rebuilds of tasks that depend on it whenever it is updated.
+ #
+ class FileCreationTask < FileTask
+ # Is this file task needed? Yes if it doesn't exist.
+ def needed?
+ ! File.exist?(name)
+ end
+
+ # Time stamp for file creation task. This time stamp is earlier
+ # than any other time stamp.
+ def timestamp
+ Rake::EARLY
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/file_list.rb b/ruby_2_2/lib/rake/file_list.rb
new file mode 100644
index 0000000000..006ec7703e
--- /dev/null
+++ b/ruby_2_2/lib/rake/file_list.rb
@@ -0,0 +1,428 @@
+require 'rake/cloneable'
+require 'rake/file_utils_ext'
+require 'rake/pathmap'
+
+
+module Rake
+
+ ##
+ # A FileList is essentially an array with a few helper methods defined to
+ # make file manipulation a bit easier.
+ #
+ # FileLists are lazy. When given a list of glob patterns for possible files
+ # to be included in the file list, instead of searching the file structures
+ # to find the files, a FileList holds the pattern for latter use.
+ #
+ # This allows us to define a number of FileList to match any number of
+ # files, but only search out the actual files when then FileList itself is
+ # actually used. The key is that the first time an element of the
+ # FileList/Array is requested, the pending patterns are resolved into a real
+ # list of file names.
+ #
+ class FileList
+
+ include Cloneable
+
+ # == Method Delegation
+ #
+ # The lazy evaluation magic of FileLists happens by implementing all the
+ # array specific methods to call +resolve+ before delegating the heavy
+ # lifting to an embedded array object (@items).
+ #
+ # In addition, there are two kinds of delegation calls. The regular kind
+ # delegates to the @items array and returns the result directly. Well,
+ # almost directly. It checks if the returned value is the @items object
+ # itself, and if so will return the FileList object instead.
+ #
+ # The second kind of delegation call is used in methods that normally
+ # return a new Array object. We want to capture the return value of these
+ # methods and wrap them in a new FileList object. We enumerate these
+ # methods in the +SPECIAL_RETURN+ list below.
+
+ # List of array methods (that are not in +Object+) that need to be
+ # delegated.
+ ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).
+ map { |n| n.to_s }
+
+ # List of additional methods that must be delegated.
+ MUST_DEFINE = %w[inspect <=>]
+
+ # List of methods that should not be delegated here (we define special
+ # versions of them explicitly below).
+ MUST_NOT_DEFINE = %w[to_a to_ary partition * <<]
+
+ # List of delegated methods that return new array values which need
+ # wrapping.
+ SPECIAL_RETURN = %w[
+ map collect sort sort_by select find_all reject grep
+ compact flatten uniq values_at
+ + - & |
+ ]
+
+ DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).
+ map { |s| s.to_s }.sort.uniq
+
+ # Now do the delegation.
+ DELEGATING_METHODS.each do |sym|
+ if SPECIAL_RETURN.include?(sym)
+ ln = __LINE__ + 1
+ class_eval %{
+ def #{sym}(*args, &block)
+ resolve
+ result = @items.send(:#{sym}, *args, &block)
+ FileList.new.import(result)
+ end
+ }, __FILE__, ln
+ else
+ ln = __LINE__ + 1
+ class_eval %{
+ def #{sym}(*args, &block)
+ resolve
+ result = @items.send(:#{sym}, *args, &block)
+ result.object_id == @items.object_id ? self : result
+ end
+ }, __FILE__, ln
+ end
+ end
+
+ # Create a file list from the globbable patterns given. If you wish to
+ # perform multiple includes or excludes at object build time, use the
+ # "yield self" pattern.
+ #
+ # Example:
+ # file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
+ #
+ # pkg_files = FileList.new('lib/**/*') do |fl|
+ # fl.exclude(/\bCVS\b/)
+ # end
+ #
+ def initialize(*patterns)
+ @pending_add = []
+ @pending = false
+ @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
+ @exclude_procs = DEFAULT_IGNORE_PROCS.dup
+ @items = []
+ patterns.each { |pattern| include(pattern) }
+ yield self if block_given?
+ end
+
+ # Add file names defined by glob patterns to the file list. If an array
+ # is given, add each element of the array.
+ #
+ # Example:
+ # file_list.include("*.java", "*.cfg")
+ # file_list.include %w( math.c lib.h *.o )
+ #
+ def include(*filenames)
+ # TODO: check for pending
+ filenames.each do |fn|
+ if fn.respond_to? :to_ary
+ include(*fn.to_ary)
+ else
+ @pending_add << Rake.from_pathname(fn)
+ end
+ end
+ @pending = true
+ self
+ end
+ alias :add :include
+
+ # Register a list of file name patterns that should be excluded from the
+ # list. Patterns may be regular expressions, glob patterns or regular
+ # strings. In addition, a block given to exclude will remove entries that
+ # return true when given to the block.
+ #
+ # Note that glob patterns are expanded against the file system. If a file
+ # is explicitly added to a file list, but does not exist in the file
+ # system, then an glob pattern in the exclude list will not exclude the
+ # file.
+ #
+ # Examples:
+ # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
+ # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
+ #
+ # If "a.c" is a file, then ...
+ # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
+ #
+ # If "a.c" is not a file, then ...
+ # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
+ #
+ def exclude(*patterns, &block)
+ patterns.each do |pat|
+ @exclude_patterns << Rake.from_pathname(pat)
+ end
+ @exclude_procs << block if block_given?
+ resolve_exclude unless @pending
+ self
+ end
+
+ # Clear all the exclude patterns so that we exclude nothing.
+ def clear_exclude
+ @exclude_patterns = []
+ @exclude_procs = []
+ self
+ end
+
+ # A FileList is equal through array equality.
+ def ==(array)
+ to_ary == array
+ end
+
+ # Return the internal array object.
+ def to_a
+ resolve
+ @items
+ end
+
+ # Return the internal array object.
+ def to_ary
+ to_a
+ end
+
+ # Lie about our class.
+ def is_a?(klass)
+ klass == Array || super(klass)
+ end
+ alias kind_of? is_a?
+
+ # Redefine * to return either a string or a new file list.
+ def *(other)
+ result = @items * other
+ case result
+ when Array
+ FileList.new.import(result)
+ else
+ result
+ end
+ end
+
+ def <<(obj)
+ resolve
+ @items << Rake.from_pathname(obj)
+ self
+ end
+
+ # Resolve all the pending adds now.
+ def resolve
+ if @pending
+ @pending = false
+ @pending_add.each do |fn| resolve_add(fn) end
+ @pending_add = []
+ resolve_exclude
+ end
+ self
+ end
+
+ def resolve_add(fn) # :nodoc:
+ case fn
+ when %r{[*?\[\{]}
+ add_matching(fn)
+ else
+ self << fn
+ end
+ end
+ private :resolve_add
+
+ def resolve_exclude # :nodoc:
+ reject! { |fn| excluded_from_list?(fn) }
+ self
+ end
+ private :resolve_exclude
+
+ # Return a new FileList with the results of running +sub+ against each
+ # element of the original list.
+ #
+ # Example:
+ # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o']
+ #
+ def sub(pat, rep)
+ inject(FileList.new) { |res, fn| res << fn.sub(pat, rep) }
+ end
+
+ # Return a new FileList with the results of running +gsub+ against each
+ # element of the original list.
+ #
+ # Example:
+ # FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
+ # => ['lib\\test\\file', 'x\\y']
+ #
+ def gsub(pat, rep)
+ inject(FileList.new) { |res, fn| res << fn.gsub(pat, rep) }
+ end
+
+ # Same as +sub+ except that the original file list is modified.
+ def sub!(pat, rep)
+ each_with_index { |fn, i| self[i] = fn.sub(pat, rep) }
+ self
+ end
+
+ # Same as +gsub+ except that the original file list is modified.
+ def gsub!(pat, rep)
+ each_with_index { |fn, i| self[i] = fn.gsub(pat, rep) }
+ self
+ end
+
+ # Apply the pathmap spec to each of the included file names, returning a
+ # new file list with the modified paths. (See String#pathmap for
+ # details.)
+ def pathmap(spec=nil)
+ collect { |fn| fn.pathmap(spec) }
+ end
+
+ # Return a new FileList with <tt>String#ext</tt> method applied to
+ # each member of the array.
+ #
+ # This method is a shortcut for:
+ #
+ # array.collect { |item| item.ext(newext) }
+ #
+ # +ext+ is a user added method for the Array class.
+ def ext(newext='')
+ collect { |fn| fn.ext(newext) }
+ end
+
+ # Grep each of the files in the filelist using the given pattern. If a
+ # block is given, call the block on each matching line, passing the file
+ # name, line number, and the matching line of text. If no block is given,
+ # a standard emacs style file:linenumber:line message will be printed to
+ # standard out. Returns the number of matched items.
+ def egrep(pattern, *options)
+ matched = 0
+ each do |fn|
+ begin
+ open(fn, "r", *options) do |inf|
+ count = 0
+ inf.each do |line|
+ count += 1
+ if pattern.match(line)
+ matched += 1
+ if block_given?
+ yield fn, count, line
+ else
+ puts "#{fn}:#{count}:#{line}"
+ end
+ end
+ end
+ end
+ rescue StandardError => ex
+ $stderr.puts "Error while processing '#{fn}': #{ex}"
+ end
+ end
+ matched
+ end
+
+ # Return a new file list that only contains file names from the current
+ # file list that exist on the file system.
+ def existing
+ select { |fn| File.exist?(fn) }
+ end
+
+ # Modify the current file list so that it contains only file name that
+ # exist on the file system.
+ def existing!
+ resolve
+ @items = @items.select { |fn| File.exist?(fn) }
+ self
+ end
+
+ # FileList version of partition. Needed because the nested arrays should
+ # be FileLists in this version.
+ def partition(&block) # :nodoc:
+ resolve
+ result = @items.partition(&block)
+ [
+ FileList.new.import(result[0]),
+ FileList.new.import(result[1]),
+ ]
+ end
+
+ # Convert a FileList to a string by joining all elements with a space.
+ def to_s
+ resolve
+ self.join(' ')
+ end
+
+ # Add matching glob patterns.
+ def add_matching(pattern)
+ FileList.glob(pattern).each do |fn|
+ self << fn unless excluded_from_list?(fn)
+ end
+ end
+ private :add_matching
+
+ # Should the given file name be excluded from the list?
+ #
+ # NOTE: This method was formerly named "exclude?", but Rails
+ # introduced an exclude? method as an array method and setup a
+ # conflict with file list. We renamed the method to avoid
+ # confusion. If you were using "FileList#exclude?" in your user
+ # code, you will need to update.
+ def excluded_from_list?(fn)
+ return true if @exclude_patterns.any? do |pat|
+ case pat
+ when Regexp
+ fn =~ pat
+ when /[*?]/
+ File.fnmatch?(pat, fn, File::FNM_PATHNAME)
+ else
+ fn == pat
+ end
+ end
+ @exclude_procs.any? { |p| p.call(fn) }
+ end
+
+ DEFAULT_IGNORE_PATTERNS = [
+ /(^|[\/\\])CVS([\/\\]|$)/,
+ /(^|[\/\\])\.svn([\/\\]|$)/,
+ /\.bak$/,
+ /~$/
+ ]
+ DEFAULT_IGNORE_PROCS = [
+ proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
+ ]
+
+ def import(array) # :nodoc:
+ @items = array
+ self
+ end
+
+ class << self
+ # Create a new file list including the files listed. Similar to:
+ #
+ # FileList.new(*args)
+ def [](*args)
+ new(*args)
+ end
+
+ # Get a sorted list of files matching the pattern. This method
+ # should be preferred to Dir[pattern] and Dir.glob(pattern) because
+ # the files returned are guaranteed to be sorted.
+ def glob(pattern, *args)
+ Dir.glob(pattern, *args).sort
+ end
+ end
+ end
+end
+
+module Rake
+ class << self
+
+ # Yield each file or directory component.
+ def each_dir_parent(dir) # :nodoc:
+ old_length = nil
+ while dir != '.' && dir.length != old_length
+ yield(dir)
+ old_length = dir.length
+ dir = File.dirname(dir)
+ end
+ end
+
+ # Convert Pathname and Pathname-like objects to strings;
+ # leave everything else alone
+ def from_pathname(path) # :nodoc:
+ path = path.to_path if path.respond_to?(:to_path)
+ path = path.to_str if path.respond_to?(:to_str)
+ path
+ end
+ end
+end # module Rake
diff --git a/ruby_2_2/lib/rake/file_task.rb b/ruby_2_2/lib/rake/file_task.rb
new file mode 100644
index 0000000000..4c9b04074f
--- /dev/null
+++ b/ruby_2_2/lib/rake/file_task.rb
@@ -0,0 +1,46 @@
+require 'rake/task.rb'
+require 'rake/early_time'
+
+module Rake
+
+ # A FileTask is a task that includes time based dependencies. If any of a
+ # FileTask's prerequisites have a timestamp that is later than the file
+ # represented by this task, then the file must be rebuilt (using the
+ # supplied actions).
+ #
+ class FileTask < Task
+
+ # Is this file task needed? Yes if it doesn't exist, or if its time stamp
+ # is out of date.
+ def needed?
+ ! File.exist?(name) || out_of_date?(timestamp) || @application.options.build_all
+ end
+
+ # Time stamp for file task.
+ def timestamp
+ if File.exist?(name)
+ File.mtime(name.to_s)
+ else
+ Rake::LATE
+ end
+ end
+
+ private
+
+ # Are there any prerequisites with a later time than the given time stamp?
+ def out_of_date?(stamp)
+ @prerequisites.any? { |n| application[n, @scope].timestamp > stamp }
+ end
+
+ # ----------------------------------------------------------------
+ # Task class methods.
+ #
+ class << self
+ # Apply the scope to the task name according to the rules for this kind
+ # of task. File based tasks ignore the scope when creating the name.
+ def scope_name(scope, task_name)
+ Rake.from_pathname(task_name)
+ end
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/file_utils.rb b/ruby_2_2/lib/rake/file_utils.rb
new file mode 100644
index 0000000000..27f4e2e1d1
--- /dev/null
+++ b/ruby_2_2/lib/rake/file_utils.rb
@@ -0,0 +1,128 @@
+require 'rbconfig'
+require 'fileutils'
+
+#--
+# This a FileUtils extension that defines several additional commands to be
+# added to the FileUtils utility functions.
+module FileUtils
+ # Path to the currently running Ruby program
+ RUBY = ENV['RUBY'] || File.join(
+ RbConfig::CONFIG['bindir'],
+ RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT']).
+ sub(/.*\s.*/m, '"\&"')
+
+ OPT_TABLE['sh'] = %w(noop verbose)
+ OPT_TABLE['ruby'] = %w(noop verbose)
+
+ # Run the system command +cmd+. If multiple arguments are given the command
+ # is run directly (without the shell, same semantics as Kernel::exec and
+ # Kernel::system).
+ #
+ # It is recommended you use the multiple argument form over interpolating
+ # user input for both usability and security reasons. With the multiple
+ # argument form you can easily process files with spaces or other shell
+ # reserved characters in them. With the multiple argument form your rake
+ # tasks are not vulnerable to users providing an argument like
+ # <code>; rm # -rf /</code>.
+ #
+ # If a block is given, upon command completion the block is called with an
+ # OK flag (true on a zero exit status) and a Process::Status object.
+ # Without a block a RuntimeError is raised when the command exits non-zero.
+ #
+ # Examples:
+ #
+ # sh 'ls -ltr'
+ #
+ # sh 'ls', 'file with spaces'
+ #
+ # # check exit status after command runs
+ # sh %{grep pattern file} do |ok, res|
+ # if ! ok
+ # puts "pattern not found (status = #{res.exitstatus})"
+ # end
+ # end
+ #
+ def sh(*cmd, &block)
+ options = (Hash === cmd.last) ? cmd.pop : {}
+ shell_runner = block_given? ? block : create_shell_runner(cmd)
+ set_verbose_option(options)
+ options[:noop] ||= Rake::FileUtilsExt.nowrite_flag
+ Rake.rake_check_options options, :noop, :verbose
+ Rake.rake_output_message cmd.join(" ") if options[:verbose]
+
+ unless options[:noop]
+ res = rake_system(*cmd)
+ status = $?
+ status = Rake::PseudoStatus.new(1) if !res && status.nil?
+ shell_runner.call(res, status)
+ end
+ end
+
+ def create_shell_runner(cmd) # :nodoc:
+ show_command = cmd.join(" ")
+ show_command = show_command[0, 42] + "..." unless $trace
+ lambda do |ok, status|
+ ok or
+ fail "Command failed with status (#{status.exitstatus}): " +
+ "[#{show_command}]"
+ end
+ end
+ private :create_shell_runner
+
+ def set_verbose_option(options) # :nodoc:
+ unless options.key? :verbose
+ options[:verbose] =
+ (Rake::FileUtilsExt.verbose_flag == Rake::FileUtilsExt::DEFAULT) ||
+ Rake::FileUtilsExt.verbose_flag
+ end
+ end
+ private :set_verbose_option
+
+ def rake_system(*cmd) # :nodoc:
+ Rake::AltSystem.system(*cmd)
+ end
+ private :rake_system
+
+ # Run a Ruby interpreter with the given arguments.
+ #
+ # Example:
+ # ruby %{-pe '$_.upcase!' <README}
+ #
+ def ruby(*args, &block)
+ options = (Hash === args.last) ? args.pop : {}
+ if args.length > 1
+ sh(*([RUBY] + args + [options]), &block)
+ else
+ sh("#{RUBY} #{args.first}", options, &block)
+ end
+ end
+
+ LN_SUPPORTED = [true]
+
+ # Attempt to do a normal file link, but fall back to a copy if the link
+ # fails.
+ def safe_ln(*args)
+ if ! LN_SUPPORTED[0]
+ cp(*args)
+ else
+ begin
+ ln(*args)
+ rescue StandardError, NotImplementedError
+ LN_SUPPORTED[0] = false
+ cp(*args)
+ end
+ end
+ end
+
+ # Split a file path into individual directory names.
+ #
+ # Example:
+ # split_all("a/b/c") => ['a', 'b', 'c']
+ #
+ def split_all(path)
+ head, tail = File.split(path)
+ return [tail] if head == '.' || tail == '/'
+ return [head, tail] if head == '/'
+ return split_all(head) + [tail]
+ end
+end
diff --git a/ruby_2_2/lib/rake/file_utils_ext.rb b/ruby_2_2/lib/rake/file_utils_ext.rb
new file mode 100644
index 0000000000..309159aec1
--- /dev/null
+++ b/ruby_2_2/lib/rake/file_utils_ext.rb
@@ -0,0 +1,144 @@
+require 'rake/file_utils'
+
+module Rake
+ #
+ # FileUtilsExt provides a custom version of the FileUtils methods
+ # that respond to the <tt>verbose</tt> and <tt>nowrite</tt>
+ # commands.
+ #
+ module FileUtilsExt
+ include FileUtils
+
+ class << self
+ attr_accessor :verbose_flag, :nowrite_flag
+ end
+
+ DEFAULT = Object.new
+
+ FileUtilsExt.verbose_flag = DEFAULT
+ FileUtilsExt.nowrite_flag = false
+
+ FileUtils.commands.each do |name|
+ opts = FileUtils.options_of name
+ default_options = []
+ if opts.include?("verbose")
+ default_options << ':verbose => FileUtilsExt.verbose_flag'
+ end
+ if opts.include?("noop")
+ default_options << ':noop => FileUtilsExt.nowrite_flag'
+ end
+
+ next if default_options.empty?
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{name}( *args, &block )
+ super(
+ *rake_merge_option(args,
+ #{default_options.join(', ')}
+ ), &block)
+ end
+ EOS
+ end
+
+ # Get/set the verbose flag controlling output from the FileUtils
+ # utilities. If verbose is true, then the utility method is
+ # echoed to standard output.
+ #
+ # Examples:
+ # verbose # return the current value of the
+ # # verbose flag
+ # verbose(v) # set the verbose flag to _v_.
+ # verbose(v) { code } # Execute code with the verbose flag set
+ # # temporarily to _v_. Return to the
+ # # original value when code is done.
+ def verbose(value=nil)
+ oldvalue = FileUtilsExt.verbose_flag
+ FileUtilsExt.verbose_flag = value unless value.nil?
+ if block_given?
+ begin
+ yield
+ ensure
+ FileUtilsExt.verbose_flag = oldvalue
+ end
+ end
+ FileUtilsExt.verbose_flag
+ end
+
+ # Get/set the nowrite flag controlling output from the FileUtils
+ # utilities. If verbose is true, then the utility method is
+ # echoed to standard output.
+ #
+ # Examples:
+ # nowrite # return the current value of the
+ # # nowrite flag
+ # nowrite(v) # set the nowrite flag to _v_.
+ # nowrite(v) { code } # Execute code with the nowrite flag set
+ # # temporarily to _v_. Return to the
+ # # original value when code is done.
+ def nowrite(value=nil)
+ oldvalue = FileUtilsExt.nowrite_flag
+ FileUtilsExt.nowrite_flag = value unless value.nil?
+ if block_given?
+ begin
+ yield
+ ensure
+ FileUtilsExt.nowrite_flag = oldvalue
+ end
+ end
+ oldvalue
+ end
+
+ # Use this function to prevent potentially destructive ruby code
+ # from running when the :nowrite flag is set.
+ #
+ # Example:
+ #
+ # when_writing("Building Project") do
+ # project.build
+ # end
+ #
+ # The following code will build the project under normal
+ # conditions. If the nowrite(true) flag is set, then the example
+ # will print:
+ #
+ # DRYRUN: Building Project
+ #
+ # instead of actually building the project.
+ #
+ def when_writing(msg=nil)
+ if FileUtilsExt.nowrite_flag
+ $stderr.puts "DRYRUN: #{msg}" if msg
+ else
+ yield
+ end
+ end
+
+ # Merge the given options with the default values.
+ def rake_merge_option(args, defaults)
+ if Hash === args.last
+ defaults.update(args.last)
+ args.pop
+ end
+ args.push defaults
+ args
+ end
+
+ # Send the message to the default rake output (which is $stderr).
+ def rake_output_message(message)
+ $stderr.puts(message)
+ end
+
+ # Check that the options do not contain options not listed in
+ # +optdecl+. An ArgumentError exception is thrown if non-declared
+ # options are found.
+ def rake_check_options(options, *optdecl)
+ h = options.dup
+ optdecl.each do |name|
+ h.delete name
+ end
+ raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless
+ h.empty?
+ end
+
+ extend self
+ end
+end
diff --git a/ruby_2_2/lib/rake/gempackagetask.rb b/ruby_2_2/lib/rake/gempackagetask.rb
new file mode 100644
index 0000000000..16e7ce042b
--- /dev/null
+++ b/ruby_2_2/lib/rake/gempackagetask.rb
@@ -0,0 +1,4 @@
+# TODO: Remove in Rake 11
+
+fail "ERROR: 'rake/gempackagetask' is obsolete and no longer supported. " +
+ "Use 'rubygems/package_task' instead."
diff --git a/ruby_2_2/lib/rake/invocation_chain.rb b/ruby_2_2/lib/rake/invocation_chain.rb
new file mode 100644
index 0000000000..540628957c
--- /dev/null
+++ b/ruby_2_2/lib/rake/invocation_chain.rb
@@ -0,0 +1,56 @@
+module Rake
+
+ # InvocationChain tracks the chain of task invocations to detect
+ # circular dependencies.
+ class InvocationChain < LinkedList
+
+ # Is the invocation already in the chain?
+ def member?(invocation)
+ head == invocation || tail.member?(invocation)
+ end
+
+ # Append an invocation to the chain of invocations. It is an error
+ # if the invocation already listed.
+ def append(invocation)
+ if member?(invocation)
+ fail RuntimeError, "Circular dependency detected: #{to_s} => #{invocation}"
+ end
+ conj(invocation)
+ end
+
+ # Convert to string, ie: TOP => invocation => invocation
+ def to_s
+ "#{prefix}#{head}"
+ end
+
+ # Class level append.
+ def self.append(invocation, chain)
+ chain.append(invocation)
+ end
+
+ private
+
+ def prefix
+ "#{tail} => "
+ end
+
+ # Null object for an empty chain.
+ class EmptyInvocationChain < LinkedList::EmptyLinkedList
+ @parent = InvocationChain
+
+ def member?(obj)
+ false
+ end
+
+ def append(invocation)
+ conj(invocation)
+ end
+
+ def to_s
+ "TOP"
+ end
+ end
+
+ EMPTY = EmptyInvocationChain.new
+ end
+end
diff --git a/ruby_2_2/lib/rake/invocation_exception_mixin.rb b/ruby_2_2/lib/rake/invocation_exception_mixin.rb
new file mode 100644
index 0000000000..84ff3353ba
--- /dev/null
+++ b/ruby_2_2/lib/rake/invocation_exception_mixin.rb
@@ -0,0 +1,16 @@
+module Rake
+ module InvocationExceptionMixin
+ # Return the invocation chain (list of Rake tasks) that were in
+ # effect when this exception was detected by rake. May be null if
+ # no tasks were active.
+ def chain
+ @rake_invocation_chain ||= nil
+ end
+
+ # Set the invocation chain in effect when this exception was
+ # detected.
+ def chain=(value)
+ @rake_invocation_chain = value
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/late_time.rb b/ruby_2_2/lib/rake/late_time.rb
new file mode 100644
index 0000000000..d959a7821f
--- /dev/null
+++ b/ruby_2_2/lib/rake/late_time.rb
@@ -0,0 +1,17 @@
+module Rake
+ # LateTime is a fake timestamp that occurs _after_ any other time value.
+ class LateTime
+ include Comparable
+ include Singleton
+
+ def <=>(other)
+ 1
+ end
+
+ def to_s
+ '<LATE TIME>'
+ end
+ end
+
+ LATE = LateTime.instance
+end
diff --git a/ruby_2_2/lib/rake/linked_list.rb b/ruby_2_2/lib/rake/linked_list.rb
new file mode 100644
index 0000000000..b5ab797808
--- /dev/null
+++ b/ruby_2_2/lib/rake/linked_list.rb
@@ -0,0 +1,103 @@
+module Rake
+
+ # Polylithic linked list structure used to implement several data
+ # structures in Rake.
+ class LinkedList
+ include Enumerable
+
+ attr_reader :head, :tail
+
+ def initialize(head, tail=EMPTY)
+ @head = head
+ @tail = tail
+ end
+
+ # Polymorphically add a new element to the head of a list. The
+ # type of head node will be the same list type as the tail.
+ def conj(item)
+ self.class.cons(item, self)
+ end
+
+ # Is the list empty?
+ def empty?
+ false
+ end
+
+ # Lists are structurally equivalent.
+ def ==(other)
+ current = self
+ while ! current.empty? && ! other.empty?
+ return false if current.head != other.head
+ current = current.tail
+ other = other.tail
+ end
+ current.empty? && other.empty?
+ end
+
+ # Convert to string: LL(item, item...)
+ def to_s
+ items = map { |item| item.to_s }.join(", ")
+ "LL(#{items})"
+ end
+
+ # Same as +to_s+, but with inspected items.
+ def inspect
+ items = map { |item| item.inspect }.join(", ")
+ "LL(#{items})"
+ end
+
+ # For each item in the list.
+ def each
+ current = self
+ while ! current.empty?
+ yield(current.head)
+ current = current.tail
+ end
+ self
+ end
+
+ # Make a list out of the given arguments. This method is
+ # polymorphic
+ def self.make(*args)
+ result = empty
+ args.reverse_each do |item|
+ result = cons(item, result)
+ end
+ result
+ end
+
+ # Cons a new head onto the tail list.
+ def self.cons(head, tail)
+ new(head, tail)
+ end
+
+ # The standard empty list class for the given LinkedList class.
+ def self.empty
+ self::EMPTY
+ end
+
+ # Represent an empty list, using the Null Object Pattern.
+ #
+ # When inheriting from the LinkedList class, you should implement
+ # a type specific Empty class as well. Make sure you set the class
+ # instance variable @parent to the associated list class (this
+ # allows conj, cons and make to work polymorphically).
+ class EmptyLinkedList < LinkedList
+ @parent = LinkedList
+
+ def initialize
+ end
+
+ def empty?
+ true
+ end
+
+ def self.cons(head, tail)
+ @parent.cons(head, tail)
+ end
+ end
+
+ EMPTY = EmptyLinkedList.new
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/loaders/makefile.rb b/ruby_2_2/lib/rake/loaders/makefile.rb
new file mode 100644
index 0000000000..4ece4323af
--- /dev/null
+++ b/ruby_2_2/lib/rake/loaders/makefile.rb
@@ -0,0 +1,40 @@
+module Rake
+
+ # Makefile loader to be used with the import file loader.
+ class MakefileLoader
+ include Rake::DSL
+
+ SPACE_MARK = "\0"
+
+ # Load the makefile dependencies in +fn+.
+ def load(fn)
+ lines = File.read fn
+ lines.gsub!(/\\ /, SPACE_MARK)
+ lines.gsub!(/#[^\n]*\n/m, "")
+ lines.gsub!(/\\\n/, ' ')
+ lines.each_line do |line|
+ process_line(line)
+ end
+ end
+
+ private
+
+ # Process one logical line of makefile data.
+ def process_line(line)
+ file_tasks, args = line.split(':', 2)
+ return if args.nil?
+ dependents = args.split.map { |d| respace(d) }
+ file_tasks.scan(/\S+/) do |file_task|
+ file_task = respace(file_task)
+ file file_task => dependents
+ end
+ end
+
+ def respace(str)
+ str.tr SPACE_MARK, ' '
+ end
+ end
+
+ # Install the handler
+ Rake.application.add_loader('mf', MakefileLoader.new)
+end
diff --git a/ruby_2_2/lib/rake/multi_task.rb b/ruby_2_2/lib/rake/multi_task.rb
new file mode 100644
index 0000000000..5418a7a7b0
--- /dev/null
+++ b/ruby_2_2/lib/rake/multi_task.rb
@@ -0,0 +1,13 @@
+module Rake
+
+ # Same as a regular task, but the immediate prerequisites are done in
+ # parallel using Ruby threads.
+ #
+ class MultiTask < Task
+ private
+ def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
+ invoke_prerequisites_concurrently(task_args, invocation_chain)
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/name_space.rb b/ruby_2_2/lib/rake/name_space.rb
new file mode 100644
index 0000000000..58f911e434
--- /dev/null
+++ b/ruby_2_2/lib/rake/name_space.rb
@@ -0,0 +1,38 @@
+##
+# The NameSpace class will lookup task names in the scope defined by a
+# +namespace+ command.
+
+class Rake::NameSpace
+
+ ##
+ # Create a namespace lookup object using the given task manager
+ # and the list of scopes.
+
+ def initialize(task_manager, scope_list)
+ @task_manager = task_manager
+ @scope = scope_list.dup
+ end
+
+ ##
+ # Lookup a task named +name+ in the namespace.
+
+ def [](name)
+ @task_manager.lookup(name, @scope)
+ end
+
+ ##
+ # The scope of the namespace (a LinkedList)
+
+ def scope
+ @scope.dup
+ end
+
+ ##
+ # Return the list of tasks defined in this and nested namespaces.
+
+ def tasks
+ @task_manager.tasks_in_scope(@scope)
+ end
+
+end
+
diff --git a/ruby_2_2/lib/rake/packagetask.rb b/ruby_2_2/lib/rake/packagetask.rb
new file mode 100644
index 0000000000..249ee72b11
--- /dev/null
+++ b/ruby_2_2/lib/rake/packagetask.rb
@@ -0,0 +1,199 @@
+# Define a package task library to aid in the definition of
+# redistributable package files.
+
+require 'rake'
+require 'rake/tasklib'
+
+module Rake
+
+ # Create a packaging task that will package the project into
+ # distributable files (e.g zip archive or tar files).
+ #
+ # The PackageTask will create the following targets:
+ #
+ # +:package+ ::
+ # Create all the requested package files.
+ #
+ # +:clobber_package+ ::
+ # Delete all the package files. This target is automatically
+ # added to the main clobber target.
+ #
+ # +:repackage+ ::
+ # Rebuild the package files from scratch, even if they are not out
+ # of date.
+ #
+ # <tt>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tgz"</tt> ::
+ # Create a gzipped tar package (if <em>need_tar</em> is true).
+ #
+ # <tt>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.gz"</tt> ::
+ # Create a gzipped tar package (if <em>need_tar_gz</em> is true).
+ #
+ # <tt>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.bz2"</tt> ::
+ # Create a bzip2'd tar package (if <em>need_tar_bz2</em> is true).
+ #
+ # <tt>"<em>package_dir</em>/<em>name</em>-<em>version</em>.zip"</tt> ::
+ # Create a zip package archive (if <em>need_zip</em> is true).
+ #
+ # Example:
+ #
+ # Rake::PackageTask.new("rake", "1.2.3") do |p|
+ # p.need_tar = true
+ # p.package_files.include("lib/**/*.rb")
+ # end
+ #
+ class PackageTask < TaskLib
+ # Name of the package (from the GEM Spec).
+ attr_accessor :name
+
+ # Version of the package (e.g. '1.3.2').
+ attr_accessor :version
+
+ # Directory used to store the package files (default is 'pkg').
+ attr_accessor :package_dir
+
+ # True if a gzipped tar file (tgz) should be produced (default is
+ # false).
+ attr_accessor :need_tar
+
+ # True if a gzipped tar file (tar.gz) should be produced (default
+ # is false).
+ attr_accessor :need_tar_gz
+
+ # True if a bzip2'd tar file (tar.bz2) should be produced (default
+ # is false).
+ attr_accessor :need_tar_bz2
+
+ # True if a zip file should be produced (default is false)
+ attr_accessor :need_zip
+
+ # List of files to be included in the package.
+ attr_accessor :package_files
+
+ # Tar command for gzipped or bzip2ed archives. The default is 'tar'.
+ attr_accessor :tar_command
+
+ # Zip command for zipped archives. The default is 'zip'.
+ attr_accessor :zip_command
+
+ # Create a Package Task with the given name and version. Use +:noversion+
+ # as the version to build a package without a version or to provide a
+ # fully-versioned package name.
+
+ def initialize(name=nil, version=nil)
+ init(name, version)
+ yield self if block_given?
+ define unless name.nil?
+ end
+
+ # Initialization that bypasses the "yield self" and "define" step.
+ def init(name, version)
+ @name = name
+ @version = version
+ @package_files = Rake::FileList.new
+ @package_dir = 'pkg'
+ @need_tar = false
+ @need_tar_gz = false
+ @need_tar_bz2 = false
+ @need_zip = false
+ @tar_command = 'tar'
+ @zip_command = 'zip'
+ end
+
+ # Create the tasks defined by this task library.
+ def define
+ fail "Version required (or :noversion)" if @version.nil?
+ @version = nil if :noversion == @version
+
+ desc "Build all the packages"
+ task :package
+
+ desc "Force a rebuild of the package files"
+ task :repackage => [:clobber_package, :package]
+
+ desc "Remove package products"
+ task :clobber_package do
+ rm_r package_dir rescue nil
+ end
+
+ task :clobber => [:clobber_package]
+
+ [
+ [need_tar, tgz_file, "z"],
+ [need_tar_gz, tar_gz_file, "z"],
+ [need_tar_bz2, tar_bz2_file, "j"]
+ ].each do |(need, file, flag)|
+ if need
+ task :package => ["#{package_dir}/#{file}"]
+ file "#{package_dir}/#{file}" =>
+ [package_dir_path] + package_files do
+ chdir(package_dir) do
+ sh @tar_command, "#{flag}cvf", file, package_name
+ end
+ end
+ end
+ end
+
+ if need_zip
+ task :package => ["#{package_dir}/#{zip_file}"]
+ file "#{package_dir}/#{zip_file}" =>
+ [package_dir_path] + package_files do
+ chdir(package_dir) do
+ sh @zip_command, "-r", zip_file, package_name
+ end
+ end
+ end
+
+ directory package_dir_path => @package_files do
+ @package_files.each do |fn|
+ f = File.join(package_dir_path, fn)
+ fdir = File.dirname(f)
+ mkdir_p(fdir) unless File.exist?(fdir)
+ if File.directory?(fn)
+ mkdir_p(f)
+ else
+ rm_f f
+ safe_ln(fn, f)
+ end
+ end
+ end
+ self
+ end
+
+ # The name of this package
+
+ def package_name
+ @version ? "#{@name}-#{@version}" : @name
+ end
+
+ # The directory this package will be built in
+
+ def package_dir_path
+ "#{package_dir}/#{package_name}"
+ end
+
+ # The package name with .tgz added
+
+ def tgz_file
+ "#{package_name}.tgz"
+ end
+
+ # The package name with .tar.gz added
+
+ def tar_gz_file
+ "#{package_name}.tar.gz"
+ end
+
+ # The package name with .tar.bz2 added
+
+ def tar_bz2_file
+ "#{package_name}.tar.bz2"
+ end
+
+ # The package name with .zip added
+
+ def zip_file
+ "#{package_name}.zip"
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/pathmap.rb b/ruby_2_2/lib/rake/pathmap.rb
new file mode 100644
index 0000000000..9a840cda29
--- /dev/null
+++ b/ruby_2_2/lib/rake/pathmap.rb
@@ -0,0 +1,3 @@
+# TODO: Remove in Rake 11
+
+require 'rake/ext/string'
diff --git a/ruby_2_2/lib/rake/phony.rb b/ruby_2_2/lib/rake/phony.rb
new file mode 100644
index 0000000000..29633ae066
--- /dev/null
+++ b/ruby_2_2/lib/rake/phony.rb
@@ -0,0 +1,15 @@
+# Defines a :phony task that you can use as a dependency. This allows
+# file-based tasks to use non-file-based tasks as prerequisites
+# without forcing them to rebuild.
+#
+# See FileTask#out_of_date? and Task#timestamp for more info.
+
+require 'rake'
+
+task :phony
+
+Rake::Task[:phony].tap do |task|
+ def task.timestamp # :nodoc:
+ Time.at 0
+ end
+end
diff --git a/ruby_2_2/lib/rake/private_reader.rb b/ruby_2_2/lib/rake/private_reader.rb
new file mode 100644
index 0000000000..1620978576
--- /dev/null
+++ b/ruby_2_2/lib/rake/private_reader.rb
@@ -0,0 +1,20 @@
+module Rake
+
+ # Include PrivateReader to use +private_reader+.
+ module PrivateReader # :nodoc: all
+
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+
+ # Declare a list of private accessors
+ def private_reader(*names)
+ attr_reader(*names)
+ private(*names)
+ end
+ end
+
+ end
+end
diff --git a/ruby_2_2/lib/rake/promise.rb b/ruby_2_2/lib/rake/promise.rb
new file mode 100644
index 0000000000..31c4563476
--- /dev/null
+++ b/ruby_2_2/lib/rake/promise.rb
@@ -0,0 +1,99 @@
+module Rake
+
+ # A Promise object represents a promise to do work (a chore) in the
+ # future. The promise is created with a block and a list of
+ # arguments for the block. Calling value will return the value of
+ # the promised chore.
+ #
+ # Used by ThreadPool.
+ #
+ class Promise # :nodoc: all
+ NOT_SET = Object.new.freeze # :nodoc:
+
+ attr_accessor :recorder
+
+ # Create a promise to do the chore specified by the block.
+ def initialize(args, &block)
+ @mutex = Mutex.new
+ @result = NOT_SET
+ @error = NOT_SET
+ @args = args
+ @block = block
+ end
+
+ # Return the value of this promise.
+ #
+ # If the promised chore is not yet complete, then do the work
+ # synchronously. We will wait.
+ def value
+ unless complete?
+ stat :sleeping_on, :item_id => object_id
+ @mutex.synchronize do
+ stat :has_lock_on, :item_id => object_id
+ chore
+ stat :releasing_lock_on, :item_id => object_id
+ end
+ end
+ error? ? raise(@error) : @result
+ end
+
+ # If no one else is working this promise, go ahead and do the chore.
+ def work
+ stat :attempting_lock_on, :item_id => object_id
+ if @mutex.try_lock
+ stat :has_lock_on, :item_id => object_id
+ chore
+ stat :releasing_lock_on, :item_id => object_id
+ @mutex.unlock
+ else
+ stat :bailed_on, :item_id => object_id
+ end
+ end
+
+ private
+
+ # Perform the chore promised
+ def chore
+ if complete?
+ stat :found_completed, :item_id => object_id
+ return
+ end
+ stat :will_execute, :item_id => object_id
+ begin
+ @result = @block.call(*@args)
+ rescue Exception => e
+ @error = e
+ end
+ stat :did_execute, :item_id => object_id
+ discard
+ end
+
+ # Do we have a result for the promise
+ def result?
+ ! @result.equal?(NOT_SET)
+ end
+
+ # Did the promise throw an error
+ def error?
+ ! @error.equal?(NOT_SET)
+ end
+
+ # Are we done with the promise
+ def complete?
+ result? || error?
+ end
+
+ # free up these items for the GC
+ def discard
+ @args = nil
+ @block = nil
+ end
+
+ # Record execution statistics if there is a recorder
+ def stat(*args)
+ @recorder.call(*args) if @recorder
+ end
+
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/pseudo_status.rb b/ruby_2_2/lib/rake/pseudo_status.rb
new file mode 100644
index 0000000000..16e1903bd6
--- /dev/null
+++ b/ruby_2_2/lib/rake/pseudo_status.rb
@@ -0,0 +1,29 @@
+module Rake
+
+ ##
+ # Exit status class for times the system just gives us a nil.
+ class PseudoStatus # :nodoc: all
+ attr_reader :exitstatus
+
+ def initialize(code=0)
+ @exitstatus = code
+ end
+
+ def to_i
+ @exitstatus << 8
+ end
+
+ def >>(n)
+ to_i >> n
+ end
+
+ def stopped?
+ false
+ end
+
+ def exited?
+ true
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/rake_module.rb b/ruby_2_2/lib/rake/rake_module.rb
new file mode 100644
index 0000000000..3692753434
--- /dev/null
+++ b/ruby_2_2/lib/rake/rake_module.rb
@@ -0,0 +1,38 @@
+require 'rake/application'
+
+module Rake
+
+ class << self
+ # Current Rake Application
+ def application
+ @application ||= Rake::Application.new
+ end
+
+ # Set the current Rake application object.
+ def application=(app)
+ @application = app
+ end
+
+ def suggested_thread_count # :nodoc:
+ @cpu_count ||= Rake::CpuCounter.count
+ @cpu_count + 4
+ end
+
+ # Return the original directory where the Rake application was started.
+ def original_dir
+ application.original_dir
+ end
+
+ # Load a rakefile.
+ def load_rakefile(path)
+ load(path)
+ end
+
+ # Add files to the rakelib list
+ def add_rakelib(*files)
+ application.options.rakelib ||= []
+ application.options.rakelib.concat(files)
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/rake_test_loader.rb b/ruby_2_2/lib/rake/rake_test_loader.rb
new file mode 100644
index 0000000000..7e3a6b3f35
--- /dev/null
+++ b/ruby_2_2/lib/rake/rake_test_loader.rb
@@ -0,0 +1,22 @@
+require 'rake'
+
+# Load the test files from the command line.
+argv = ARGV.select do |argument|
+ case argument
+ when /^-/ then
+ argument
+ when /\*/ then
+ FileList[argument].to_a.each do |file|
+ require File.expand_path file
+ end
+
+ false
+ else
+ require File.expand_path argument
+
+ false
+ end
+end
+
+ARGV.replace argv
+
diff --git a/ruby_2_2/lib/rake/rdoctask.rb b/ruby_2_2/lib/rake/rdoctask.rb
new file mode 100644
index 0000000000..8d7df4f12b
--- /dev/null
+++ b/ruby_2_2/lib/rake/rdoctask.rb
@@ -0,0 +1,4 @@
+# TODO: Remove in Rake 11
+
+fail "ERROR: 'rake/rdoctask' is obsolete and no longer supported. " +
+ "Use 'rdoc/task' (available in RDoc 2.4.2+) instead."
diff --git a/ruby_2_2/lib/rake/ruby182_test_unit_fix.rb b/ruby_2_2/lib/rake/ruby182_test_unit_fix.rb
new file mode 100644
index 0000000000..40b30a6fde
--- /dev/null
+++ b/ruby_2_2/lib/rake/ruby182_test_unit_fix.rb
@@ -0,0 +1,29 @@
+# TODO: Remove in rake 11
+
+# Local Rake override to fix bug in Ruby 0.8.2
+module Test # :nodoc:
+ # Local Rake override to fix bug in Ruby 0.8.2
+ module Unit # :nodoc:
+ # Local Rake override to fix bug in Ruby 0.8.2
+ module Collector # :nodoc:
+ # Local Rake override to fix bug in Ruby 0.8.2
+ class Dir # :nodoc:
+ undef collect_file
+ def collect_file(name, suites, already_gathered) # :nodoc:
+ dir = File.dirname(File.expand_path(name))
+ $:.unshift(dir) unless $:.first == dir
+ if @req
+ @req.require(name)
+ else
+ require(name)
+ end
+ find_test_cases(already_gathered).each do |t|
+ add_suite(suites, t.suite)
+ end
+ ensure
+ $:.delete_at $:.rindex(dir)
+ end
+ end
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/rule_recursion_overflow_error.rb b/ruby_2_2/lib/rake/rule_recursion_overflow_error.rb
new file mode 100644
index 0000000000..da4318da9d
--- /dev/null
+++ b/ruby_2_2/lib/rake/rule_recursion_overflow_error.rb
@@ -0,0 +1,20 @@
+
+module Rake
+
+ # Error indicating a recursion overflow error in task selection.
+ class RuleRecursionOverflowError < StandardError
+ def initialize(*args)
+ super
+ @targets = []
+ end
+
+ def add_target(target)
+ @targets << target
+ end
+
+ def message
+ super + ": [" + @targets.reverse.join(' => ') + "]"
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/runtest.rb b/ruby_2_2/lib/rake/runtest.rb
new file mode 100644
index 0000000000..4774b0e262
--- /dev/null
+++ b/ruby_2_2/lib/rake/runtest.rb
@@ -0,0 +1,27 @@
+require 'test/unit'
+require 'test/unit/assertions'
+require 'rake/file_list'
+
+module Rake
+ include Test::Unit::Assertions
+
+ ##
+ # Deprecated way of running tests in process, but only for Test::Unit.
+ #--
+ # TODO: Remove in rake 11
+
+ def run_tests(pattern='test/test*.rb', log_enabled=false) # :nodoc:
+ FileList.glob(pattern).each do |fn|
+ $stderr.puts fn if log_enabled
+ begin
+ require fn
+ rescue Exception => ex
+ $stderr.puts "Error in #{fn}: #{ex.message}"
+ $stderr.puts ex.backtrace
+ assert false
+ end
+ end
+ end
+
+ extend self
+end
diff --git a/ruby_2_2/lib/rake/scope.rb b/ruby_2_2/lib/rake/scope.rb
new file mode 100644
index 0000000000..dbefcea465
--- /dev/null
+++ b/ruby_2_2/lib/rake/scope.rb
@@ -0,0 +1,42 @@
+module Rake
+ class Scope < LinkedList # :nodoc: all
+
+ # Path for the scope.
+ def path
+ map { |item| item.to_s }.reverse.join(":")
+ end
+
+ # Path for the scope + the named path.
+ def path_with_task_name(task_name)
+ "#{path}:#{task_name}"
+ end
+
+ # Trim +n+ innermost scope levels from the scope. In no case will
+ # this trim beyond the toplevel scope.
+ def trim(n)
+ result = self
+ while n > 0 && ! result.empty?
+ result = result.tail
+ n -= 1
+ end
+ result
+ end
+
+ # Scope lists always end with an EmptyScope object. See Null
+ # Object Pattern)
+ class EmptyScope < EmptyLinkedList
+ @parent = Scope
+
+ def path
+ ""
+ end
+
+ def path_with_task_name(task_name)
+ task_name
+ end
+ end
+
+ # Singleton null object for an empty scope.
+ EMPTY = EmptyScope.new
+ end
+end
diff --git a/ruby_2_2/lib/rake/task.rb b/ruby_2_2/lib/rake/task.rb
new file mode 100644
index 0000000000..9bcf725523
--- /dev/null
+++ b/ruby_2_2/lib/rake/task.rb
@@ -0,0 +1,383 @@
+require 'rake/invocation_exception_mixin'
+
+module Rake
+
+ ##
+ # A Task is the basic unit of work in a Rakefile. Tasks have associated
+ # actions (possibly more than one) and a list of prerequisites. When
+ # invoked, a task will first ensure that all of its prerequisites have an
+ # opportunity to run and then it will execute its own actions.
+ #
+ # Tasks are not usually created directly using the new method, but rather
+ # use the +file+ and +task+ convenience methods.
+ #
+ class Task
+ # List of prerequisites for a task.
+ attr_reader :prerequisites
+
+ # List of actions attached to a task.
+ attr_reader :actions
+
+ # Application owning this task.
+ attr_accessor :application
+
+ # Array of nested namespaces names used for task lookup by this task.
+ attr_reader :scope
+
+ # File/Line locations of each of the task definitions for this
+ # task (only valid if the task was defined with the detect
+ # location option set).
+ attr_reader :locations
+
+ # Return task name
+ def to_s
+ name
+ end
+
+ def inspect # :nodoc:
+ "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
+ end
+
+ # List of sources for task.
+ attr_writer :sources
+ def sources
+ if defined?(@sources)
+ @sources
+ else
+ prerequisites
+ end
+ end
+
+ # List of prerequisite tasks
+ def prerequisite_tasks
+ prerequisites.map { |pre| lookup_prerequisite(pre) }
+ end
+
+ def lookup_prerequisite(prerequisite_name) # :nodoc:
+ application[prerequisite_name, @scope]
+ end
+ private :lookup_prerequisite
+
+ # List of all unique prerequisite tasks including prerequisite tasks'
+ # prerequisites.
+ # Includes self when cyclic dependencies are found.
+ def all_prerequisite_tasks
+ seen = {}
+ collect_prerequisites(seen)
+ seen.values
+ end
+
+ def collect_prerequisites(seen) # :nodoc:
+ prerequisite_tasks.each do |pre|
+ next if seen[pre.name]
+ seen[pre.name] = pre
+ pre.collect_prerequisites(seen)
+ end
+ end
+ protected :collect_prerequisites
+
+ # First source from a rule (nil if no sources)
+ def source
+ sources.first
+ end
+
+ # Create a task named +task_name+ with no actions or prerequisites. Use
+ # +enhance+ to add actions and prerequisites.
+ def initialize(task_name, app)
+ @name = task_name.to_s
+ @prerequisites = []
+ @actions = []
+ @already_invoked = false
+ @comments = []
+ @lock = Monitor.new
+ @application = app
+ @scope = app.current_scope
+ @arg_names = nil
+ @locations = []
+ end
+
+ # Enhance a task with prerequisites or actions. Returns self.
+ def enhance(deps=nil, &block)
+ @prerequisites |= deps if deps
+ @actions << block if block_given?
+ self
+ end
+
+ # Name of the task, including any namespace qualifiers.
+ def name
+ @name.to_s
+ end
+
+ # Name of task with argument list description.
+ def name_with_args # :nodoc:
+ if arg_description
+ "#{name}#{arg_description}"
+ else
+ name
+ end
+ end
+
+ # Argument description (nil if none).
+ def arg_description # :nodoc:
+ @arg_names ? "[#{arg_names.join(',')}]" : nil
+ end
+
+ # Name of arguments for this task.
+ def arg_names
+ @arg_names || []
+ end
+
+ # Reenable the task, allowing its tasks to be executed if the task
+ # is invoked again.
+ def reenable
+ @already_invoked = false
+ end
+
+ # Clear the existing prerequisites and actions of a rake task.
+ def clear
+ clear_prerequisites
+ clear_actions
+ clear_comments
+ self
+ end
+
+ # Clear the existing prerequisites of a rake task.
+ def clear_prerequisites
+ prerequisites.clear
+ self
+ end
+
+ # Clear the existing actions on a rake task.
+ def clear_actions
+ actions.clear
+ self
+ end
+
+ # Clear the existing comments on a rake task.
+ def clear_comments
+ @comments = []
+ self
+ end
+
+ # Invoke the task if it is needed. Prerequisites are invoked first.
+ def invoke(*args)
+ task_args = TaskArguments.new(arg_names, args)
+ invoke_with_call_chain(task_args, InvocationChain::EMPTY)
+ end
+
+ # Same as invoke, but explicitly pass a call chain to detect
+ # circular dependencies.
+ def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
+ new_chain = InvocationChain.append(self, invocation_chain)
+ @lock.synchronize do
+ if application.options.trace
+ application.trace "** Invoke #{name} #{format_trace_flags}"
+ end
+ return if @already_invoked
+ @already_invoked = true
+ invoke_prerequisites(task_args, new_chain)
+ execute(task_args) if needed?
+ end
+ rescue Exception => ex
+ add_chain_to(ex, new_chain)
+ raise ex
+ end
+ protected :invoke_with_call_chain
+
+ def add_chain_to(exception, new_chain) # :nodoc:
+ exception.extend(InvocationExceptionMixin) unless
+ exception.respond_to?(:chain)
+ exception.chain = new_chain if exception.chain.nil?
+ end
+ private :add_chain_to
+
+ # Invoke all the prerequisites of a task.
+ def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
+ if application.options.always_multitask
+ invoke_prerequisites_concurrently(task_args, invocation_chain)
+ else
+ prerequisite_tasks.each { |p|
+ prereq_args = task_args.new_scope(p.arg_names)
+ p.invoke_with_call_chain(prereq_args, invocation_chain)
+ }
+ end
+ end
+
+ # Invoke all the prerequisites of a task in parallel.
+ def invoke_prerequisites_concurrently(task_args, invocation_chain)# :nodoc:
+ futures = prerequisite_tasks.map do |p|
+ prereq_args = task_args.new_scope(p.arg_names)
+ application.thread_pool.future(p) do |r|
+ r.invoke_with_call_chain(prereq_args, invocation_chain)
+ end
+ end
+ futures.each { |f| f.value }
+ end
+
+ # Format the trace flags for display.
+ def format_trace_flags
+ flags = []
+ flags << "first_time" unless @already_invoked
+ flags << "not_needed" unless needed?
+ flags.empty? ? "" : "(" + flags.join(", ") + ")"
+ end
+ private :format_trace_flags
+
+ # Execute the actions associated with this task.
+ def execute(args=nil)
+ args ||= EMPTY_TASK_ARGS
+ if application.options.dryrun
+ application.trace "** Execute (dry run) #{name}"
+ return
+ end
+ application.trace "** Execute #{name}" if application.options.trace
+ application.enhance_with_matching_rule(name) if @actions.empty?
+ @actions.each do |act|
+ case act.arity
+ when 1
+ act.call(self)
+ else
+ act.call(self, args)
+ end
+ end
+ end
+
+ # Is this task needed?
+ def needed?
+ true
+ end
+
+ # Timestamp for this task. Basic tasks return the current time for their
+ # time stamp. Other tasks can be more sophisticated.
+ def timestamp
+ Time.now
+ end
+
+ # Add a description to the task. The description can consist of an option
+ # argument list (enclosed brackets) and an optional comment.
+ def add_description(description)
+ return unless description
+ comment = description.strip
+ add_comment(comment) if comment && ! comment.empty?
+ end
+
+ def comment=(comment) # :nodoc:
+ add_comment(comment)
+ end
+
+ def add_comment(comment) # :nodoc:
+ return if comment.nil?
+ @comments << comment unless @comments.include?(comment)
+ end
+ private :add_comment
+
+ # Full collection of comments. Multiple comments are separated by
+ # newlines.
+ def full_comment
+ transform_comments("\n")
+ end
+
+ # First line (or sentence) of all comments. Multiple comments are
+ # separated by a "/".
+ def comment
+ transform_comments(" / ") { |c| first_sentence(c) }
+ end
+
+ # Transform the list of comments as specified by the block and
+ # join with the separator.
+ def transform_comments(separator, &block)
+ if @comments.empty?
+ nil
+ else
+ block ||= lambda { |c| c }
+ @comments.map(&block).join(separator)
+ end
+ end
+ private :transform_comments
+
+ # Get the first sentence in a string. The sentence is terminated
+ # by the first period or the end of the line. Decimal points do
+ # not count as periods.
+ def first_sentence(string)
+ string.split(/\.[ \t]|\.$|\n/).first
+ end
+ private :first_sentence
+
+ # Set the names of the arguments for this task. +args+ should be
+ # an array of symbols, one for each argument name.
+ def set_arg_names(args)
+ @arg_names = args.map { |a| a.to_sym }
+ end
+
+ # Return a string describing the internal state of a task. Useful for
+ # debugging.
+ def investigation
+ result = "------------------------------\n"
+ result << "Investigating #{name}\n"
+ result << "class: #{self.class}\n"
+ result << "task needed: #{needed?}\n"
+ result << "timestamp: #{timestamp}\n"
+ result << "pre-requisites: \n"
+ prereqs = prerequisite_tasks
+ prereqs.sort! { |a, b| a.timestamp <=> b.timestamp }
+ prereqs.each do |p|
+ result << "--#{p.name} (#{p.timestamp})\n"
+ end
+ latest_prereq = prerequisite_tasks.map { |pre| pre.timestamp }.max
+ result << "latest-prerequisite time: #{latest_prereq}\n"
+ result << "................................\n\n"
+ return result
+ end
+
+ # ----------------------------------------------------------------
+ # Rake Module Methods
+ #
+ class << self
+
+ # Clear the task list. This cause rake to immediately forget all the
+ # tasks that have been assigned. (Normally used in the unit tests.)
+ def clear
+ Rake.application.clear
+ end
+
+ # List of all defined tasks.
+ def tasks
+ Rake.application.tasks
+ end
+
+ # Return a task with the given name. If the task is not currently
+ # known, try to synthesize one from the defined rules. If no rules are
+ # found, but an existing file matches the task name, assume it is a file
+ # task with no dependencies or actions.
+ def [](task_name)
+ Rake.application[task_name]
+ end
+
+ # TRUE if the task name is already defined.
+ def task_defined?(task_name)
+ Rake.application.lookup(task_name) != nil
+ end
+
+ # Define a task given +args+ and an option block. If a rule with the
+ # given name already exists, the prerequisites and actions are added to
+ # the existing task. Returns the defined task.
+ def define_task(*args, &block)
+ Rake.application.define_task(self, *args, &block)
+ end
+
+ # Define a rule for synthesizing tasks.
+ def create_rule(*args, &block)
+ Rake.application.create_rule(*args, &block)
+ end
+
+ # Apply the scope to the task name according to the rules for
+ # this kind of task. Generic tasks will accept the scope as
+ # part of the name.
+ def scope_name(scope, task_name)
+# (scope + [task_name]).join(':')
+ scope.path_with_task_name(task_name)
+ end
+
+ end # class << Rake::Task
+ end # class Rake::Task
+end
diff --git a/ruby_2_2/lib/rake/task_argument_error.rb b/ruby_2_2/lib/rake/task_argument_error.rb
new file mode 100644
index 0000000000..3e1dda64db
--- /dev/null
+++ b/ruby_2_2/lib/rake/task_argument_error.rb
@@ -0,0 +1,7 @@
+module Rake
+
+ # Error indicating an ill-formed task declaration.
+ class TaskArgumentError < ArgumentError
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/task_arguments.rb b/ruby_2_2/lib/rake/task_arguments.rb
new file mode 100644
index 0000000000..fc0d657274
--- /dev/null
+++ b/ruby_2_2/lib/rake/task_arguments.rb
@@ -0,0 +1,98 @@
+module Rake
+
+ ##
+ # TaskArguments manage the arguments passed to a task.
+ #
+ class TaskArguments
+ include Enumerable
+
+ # Argument names
+ attr_reader :names
+
+ # Create a TaskArgument object with a list of argument +names+ and a set
+ # of associated +values+. +parent+ is the parent argument object.
+ def initialize(names, values, parent=nil)
+ @names = names
+ @parent = parent
+ @hash = {}
+ @values = values
+ names.each_with_index { |name, i|
+ @hash[name.to_sym] = values[i] unless values[i].nil?
+ }
+ end
+
+ # Retrieve the complete array of sequential values
+ def to_a
+ @values.dup
+ end
+
+ # Retrieve the list of values not associated with named arguments
+ def extras
+ @values[@names.length..-1] || []
+ end
+
+ # Create a new argument scope using the prerequisite argument
+ # names.
+ def new_scope(names)
+ values = names.map { |n| self[n] }
+ self.class.new(names, values + extras, self)
+ end
+
+ # Find an argument value by name or index.
+ def [](index)
+ lookup(index.to_sym)
+ end
+
+ # Specify a hash of default values for task arguments. Use the
+ # defaults only if there is no specific value for the given
+ # argument.
+ def with_defaults(defaults)
+ @hash = defaults.merge(@hash)
+ end
+
+ # Enumerates the arguments and their values
+ def each(&block)
+ @hash.each(&block)
+ end
+
+ # Extracts the argument values at +keys+
+ def values_at(*keys)
+ keys.map { |k| lookup(k) }
+ end
+
+ # Returns the value of the given argument via method_missing
+ def method_missing(sym, *args)
+ lookup(sym.to_sym)
+ end
+
+ # Returns a Hash of arguments and their values
+ def to_hash
+ @hash
+ end
+
+ def to_s # :nodoc:
+ @hash.inspect
+ end
+
+ def inspect # :nodoc:
+ to_s
+ end
+
+ # Returns true if +key+ is one of the arguments
+ def has_key?(key)
+ @hash.has_key?(key)
+ end
+
+ protected
+
+ def lookup(name) # :nodoc:
+ if @hash.has_key?(name)
+ @hash[name]
+ elsif @parent
+ @parent.lookup(name)
+ end
+ end
+ end
+
+ EMPTY_TASK_ARGS = TaskArguments.new([], []) # :nodoc:
+end
diff --git a/ruby_2_2/lib/rake/task_manager.rb b/ruby_2_2/lib/rake/task_manager.rb
new file mode 100644
index 0000000000..cbb9f5ee2f
--- /dev/null
+++ b/ruby_2_2/lib/rake/task_manager.rb
@@ -0,0 +1,310 @@
+module Rake
+
+ # The TaskManager module is a mixin for managing tasks.
+ module TaskManager
+ # Track the last comment made in the Rakefile.
+ attr_accessor :last_description
+
+ # TODO: Remove in Rake 11
+
+ alias :last_comment :last_description # :nodoc: Backwards compatibility
+
+ def initialize # :nodoc:
+ super
+ @tasks = Hash.new
+ @rules = Array.new
+ @scope = Scope.make
+ @last_description = nil
+ end
+
+ def create_rule(*args, &block) # :nodoc:
+ pattern, args, deps = resolve_args(args)
+ pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
+ @rules << [pattern, args, deps, block]
+ end
+
+ def define_task(task_class, *args, &block) # :nodoc:
+ task_name, arg_names, deps = resolve_args(args)
+
+ original_scope = @scope
+ if String === task_name and
+ not task_class.ancestors.include? Rake::FileTask then
+ task_name, *definition_scope = *(task_name.split(":").reverse)
+ @scope = Scope.make(*(definition_scope + @scope.to_a))
+ end
+
+ task_name = task_class.scope_name(@scope, task_name)
+ deps = [deps] unless deps.respond_to?(:to_ary)
+ deps = deps.map { |d| Rake.from_pathname(d).to_s }
+ task = intern(task_class, task_name)
+ task.set_arg_names(arg_names) unless arg_names.empty?
+ if Rake::TaskManager.record_task_metadata
+ add_location(task)
+ task.add_description(get_description(task))
+ end
+ task.enhance(deps, &block)
+ ensure
+ @scope = original_scope
+ end
+
+ # Lookup a task. Return an existing task if found, otherwise
+ # create a task of the current type.
+ def intern(task_class, task_name)
+ @tasks[task_name.to_s] ||= task_class.new(task_name, self)
+ end
+
+ # Find a matching task for +task_name+.
+ def [](task_name, scopes=nil)
+ task_name = task_name.to_s
+ self.lookup(task_name, scopes) or
+ enhance_with_matching_rule(task_name) or
+ synthesize_file_task(task_name) or
+ fail "Don't know how to build task '#{task_name}'"
+ end
+
+ def synthesize_file_task(task_name) # :nodoc:
+ return nil unless File.exist?(task_name)
+ define_task(Rake::FileTask, task_name)
+ end
+
+ # Resolve the arguments for a task/rule. Returns a triplet of
+ # [task_name, arg_name_list, prerequisites].
+ def resolve_args(args)
+ if args.last.is_a?(Hash)
+ deps = args.pop
+ resolve_args_with_dependencies(args, deps)
+ else
+ resolve_args_without_dependencies(args)
+ end
+ end
+
+ # Resolve task arguments for a task or rule when there are no
+ # dependencies declared.
+ #
+ # The patterns recognized by this argument resolving function are:
+ #
+ # task :t
+ # task :t, [:a]
+ #
+ def resolve_args_without_dependencies(args)
+ task_name = args.shift
+ if args.size == 1 && args.first.respond_to?(:to_ary)
+ arg_names = args.first.to_ary
+ else
+ arg_names = args
+ end
+ [task_name, arg_names, []]
+ end
+ private :resolve_args_without_dependencies
+
+ # Resolve task arguments for a task or rule when there are
+ # dependencies declared.
+ #
+ # The patterns recognized by this argument resolving function are:
+ #
+ # task :t => [:d]
+ # task :t, [a] => [:d]
+ #
+ def resolve_args_with_dependencies(args, hash) # :nodoc:
+ fail "Task Argument Error" if hash.size != 1
+ key, value = hash.map { |k, v| [k, v] }.first
+ if args.empty?
+ task_name = key
+ arg_names = []
+ deps = value || []
+ else
+ task_name = args.shift
+ arg_names = key
+ deps = value
+ end
+ deps = [deps] unless deps.respond_to?(:to_ary)
+ [task_name, arg_names, deps]
+ end
+ private :resolve_args_with_dependencies
+
+ # If a rule can be found that matches the task name, enhance the
+ # task with the prerequisites and actions from the rule. Set the
+ # source attribute of the task appropriately for the rule. Return
+ # the enhanced task or nil of no rule was found.
+ def enhance_with_matching_rule(task_name, level=0)
+ fail Rake::RuleRecursionOverflowError,
+ "Rule Recursion Too Deep" if level >= 16
+ @rules.each do |pattern, args, extensions, block|
+ if pattern.match(task_name)
+ task = attempt_rule(task_name, args, extensions, block, level)
+ return task if task
+ end
+ end
+ nil
+ rescue Rake::RuleRecursionOverflowError => ex
+ ex.add_target(task_name)
+ fail ex
+ end
+
+ # List of all defined tasks in this application.
+ def tasks
+ @tasks.values.sort_by { |t| t.name }
+ end
+
+ # List of all the tasks defined in the given scope (and its
+ # sub-scopes).
+ def tasks_in_scope(scope)
+ prefix = scope.path
+ tasks.select { |t|
+ /^#{prefix}:/ =~ t.name
+ }
+ end
+
+ # Clear all tasks in this application.
+ def clear
+ @tasks.clear
+ @rules.clear
+ end
+
+ # Lookup a task, using scope and the scope hints in the task name.
+ # This method performs straight lookups without trying to
+ # synthesize file tasks or rules. Special scope names (e.g. '^')
+ # are recognized. If no scope argument is supplied, use the
+ # current scope. Return nil if the task cannot be found.
+ def lookup(task_name, initial_scope=nil)
+ initial_scope ||= @scope
+ task_name = task_name.to_s
+ if task_name =~ /^rake:/
+ scopes = Scope.make
+ task_name = task_name.sub(/^rake:/, '')
+ elsif task_name =~ /^(\^+)/
+ scopes = initial_scope.trim($1.size)
+ task_name = task_name.sub(/^(\^+)/, '')
+ else
+ scopes = initial_scope
+ end
+ lookup_in_scope(task_name, scopes)
+ end
+
+ # Lookup the task name
+ def lookup_in_scope(name, scope)
+ loop do
+ tn = scope.path_with_task_name(name)
+ task = @tasks[tn]
+ return task if task
+ break if scope.empty?
+ scope = scope.tail
+ end
+ nil
+ end
+ private :lookup_in_scope
+
+ # Return the list of scope names currently active in the task
+ # manager.
+ def current_scope
+ @scope
+ end
+
+ # Evaluate the block in a nested namespace named +name+. Create
+ # an anonymous namespace if +name+ is nil.
+ def in_namespace(name)
+ name ||= generate_name
+ @scope = Scope.new(name, @scope)
+ ns = NameSpace.new(self, @scope)
+ yield(ns)
+ ns
+ ensure
+ @scope = @scope.tail
+ end
+
+ private
+
+ # Add a location to the locations field of the given task.
+ def add_location(task)
+ loc = find_location
+ task.locations << loc if loc
+ task
+ end
+
+ # Find the location that called into the dsl layer.
+ def find_location
+ locations = caller
+ i = 0
+ while locations[i]
+ return locations[i + 1] if locations[i] =~ /rake\/dsl_definition.rb/
+ i += 1
+ end
+ nil
+ end
+
+ # Generate an anonymous namespace name.
+ def generate_name
+ @seed ||= 0
+ @seed += 1
+ "_anon_#{@seed}"
+ end
+
+ def trace_rule(level, message) # :nodoc:
+ options.trace_output.puts "#{" " * level}#{message}" if
+ Rake.application.options.trace_rules
+ end
+
+ # Attempt to create a rule given the list of prerequisites.
+ def attempt_rule(task_name, args, extensions, block, level)
+ sources = make_sources(task_name, extensions)
+ prereqs = sources.map { |source|
+ trace_rule level, "Attempting Rule #{task_name} => #{source}"
+ if File.exist?(source) || Rake::Task.task_defined?(source)
+ trace_rule level, "(#{task_name} => #{source} ... EXIST)"
+ source
+ elsif parent = enhance_with_matching_rule(source, level + 1)
+ trace_rule level, "(#{task_name} => #{source} ... ENHANCE)"
+ parent.name
+ else
+ trace_rule level, "(#{task_name} => #{source} ... FAIL)"
+ return nil
+ end
+ }
+ task = FileTask.define_task(task_name, {args => prereqs}, &block)
+ task.sources = prereqs
+ task
+ end
+
+ # Make a list of sources from the list of file name extensions /
+ # translation procs.
+ def make_sources(task_name, extensions)
+ result = extensions.map { |ext|
+ case ext
+ when /%/
+ task_name.pathmap(ext)
+ when %r{/}
+ ext
+ when /^\./
+ task_name.ext(ext)
+ when String
+ ext
+ when Proc, Method
+ if ext.arity == 1
+ ext.call(task_name)
+ else
+ ext.call
+ end
+ else
+ fail "Don't know how to handle rule dependent: #{ext.inspect}"
+ end
+ }
+ result.flatten
+ end
+
+
+ private
+
+ # Return the current description, clearing it in the process.
+ def get_description(task)
+ desc = @last_description
+ @last_description = nil
+ desc
+ end
+
+ class << self
+ attr_accessor :record_task_metadata # :nodoc:
+ TaskManager.record_task_metadata = false
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/tasklib.rb b/ruby_2_2/lib/rake/tasklib.rb
new file mode 100644
index 0000000000..6203d9402b
--- /dev/null
+++ b/ruby_2_2/lib/rake/tasklib.rb
@@ -0,0 +1,24 @@
+require 'rake'
+
+module Rake
+
+ # Base class for Task Libraries.
+ class TaskLib
+ include Cloneable
+ include Rake::DSL
+
+ # Make a symbol by pasting two strings together.
+ #
+ # NOTE: DEPRECATED! This method is kinda stupid. I don't know why
+ # I didn't just use string interpolation. But now other task
+ # libraries depend on this so I can't remove it without breaking
+ # other people's code. So for now it stays for backwards
+ # compatibility. BUT DON'T USE IT.
+ #--
+ # TODO: Remove in Rake 11
+ def paste(a, b) # :nodoc:
+ (a.to_s + b.to_s).intern
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/testtask.rb b/ruby_2_2/lib/rake/testtask.rb
new file mode 100644
index 0000000000..2daa589634
--- /dev/null
+++ b/ruby_2_2/lib/rake/testtask.rb
@@ -0,0 +1,212 @@
+require 'rake'
+require 'rake/tasklib'
+
+module Rake
+
+ # Create a task that runs a set of tests.
+ #
+ # Example:
+ #
+ # Rake::TestTask.new do |t|
+ # t.libs << "test"
+ # t.test_files = FileList['test/test*.rb']
+ # t.verbose = true
+ # end
+ #
+ # If rake is invoked with a "TEST=filename" command line option,
+ # then the list of test files will be overridden to include only the
+ # filename specified on the command line. This provides an easy way
+ # to run just one test.
+ #
+ # If rake is invoked with a "TESTOPTS=options" command line option,
+ # then the given options are passed to the test process after a
+ # '--'. This allows Test::Unit options to be passed to the test
+ # suite.
+ #
+ # Examples:
+ #
+ # rake test # run tests normally
+ # rake test TEST=just_one_file.rb # run just one test file.
+ # rake test TESTOPTS="-v" # run in verbose mode
+ # rake test TESTOPTS="--runner=fox" # use the fox test runner
+ #
+ class TestTask < TaskLib
+
+ # Name of test task. (default is :test)
+ attr_accessor :name
+
+ # List of directories to added to $LOAD_PATH before running the
+ # tests. (default is 'lib')
+ attr_accessor :libs
+
+ # True if verbose test output desired. (default is false)
+ attr_accessor :verbose
+
+ # Test options passed to the test suite. An explicit
+ # TESTOPTS=opts on the command line will override this. (default
+ # is NONE)
+ attr_accessor :options
+
+ # Request that the tests be run with the warning flag set.
+ # E.g. warning=true implies "ruby -w" used to run the tests.
+ attr_accessor :warning
+
+ # Glob pattern to match test files. (default is 'test/test*.rb')
+ attr_accessor :pattern
+
+ # Style of test loader to use. Options are:
+ #
+ # * :rake -- Rake provided test loading script (default).
+ # * :testrb -- Ruby provided test loading script.
+ # * :direct -- Load tests using command line loader.
+ #
+ attr_accessor :loader
+
+ # Array of commandline options to pass to ruby when running test loader.
+ attr_accessor :ruby_opts
+
+ # Description of the test task. (default is 'Run tests')
+ attr_accessor :description
+
+ # Explicitly define the list of test files to be included in a
+ # test. +list+ is expected to be an array of file names (a
+ # FileList is acceptable). If both +pattern+ and +test_files+ are
+ # used, then the list of test files is the union of the two.
+ def test_files=(list)
+ @test_files = list
+ end
+
+ # Create a testing task.
+ def initialize(name=:test)
+ @name = name
+ @libs = ["lib"]
+ @pattern = nil
+ @options = nil
+ @test_files = nil
+ @verbose = false
+ @warning = false
+ @loader = :rake
+ @ruby_opts = []
+ @description = "Run tests" + (@name == :test ? "" : " for #{@name}")
+ yield self if block_given?
+ @pattern = 'test/test*.rb' if @pattern.nil? && @test_files.nil?
+ define
+ end
+
+ # Create the tasks defined by this task lib.
+ def define
+ desc @description
+ task @name do
+ FileUtilsExt.verbose(@verbose) do
+ args =
+ "#{ruby_opts_string} #{run_code} " +
+ "#{file_list_string} #{option_list}"
+ ruby args do |ok, status|
+ if !ok && status.respond_to?(:signaled?) && status.signaled?
+ raise SignalException.new(status.termsig)
+ elsif !ok
+ fail "Command failed with status (#{status.exitstatus}): " +
+ "[ruby #{args}]"
+ end
+ end
+ end
+ end
+ self
+ end
+
+ def option_list # :nodoc:
+ (ENV['TESTOPTS'] ||
+ ENV['TESTOPT'] ||
+ ENV['TEST_OPTS'] ||
+ ENV['TEST_OPT'] ||
+ @options ||
+ "")
+ end
+
+ def ruby_opts_string # :nodoc:
+ opts = @ruby_opts.dup
+ opts.unshift("-I\"#{lib_path}\"") unless @libs.empty?
+ opts.unshift("-w") if @warning
+ opts.join(" ")
+ end
+
+ def lib_path # :nodoc:
+ @libs.join(File::PATH_SEPARATOR)
+ end
+
+ def file_list_string # :nodoc:
+ file_list.map { |fn| "\"#{fn}\"" }.join(' ')
+ end
+
+ def file_list # :nodoc:
+ if ENV['TEST']
+ FileList[ENV['TEST']]
+ else
+ result = []
+ result += @test_files.to_a if @test_files
+ result << @pattern if @pattern
+ result
+ end
+ end
+
+ def fix # :nodoc:
+ case ruby_version
+ when '1.8.2'
+ "\"#{find_file 'rake/ruby182_test_unit_fix'}\""
+ else
+ nil
+ end || ''
+ end
+
+ def ruby_version # :nodoc:
+ RUBY_VERSION
+ end
+
+ def run_code # :nodoc:
+ case @loader
+ when :direct
+ "-e \"ARGV.each{|f| require f}\""
+ when :testrb
+ "-S testrb #{fix}"
+ when :rake
+ "#{rake_include_arg} \"#{rake_loader}\""
+ end
+ end
+
+ def rake_loader # :nodoc:
+ find_file('rake/rake_test_loader') or
+ fail "unable to find rake test loader"
+ end
+
+ def find_file(fn) # :nodoc:
+ $LOAD_PATH.each do |path|
+ file_path = File.join(path, "#{fn}.rb")
+ return file_path if File.exist? file_path
+ end
+ nil
+ end
+
+ def rake_include_arg # :nodoc:
+ spec = Gem.loaded_specs['rake']
+ if spec.respond_to?(:default_gem?) && spec.default_gem?
+ ""
+ else
+ "-I\"#{rake_lib_dir}\""
+ end
+ end
+
+ def rake_lib_dir # :nodoc:
+ find_dir('rake') or
+ fail "unable to find rake lib"
+ end
+
+ def find_dir(fn) # :nodoc:
+ $LOAD_PATH.each do |path|
+ file_path = File.join(path, "#{fn}.rb")
+ return path if File.exist? file_path
+ end
+ nil
+ end
+
+ end
+end
diff --git a/ruby_2_2/lib/rake/thread_history_display.rb b/ruby_2_2/lib/rake/thread_history_display.rb
new file mode 100644
index 0000000000..c2af9ecef5
--- /dev/null
+++ b/ruby_2_2/lib/rake/thread_history_display.rb
@@ -0,0 +1,48 @@
+require 'rake/private_reader'
+
+module Rake
+
+ class ThreadHistoryDisplay # :nodoc: all
+ include Rake::PrivateReader
+
+ private_reader :stats, :items, :threads
+
+ def initialize(stats)
+ @stats = stats
+ @items = { :_seq_ => 1 }
+ @threads = { :_seq_ => "A" }
+ end
+
+ def show
+ puts "Job History:"
+ stats.each do |stat|
+ stat[:data] ||= {}
+ rename(stat, :thread, threads)
+ rename(stat[:data], :item_id, items)
+ rename(stat[:data], :new_thread, threads)
+ rename(stat[:data], :deleted_thread, threads)
+ printf("%8d %2s %-20s %s\n",
+ (stat[:time] * 1_000_000).round,
+ stat[:thread],
+ stat[:event],
+ stat[:data].map do |k, v| "#{k}:#{v}" end.join(" "))
+ end
+ end
+
+ private
+
+ def rename(hash, key, renames)
+ if hash && hash[key]
+ original = hash[key]
+ value = renames[original]
+ unless value
+ value = renames[:_seq_]
+ renames[:_seq_] = renames[:_seq_].succ
+ renames[original] = value
+ end
+ hash[key] = value
+ end
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/thread_pool.rb b/ruby_2_2/lib/rake/thread_pool.rb
new file mode 100644
index 0000000000..d2ac6e7ac2
--- /dev/null
+++ b/ruby_2_2/lib/rake/thread_pool.rb
@@ -0,0 +1,164 @@
+require 'thread'
+require 'set'
+
+require 'rake/promise'
+
+module Rake
+
+ class ThreadPool # :nodoc: all
+
+ # Creates a ThreadPool object. The +thread_count+ parameter is the size
+ # of the pool.
+ def initialize(thread_count)
+ @max_active_threads = [thread_count, 0].max
+ @threads = Set.new
+ @threads_mon = Monitor.new
+ @queue = Queue.new
+ @join_cond = @threads_mon.new_cond
+
+ @history_start_time = nil
+ @history = []
+ @history_mon = Monitor.new
+ @total_threads_in_play = 0
+ end
+
+ # Creates a future executed by the +ThreadPool+.
+ #
+ # The args are passed to the block when executing (similarly to
+ # Thread#new) The return value is an object representing
+ # a future which has been created and added to the queue in the
+ # pool. Sending #value to the object will sleep the
+ # current thread until the future is finished and will return the
+ # result (or raise an exception thrown from the future)
+ def future(*args, &block)
+ promise = Promise.new(args, &block)
+ promise.recorder = lambda { |*stats| stat(*stats) }
+
+ @queue.enq promise
+ stat :queued, :item_id => promise.object_id
+ start_thread
+ promise
+ end
+
+ # Waits until the queue of futures is empty and all threads have exited.
+ def join
+ @threads_mon.synchronize do
+ begin
+ stat :joining
+ @join_cond.wait unless @threads.empty?
+ stat :joined
+ rescue Exception => e
+ stat :joined
+ $stderr.puts e
+ $stderr.print "Queue contains #{@queue.size} items. " +
+ "Thread pool contains #{@threads.count} threads\n"
+ $stderr.print "Current Thread #{Thread.current} status = " +
+ "#{Thread.current.status}\n"
+ $stderr.puts e.backtrace.join("\n")
+ @threads.each do |t|
+ $stderr.print "Thread #{t} status = #{t.status}\n"
+ # 1.8 doesn't support Thread#backtrace
+ $stderr.puts t.backtrace.join("\n") if t.respond_to? :backtrace
+ end
+ raise e
+ end
+ end
+ end
+
+ # Enable the gathering of history events.
+ def gather_history #:nodoc:
+ @history_start_time = Time.now if @history_start_time.nil?
+ end
+
+ # Return a array of history events for the thread pool.
+ #
+ # History gathering must be enabled to be able to see the events
+ # (see #gather_history). Best to call this when the job is
+ # complete (i.e. after ThreadPool#join is called).
+ def history # :nodoc:
+ @history_mon.synchronize { @history.dup }.
+ sort_by { |i| i[:time] }.
+ each { |i| i[:time] -= @history_start_time }
+ end
+
+ # Return a hash of always collected statistics for the thread pool.
+ def statistics # :nodoc:
+ {
+ :total_threads_in_play => @total_threads_in_play,
+ :max_active_threads => @max_active_threads,
+ }
+ end
+
+ private
+
+ # processes one item on the queue. Returns true if there was an
+ # item to process, false if there was no item
+ def process_queue_item #:nodoc:
+ return false if @queue.empty?
+
+ # Even though we just asked if the queue was empty, it
+ # still could have had an item which by this statement
+ # is now gone. For this reason we pass true to Queue#deq
+ # because we will sleep indefinitely if it is empty.
+ promise = @queue.deq(true)
+ stat :dequeued, :item_id => promise.object_id
+ promise.work
+ return true
+
+ rescue ThreadError # this means the queue is empty
+ false
+ end
+
+ def safe_thread_count
+ @threads_mon.synchronize do
+ @threads.count
+ end
+ end
+
+ def start_thread # :nodoc:
+ @threads_mon.synchronize do
+ next unless @threads.count < @max_active_threads
+
+ t = Thread.new do
+ begin
+ while safe_thread_count <= @max_active_threads
+ break unless process_queue_item
+ end
+ ensure
+ @threads_mon.synchronize do
+ @threads.delete Thread.current
+ stat :ended, :thread_count => @threads.count
+ @join_cond.broadcast if @threads.empty?
+ end
+ end
+ end
+
+ @threads << t
+ stat(
+ :spawned,
+ :new_thread => t.object_id,
+ :thread_count => @threads.count)
+ @total_threads_in_play = @threads.count if
+ @threads.count > @total_threads_in_play
+ end
+ end
+
+ def stat(event, data=nil) # :nodoc:
+ return if @history_start_time.nil?
+ info = {
+ :event => event,
+ :data => data,
+ :time => Time.now,
+ :thread => Thread.current.object_id,
+ }
+ @history_mon.synchronize { @history << info }
+ end
+
+ # for testing only
+
+ def __queue__ # :nodoc:
+ @queue
+ end
+ end
+
+end
diff --git a/ruby_2_2/lib/rake/trace_output.rb b/ruby_2_2/lib/rake/trace_output.rb
new file mode 100644
index 0000000000..396096d4df
--- /dev/null
+++ b/ruby_2_2/lib/rake/trace_output.rb
@@ -0,0 +1,22 @@
+module Rake
+ module TraceOutput # :nodoc: all
+
+ # Write trace output to output stream +out+.
+ #
+ # The write is done as a single IO call (to print) to lessen the
+ # chance that the trace output is interrupted by other tasks also
+ # producing output.
+ def trace_on(out, *strings)
+ sep = $\ || "\n"
+ if strings.empty?
+ output = sep
+ else
+ output = strings.map { |s|
+ next if s.nil?
+ s =~ /#{sep}$/ ? s : s + sep
+ }.join
+ end
+ out.print(output)
+ end
+ end
+end
diff --git a/ruby_2_2/lib/rake/version.rb b/ruby_2_2/lib/rake/version.rb
new file mode 100644
index 0000000000..b9b1b2d485
--- /dev/null
+++ b/ruby_2_2/lib/rake/version.rb
@@ -0,0 +1,7 @@
+module Rake
+ module Version # :nodoc: all
+ MAJOR, MINOR, BUILD, *OTHER = Rake::VERSION.split '.'
+
+ NUMBERS = [MAJOR, MINOR, BUILD, *OTHER]
+ end
+end
diff --git a/ruby_2_2/lib/rake/win32.rb b/ruby_2_2/lib/rake/win32.rb
new file mode 100644
index 0000000000..6b4873da2c
--- /dev/null
+++ b/ruby_2_2/lib/rake/win32.rb
@@ -0,0 +1,56 @@
+
+module Rake
+ require 'rake/alt_system'
+
+ # Win 32 interface methods for Rake. Windows specific functionality
+ # will be placed here to collect that knowledge in one spot.
+ module Win32 # :nodoc: all
+
+ # Error indicating a problem in locating the home directory on a
+ # Win32 system.
+ class Win32HomeError < RuntimeError
+ end
+
+ class << self
+ # True if running on a windows system.
+ def windows?
+ AltSystem::WINDOWS
+ end
+
+ # Run a command line on windows.
+ def rake_system(*cmd)
+ AltSystem.system(*cmd)
+ end
+
+ # The standard directory containing system wide rake files on
+ # Win 32 systems. Try the following environment variables (in
+ # order):
+ #
+ # * HOME
+ # * HOMEDRIVE + HOMEPATH
+ # * APPDATA
+ # * USERPROFILE
+ #
+ # If the above are not defined, the return nil.
+ def win32_system_dir #:nodoc:
+ win32_shared_path = ENV['HOME']
+ if win32_shared_path.nil? && ENV['HOMEDRIVE'] && ENV['HOMEPATH']
+ win32_shared_path = ENV['HOMEDRIVE'] + ENV['HOMEPATH']
+ end
+
+ win32_shared_path ||= ENV['APPDATA']
+ win32_shared_path ||= ENV['USERPROFILE']
+ raise Win32HomeError,
+ "Unable to determine home path environment variable." if
+ win32_shared_path.nil? or win32_shared_path.empty?
+ normalize(File.join(win32_shared_path, 'Rake'))
+ end
+
+ # Normalize a win32 path so that the slashes are all forward slashes.
+ def normalize(path)
+ path.gsub(/\\/, '/')
+ end
+
+ end
+ end
+end