From 25b73ebd8ff96b36b964e90d66a387afa7959a00 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 29 Nov 2018 21:51:30 -0500 Subject: [PATCH] move logic to find an executable from ConfigureOp to Util --- lib/rscons/configure_op.rb | 47 ++------------------------------ lib/rscons/util.rb | 50 ++++++++++++++++++++++++++++++++++ spec/rscons/util_spec.rb | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 45 deletions(-) diff --git a/lib/rscons/configure_op.rb b/lib/rscons/configure_op.rb index 2dc1e35..05de79d 100644 --- a/lib/rscons/configure_op.rb +++ b/lib/rscons/configure_op.rb @@ -184,22 +184,8 @@ module Rscons # Check for a executable program. def check_program(program, options = {}) Ansi.write($stdout, "Checking for program '", :cyan, program, :reset, "'... ") - found = false - if program["/"] or program["\\"] - if File.file?(program) and File.executable?(program) - found = true - success_message = program - end - else - path_entries = ENV["PATH"].split(File::PATH_SEPARATOR) - path_entries.find do |path_entry| - if path = test_path_for_executable(path_entry, program) - found = true - success_message = path - end - end - end - common_config_checks(found ? 0 : 1, options.merge(success_message: success_message)) + path = Util.find_executable(program) + common_config_checks(path ? 0 : 1, options.merge(success_message: path)) end private @@ -401,34 +387,5 @@ module Rscons end end - # Check if a directory contains a certain executable. - # - # @param path_entry [String] - # Directory to look in. - # @param executable [String] - # Executable to look for. - def test_path_for_executable(path_entry, executable) - is_executable = lambda do |path| - File.file?(path) and File.executable?(path) - end - if RbConfig::CONFIG["host_os"] =~ /mswin|windows|mingw/i - executable = executable.downcase - dir_entries = Dir.entries(path_entry) - dir_entries.find do |entry| - path = "#{path_entry}/#{entry}" - entry = entry.downcase - if ((entry == executable) or - (entry == "#{executable}.exe") or - (entry == "#{executable}.com") or - (entry == "#{executable}.bat")) and is_executable[path] - return path - end - end - else - path = "#{path_entry}/#{executable}" - return path if is_executable[path] - end - end - end end diff --git a/lib/rscons/util.rb b/lib/rscons/util.rb index a5c4762..3326b5d 100644 --- a/lib/rscons/util.rb +++ b/lib/rscons/util.rb @@ -34,6 +34,56 @@ module Rscons end end + # Look for an executable. + # + # @return [String, nil] + # Executable path, if found. + def find_executable(name) + if name["/"] or name["\\"] + if File.file?(name) and File.executable?(name) + return name + end + else + path_entries = ENV["PATH"].split(File::PATH_SEPARATOR) + path_entries.find do |path_entry| + if path = test_path_for_executable(path_entry, name) + return path + end + end + end + end + + private + + # Check if a directory contains a certain executable. + # + # @param path_entry [String] + # Directory to look in. + # @param executable [String] + # Executable to look for. + def test_path_for_executable(path_entry, executable) + is_executable = lambda do |path| + File.file?(path) and File.executable?(path) + end + if RbConfig::CONFIG["host_os"] =~ /mswin|windows|mingw/i + executable = executable.downcase + dir_entries = Dir.entries(path_entry) + dir_entries.find do |entry| + path = "#{path_entry}/#{entry}" + entry = entry.downcase + if ((entry == executable) or + (entry == "#{executable}.exe") or + (entry == "#{executable}.com") or + (entry == "#{executable}.bat")) and is_executable[path] + return path + end + end + else + path = "#{path_entry}/#{executable}" + return path if is_executable[path] + end + end + end end end diff --git a/spec/rscons/util_spec.rb b/spec/rscons/util_spec.rb index 04495a0..1c56aa5 100644 --- a/spec/rscons/util_spec.rb +++ b/spec/rscons/util_spec.rb @@ -55,5 +55,61 @@ module Rscons end end + describe ".find_executable" do + context "when given a path with directory components" do + it "returns the path if it is executable" do + expect(File).to receive(:file?).with("a/path").and_return(true) + expect(File).to receive(:executable?).with("a/path").and_return(true) + expect(Util.find_executable("a/path")).to eq "a/path" + end + + it "returns nil if the path is not executable" do + expect(File).to receive(:file?).with("a/path").and_return(true) + expect(File).to receive(:executable?).with("a/path").and_return(false) + expect(Util.find_executable("a/path")).to be_nil + end + end + + context "when given a program name without directory components" do + context "on Windows" do + before(:each) do + stub_const("File::PATH_SEPARATOR", ";") + stub_const("RbConfig::CONFIG", "host_os" => "mingw") + expect(ENV).to receive(:[]).with("PATH").and_return("C:\\bin;C:\\Windows") + allow(Dir).to receive(:entries).with("C:\\bin").and_return(%w[one.com]) + allow(Dir).to receive(:entries).with("C:\\Windows").and_return(%w[two.exe Three.bat]) + end + + it "returns a path to a .exe found" do + expect(File).to receive(:file?).with("C:\\Windows/two.exe").and_return(true) + expect(File).to receive(:executable?).with("C:\\Windows/two.exe").and_return(true) + expect(Util.find_executable("two")).to eq "C:\\Windows/two.exe" + end + + it "returns a path to a .exe found including extension" do + expect(File).to receive(:file?).with("C:\\Windows/two.exe").and_return(true) + expect(File).to receive(:executable?).with("C:\\Windows/two.exe").and_return(true) + expect(Util.find_executable("TWO.EXE")).to eq "C:\\Windows/two.exe" + end + + it "returns a path to a .com found" do + expect(File).to receive(:file?).with("C:\\bin/one.com").and_return(true) + expect(File).to receive(:executable?).with("C:\\bin/one.com").and_return(true) + expect(Util.find_executable("ONE")).to eq "C:\\bin/one.com" + end + + it "returns a path to a .bat found" do + expect(File).to receive(:file?).with("C:\\Windows/Three.bat").and_return(true) + expect(File).to receive(:executable?).with("C:\\Windows/Three.bat").and_return(true) + expect(Util.find_executable("three")).to eq "C:\\Windows/Three.bat" + end + + it "returns nil when nothing is found" do + expect(Util.find_executable("notthere")).to be_nil + end + end + end + end + end end