Support pwsh executable name for powershell

This updates the powershell detection to look for the `pwsh` executable
    and use it when the powershell executable is not available.
This commit is contained in:
Chris Roberts 2021-04-28 12:44:06 -07:00
parent da0a2bff53
commit 5967a23fa0
2 changed files with 60 additions and 41 deletions

View File

@ -14,28 +14,44 @@ module Vagrant
MINIMUM_REQUIRED_VERSION = 3
# Number of seconds to wait while attempting to get powershell version
DEFAULT_VERSION_DETECTION_TIMEOUT = 30
# Names of the powershell executable
POWERSHELL_NAMES = ["powershell", "pwsh"].map(&:freeze).freeze
# Paths to powershell executable
POWERSHELL_PATHS = [
"%WINDIR%/WindowsPowerShell/v1.0",
"%PROGRAMFILES%/PowerShell/7",
"%PROGRAMFILES%/PowerShell/6"
].map(&:freeze).freeze
LOGGER = Log4r::Logger.new("vagrant::util::powershell")
# @return [String|nil] a powershell executable, depending on environment
def self.executable
if !defined?(@_powershell_executable)
@_powershell_executable = "powershell"
# First start with detecting executable on configured path
POWERSHELL_NAMES.detect do |psh|
return @_powershell_executable = psh if Which.which(psh)
psh += ".exe"
return @_powershell_executable = psh if Which.which(psh)
end
if Which.which(@_powershell_executable).nil?
# Try to use WSL interoperability if PowerShell is not symlinked to
# the container.
if Platform.wsl?
@_powershell_executable += ".exe"
# Now attempt with paths
paths = POWERSHELL_PATHS.map do |ppath|
result = Util::Subprocess.execute("cmd.exe", "/c", "echo #{ppath}")
result.stdout.gsub("\"", "").strip if result.exit_code == 0
end.compact
if Which.which(@_powershell_executable).nil?
@_powershell_executable = "/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe"
paths.each do |psh_path|
POWERSHELL_NAMES.each do |psh|
path = File.join(psh_path, psh)
return @_powershell_executable = path if Which.which(path)
if Which.which(@_powershell_executable).nil?
@_powershell_executable = nil
end
end
else
@_powershell_executable = nil
path += ".exe"
return @_powershell_executable = path if Which.which(path)
# Finally test the msys2 style path
path = path.sub(/^([A-Za-z]):/, "/mnt/\\1")
return @_powershell_executable = path if Which.which(path)
end
end
end

View File

@ -45,47 +45,50 @@ describe Vagrant::Util::PowerShell do
end
describe ".executable" do
before{ allow(Vagrant::Util::Platform).to receive(:wsl?).and_return(false) }
before do
allow(Vagrant::Util::Which).to receive(:which).and_return(nil)
allow(Vagrant::Util::Subprocess).to receive(:execute) do |*args|
Vagrant::Util::Subprocess::Result.new(0, args.last.sub("echo ", ""), "")
end
end
context "when found in PATH" do
before{ expect(Vagrant::Util::Which).to receive(:which).with("powershell").and_return(true) }
context "when powershell found in PATH" do
before{ expect(Vagrant::Util::Which).to receive(:which).
with("powershell").and_return(true) }
it "should return powershell string" do
expect(described_class.executable).to eq("powershell")
end
end
context "when not found in PATH" do
before{ expect(Vagrant::Util::Which).to receive(:which).with("powershell").and_return(nil) }
context "when pwsh found in PATH" do
before { expect(Vagrant::Util::Which).to receive(:which).
with("pwsh").and_return(true) }
it "should return pwsh string" do
expect(described_class.executable).to eq("pwsh")
end
end
context "when not found in PATH" do
it "should return nil" do
expect(described_class.executable).to be_nil
end
context "when within WSL" do
before do
allow(Vagrant::Util::Which).to receive(:which).with(/powershell/).and_return(nil)
expect(Vagrant::Util::Platform).to receive(:wsl?).and_return(true)
end
it "should check PATH with .exe extension" do
expect(Vagrant::Util::Which).to receive(:which).with("powershell.exe")
described_class.executable
end
it "should check PATH with .exe extension" do
expect(Vagrant::Util::Which).to receive(:which).with("powershell.exe")
described_class.executable
end
it "should return powershell.exe when found" do
expect(Vagrant::Util::Which).to receive(:which).
with("powershell.exe").and_return(true)
expect(described_class.executable).to eq("powershell.exe")
end
it "should return powershell.exe when found" do
expect(Vagrant::Util::Which).to receive(:which).with("powershell.exe").and_return(true)
expect(described_class.executable).to eq("powershell.exe")
end
it "should return nil when not found" do
expect(described_class.executable).to be_nil
end
it "should check for powershell with full path" do
expect(Vagrant::Util::Which).to receive(:which).with(/Windows\/System32.+powershell.exe/)
described_class.executable
end
it "should check for powershell with full path" do
expect(Vagrant::Util::Which).to receive(:which).with(/WindowsPowerShell\/v1.0\/powershell.exe/)
described_class.executable
end
end
end