Skip to content

Commit 20a2140

Browse files
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.
1 parent c2eeae2 commit 20a2140

File tree

2 files changed

+51
-40
lines changed

2 files changed

+51
-40
lines changed

lib/rake/application.rb

+37-39
Original file line numberDiff line numberDiff line change
@@ -269,18 +269,11 @@ def has_chain?(exception) # :nodoc:
269269
end
270270
private :has_chain?
271271

272-
# True if one of the files in RAKEFILES is in the current directory.
273-
# If a match is found, it is copied into @rakefile.
274-
def have_rakefile # :nodoc:
275-
@rakefiles.each do |fn|
276-
if File.exist?(fn)
277-
others = FileList.glob(fn, File::FNM_CASEFOLD)
278-
return others.size == 1 ? others.first : fn
279-
elsif fn == ""
280-
return fn
281-
end
272+
# Returns first filename from @rakefiles that exists in the specified dir.
273+
def have_rakefile(dir = Dir.pwd) # :nodoc:
274+
Dir.chdir(dir) do
275+
Dir.glob(@rakefiles.map { |name| escape_for_glob(name) }).first || @rakefiles.find(&:empty?)
282276
end
283-
return nil
284277
end
285278

286279
# True if we are outputting to TTY, false otherwise
@@ -669,45 +662,37 @@ def rake_require(file_name, paths=$LOAD_PATH, loaded=$") # :nodoc:
669662
end
670663

671664
def find_rakefile_location # :nodoc:
672-
here = Dir.pwd
673-
until (fn = have_rakefile)
674-
Dir.chdir("..")
675-
return nil if Dir.pwd == here || options.nosearch
676-
here = Dir.pwd
665+
previous_dir, current_dir = nil, original_dir
666+
until (rakefile = have_rakefile(current_dir)) || current_dir == previous_dir
667+
break if options.nosearch
668+
previous_dir, current_dir = current_dir, File.expand_path("..", current_dir)
677669
end
678-
[fn, here]
679-
ensure
680-
Dir.chdir(Rake.original_dir)
670+
[rakefile, current_dir] if rakefile
681671
end
682672

683-
def print_rakefile_directory(location) # :nodoc:
684-
$stderr.puts "(in #{Dir.pwd})" unless
685-
options.silent or original_dir == location
673+
def print_rakefile_directory # :nodoc:
674+
$stderr.puts "(in #{@rakefile_dir})" unless
675+
options.silent || original_dir == @rakefile_dir
686676
end
687677

688678
def raw_load_rakefile # :nodoc:
689-
rakefile, location = find_rakefile_location
679+
@rakefile, @rakefile_dir = find_rakefile_location
680+
690681
if (!options.ignore_system) &&
691-
(options.load_system || rakefile.nil?) &&
682+
(options.load_system || @rakefile.nil?) &&
692683
system_dir && File.directory?(system_dir)
693-
print_rakefile_directory(location)
694-
glob("#{system_dir}/*.rake") do |name|
695-
add_import name
696-
end
684+
print_rakefile_directory
685+
add_globbed_imports(system_dir, "*.rake")
697686
else
698-
fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if
699-
rakefile.nil?
700-
@rakefile = rakefile
701-
Dir.chdir(location)
702-
print_rakefile_directory(location)
703-
Rake.load_rakefile(File.expand_path(@rakefile)) if
704-
@rakefile && @rakefile != ""
705-
options.rakelib.each do |rlib|
706-
glob("#{rlib}/*.rake") do |name|
707-
add_import name
708-
end
687+
fail "No Rakefile found (looking for: #{@rakefiles.join(", ")})" if @rakefile.nil?
688+
Dir.chdir(@rakefile_dir) unless @rakefile_dir == Dir.pwd
689+
print_rakefile_directory
690+
Rake.load_rakefile(File.expand_path(@rakefile, @rakefile_dir)) unless @rakefile.empty?
691+
options.rakelib.each do |rakelib|
692+
add_globbed_imports(File.expand_path(rakelib, @rakefile_dir), "*.rake")
709693
end
710694
end
695+
711696
load_imports
712697
end
713698

@@ -716,6 +701,11 @@ def glob(path, &block) # :nodoc:
716701
end
717702
private :glob
718703

704+
def escape_for_glob(pattern)
705+
pattern.tr("\\", "/").gsub(/[*?\[\]{}]/, "\\\\" + '\0')
706+
end
707+
private :escape_for_glob
708+
719709
# The directory path containing the system wide rakefiles.
720710
def system_dir # :nodoc:
721711
@system_dir ||=
@@ -771,6 +761,14 @@ def add_import(fn) # :nodoc:
771761
@pending_imports << fn
772762
end
773763

764+
# Globs "#{directory}/#{pattern}", and adds the results to the list
765+
# of files to be imported.
766+
def add_globbed_imports(directory, pattern) # :nodoc:
767+
Dir.glob("#{escape_for_glob(directory).chomp("/")}/#{pattern}") do |path|
768+
add_import path
769+
end
770+
end
771+
774772
# Load the pending list of imported files.
775773
def load_imports # :nodoc:
776774
while fn = @pending_imports.shift

test/test_rake_application.rb

+14-1
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ def test_load_rakefile_doesnt_print_rakefile_directory_from_same_dir
240240
def test_load_rakefile_from_subdir
241241
rakefile_unittest
242242
Dir.chdir "subdir"
243+
@app = Rake::Application.new
243244

244245
@app.instance_eval do
245246
handle_options []
@@ -248,7 +249,6 @@ def test_load_rakefile_from_subdir
248249
end
249250

250251
assert_equal "rakefile", @app.rakefile.downcase
251-
assert_equal @tempdir, Dir.pwd
252252
end
253253

254254
def test_load_rakefile_prints_rakefile_directory_from_subdir
@@ -439,6 +439,19 @@ def test_good_run
439439
assert_equal "DEFAULT\n", out
440440
end
441441

442+
def test_runs_in_rakefile_directory_from_subdir
443+
rakefile_unittest
444+
Dir.chdir "subdir"
445+
@app = Rake::Application.new
446+
447+
pwd = nil
448+
@app.define_task(Rake::Task, "default") { pwd = Dir.pwd }
449+
450+
@app.run %w[--silent]
451+
452+
assert_equal @tempdir, pwd
453+
end
454+
442455
def test_display_task_run
443456
ran = false
444457
@app.last_description = "COMMENT"

0 commit comments

Comments
 (0)