Skip to content

Commit f34546f

Browse files
jonathanhefnerhsbt
authored andcommitted
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 e45cfc0 commit f34546f

File tree

2 files changed

+51
-39
lines changed

2 files changed

+51
-39
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
@@ -676,45 +669,37 @@ def rake_require(file_name, paths=$LOAD_PATH, loaded=$") # :nodoc:
676669
end
677670

678671
def find_rakefile_location # :nodoc:
679-
here = Dir.pwd
680-
until (fn = have_rakefile)
681-
Dir.chdir("..")
682-
return nil if Dir.pwd == here || options.nosearch
683-
here = Dir.pwd
672+
previous_dir, current_dir = nil, original_dir
673+
until (rakefile = have_rakefile(current_dir)) || current_dir == previous_dir
674+
break if options.nosearch
675+
previous_dir, current_dir = current_dir, File.expand_path("..", current_dir)
684676
end
685-
[fn, here]
686-
ensure
687-
Dir.chdir(Rake.original_dir)
677+
[rakefile, current_dir] if rakefile
688678
end
689679

690-
def print_rakefile_directory(location) # :nodoc:
691-
$stderr.puts "(in #{Dir.pwd})" unless
692-
options.silent or original_dir == location
680+
def print_rakefile_directory # :nodoc:
681+
$stderr.puts "(in #{@rakefile_dir})" unless
682+
options.silent || original_dir == @rakefile_dir
693683
end
694684

695685
def raw_load_rakefile # :nodoc:
696-
rakefile, location = find_rakefile_location
686+
@rakefile, @rakefile_dir = find_rakefile_location
687+
697688
if (!options.ignore_system) &&
698-
(options.load_system || rakefile.nil?) &&
689+
(options.load_system || @rakefile.nil?) &&
699690
system_dir && File.directory?(system_dir)
700-
print_rakefile_directory(location)
701-
glob("#{system_dir}/*.rake") do |name|
702-
add_import name
703-
end
691+
print_rakefile_directory
692+
add_globbed_imports(system_dir, "*.rake")
704693
else
705-
fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if
706-
rakefile.nil?
707-
@rakefile = rakefile
708-
Dir.chdir(location)
709-
print_rakefile_directory(location)
710-
Rake.load_rakefile(File.expand_path(@rakefile)) if
711-
@rakefile && @rakefile != ""
712-
options.rakelib.each do |rlib|
713-
glob("#{rlib}/*.rake") do |name|
714-
add_import name
715-
end
694+
fail "No Rakefile found (looking for: #{@rakefiles.join(", ")})" if @rakefile.nil?
695+
Dir.chdir(@rakefile_dir) unless @rakefile_dir == Dir.pwd
696+
print_rakefile_directory
697+
Rake.load_rakefile(File.expand_path(@rakefile, @rakefile_dir)) unless @rakefile.empty?
698+
options.rakelib.each do |rakelib|
699+
add_globbed_imports(File.expand_path(rakelib, @rakefile_dir), "*.rake")
716700
end
717701
end
702+
718703
load_imports
719704
end
720705

@@ -723,6 +708,11 @@ def glob(path, &block) # :nodoc:
723708
end
724709
private :glob
725710

711+
def escape_for_glob(pattern)
712+
pattern.tr("\\", "/").gsub(/[*?\[\]{}]/, "\\\\" + '\0')
713+
end
714+
private :escape_for_glob
715+
726716
# The directory path containing the system wide rakefiles.
727717
def system_dir # :nodoc:
728718
@system_dir ||=
@@ -778,6 +768,14 @@ def add_import(fn) # :nodoc:
778768
@pending_imports << fn
779769
end
780770

771+
# Globs "#{directory}/#{pattern}", and adds the results to the list
772+
# of files to be imported.
773+
def add_globbed_imports(directory, pattern) # :nodoc:
774+
Dir.glob("#{escape_for_glob(directory).chomp("/")}/#{pattern}") do |path|
775+
add_import path
776+
end
777+
end
778+
781779
# Load the pending list of imported files.
782780
def load_imports # :nodoc:
783781
while fn = @pending_imports.shift

test/test_rake_application.rb

+14
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 []
@@ -439,6 +440,19 @@ def test_good_run
439440
assert_equal "DEFAULT\n", out
440441
end
441442

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

0 commit comments

Comments
 (0)