From 856409fcbe3568b071fdb9162b9e78bb2c5ad2a9 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Sat, 17 Oct 2020 12:22:41 -0500 Subject: [PATCH] Limit calls to Dir.chdir in Rake::Application This reduces "conflicting chdir during another chdir block" warnings when calling `Rake::Application#run` inside a `Dir.chdir` block. --- lib/rake/application.rb | 76 +++++++++++++++++------------------ test/test_rake_application.rb | 14 +++++++ 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/lib/rake/application.rb b/lib/rake/application.rb index 9ac9b2130..3a6500a35 100644 --- a/lib/rake/application.rb +++ b/lib/rake/application.rb @@ -269,18 +269,11 @@ def has_chain?(exception) # :nodoc: 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 + # Returns first filename from @rakefiles that exists in the specified dir. + def have_rakefile(dir = Dir.pwd) # :nodoc: + Dir.chdir(dir) do + Dir.glob(@rakefiles.map { |name| escape_for_glob(name) }).first || @rakefiles.find(&:empty?) end - return nil end # True if we are outputting to TTY, false otherwise @@ -669,45 +662,37 @@ def rake_require(file_name, paths=$LOAD_PATH, loaded=$") # :nodoc: 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 + previous_dir, current_dir = nil, original_dir + until (rakefile = have_rakefile(current_dir)) || current_dir == previous_dir + break if options.nosearch + previous_dir, current_dir = current_dir, File.expand_path("..", current_dir) end - [fn, here] - ensure - Dir.chdir(Rake.original_dir) + [rakefile, current_dir] if rakefile end - def print_rakefile_directory(location) # :nodoc: - $stderr.puts "(in #{Dir.pwd})" unless - options.silent or original_dir == location + def print_rakefile_directory # :nodoc: + $stderr.puts "(in #{@rakefile_dir})" unless + options.silent || original_dir == @rakefile_dir end def raw_load_rakefile # :nodoc: - rakefile, location = find_rakefile_location + @rakefile, @rakefile_dir = find_rakefile_location + if (!options.ignore_system) && - (options.load_system || rakefile.nil?) && + (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 + print_rakefile_directory + add_globbed_imports(system_dir, "*.rake") 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 + fail "No Rakefile found (looking for: #{@rakefiles.join(", ")})" if @rakefile.nil? + Dir.chdir(@rakefile_dir) unless @rakefile_dir == Dir.pwd + print_rakefile_directory + Rake.load_rakefile(File.expand_path(@rakefile, @rakefile_dir)) unless @rakefile.empty? + options.rakelib.each do |rakelib| + add_globbed_imports(File.expand_path(rakelib, @rakefile_dir), "*.rake") end end + load_imports end @@ -716,6 +701,11 @@ def glob(path, &block) # :nodoc: end private :glob + def escape_for_glob(pattern) + pattern.tr("\\", "/").gsub(/[*?\[\]{}]/, "\\\\" + '\0') + end + private :escape_for_glob + # The directory path containing the system wide rakefiles. def system_dir # :nodoc: @system_dir ||= @@ -771,6 +761,14 @@ def add_import(fn) # :nodoc: @pending_imports << fn end + # Globs "#{directory}/#{pattern}", and adds the results to the list + # of files to be imported. + def add_globbed_imports(directory, pattern) # :nodoc: + Dir.glob("#{escape_for_glob(directory).chomp("/")}/#{pattern}") do |path| + add_import path + end + end + # Load the pending list of imported files. def load_imports # :nodoc: while fn = @pending_imports.shift diff --git a/test/test_rake_application.rb b/test/test_rake_application.rb index 8514da354..eee09c8a6 100644 --- a/test/test_rake_application.rb +++ b/test/test_rake_application.rb @@ -240,6 +240,7 @@ def test_load_rakefile_doesnt_print_rakefile_directory_from_same_dir def test_load_rakefile_from_subdir rakefile_unittest Dir.chdir "subdir" + @app = Rake::Application.new @app.instance_eval do handle_options [] @@ -439,6 +440,19 @@ def test_good_run assert_equal "DEFAULT\n", out end + def test_runs_in_rakefile_directory_from_subdir + rakefile_unittest + Dir.chdir "subdir" + @app = Rake::Application.new + + pwd = nil + @app.define_task(Rake::Task, "default") { pwd = Dir.pwd } + + @app.run %w[--silent] + + assert_equal @tempdir, pwd + end + def test_display_task_run ran = false @app.last_description = "COMMENT"