Merge pull request #8915 from briancain/6656/master/format-windows-paths-for-ssh-config

Format windows paths for ssh_config command
This commit is contained in:
Brian Cain 2017-08-25 16:20:32 -07:00 committed by GitHub
commit dbc23fccab
4 changed files with 142 additions and 17 deletions

View File

@ -4,6 +4,7 @@ require "tmpdir"
require "vagrant/util/subprocess"
require "vagrant/util/powershell"
require "vagrant/util/which"
module Vagrant
module Util
@ -19,6 +20,15 @@ module Vagrant
@_cygwin
end
def msys?
if !defined?(@_msys)
@_msys = ENV["VAGRANT_DETECTED_OS"].to_s.downcase.include?("msys") ||
platform.include?("msys") ||
ENV["OSTYPE"].to_s.downcase.include?("msys")
end
@_msys
end
def wsl?
if !defined?(@_wsl)
@_wsl = false
@ -93,25 +103,36 @@ module Vagrant
# @param [String] path
# @return [String]
def cygwin_path(path)
if cygwin?
begin
# First try the real cygpath
process = Subprocess.execute("cygpath", "-u", "-a", path.to_s)
return process.stdout.chomp
rescue Errors::CommandUnavailableWindows
end
begin
# We have to revert to the old env
# path here, otherwise it looks like
# msys2 ends up using the wrong cygpath
# binary and ends up with a `/cygdrive`
# when it doesn't exist in msys2
original_path_env = ENV['PATH']
ENV['PATH'] = ENV['VAGRANT_OLD_ENV_PATH']
cygpath = Vagrant::Util::Which.which("cygpath")
cygpath.gsub!("/", '\\')
process = Subprocess.execute(
cygpath, "-u", "-a", path.to_s)
return process.stdout.chomp
rescue Errors::CommandUnavailableWindows => e
# Sometimes cygpath isn't available (msys). Instead, do what we
# can with bash tricks.
process = Subprocess.execute(
"bash",
"--noprofile",
"--norc",
"-c", "cd #{Shellwords.escape(path)} && pwd")
return process.stdout.chomp
ensure
ENV['PATH'] = original_path_env
end
# Sometimes cygpath isn't available (msys). Instead, do what we
# can with bash tricks.
process = Subprocess.execute(
"bash",
"--noprofile",
"--norc",
"-c", "cd #{Shellwords.escape(path)} && pwd")
return process.stdout.chomp
end
# Identical to cygwin_path for now
alias_method :msys_path, :cygwin_path
# This takes any path and converts it to a full-length Windows
# path on Windows machines in Cygwin.
#
@ -264,6 +285,23 @@ module Vagrant
end
end
# Takes a windows path and formats it to the
# 'unix' style (i.e. `/cygdrive/c` or `/c/`)
#
# @param [Pathname, String] path Path to convert
# @param [Hash] hash of arguments
# @return [String]
def format_windows_path(path, *args)
path = cygwin_path(path) if cygwin?
path = msys_path(path) if msys?
path = wsl_to_windows_path(path) if wsl?
if windows? || wsl?
path = windows_unc_path(path) if !args.include?(:disable_unc)
end
path
end
# Automatically convert a given path to a Windows path. Will only
# be applied if running on a Windows host. If running on Windows
# host within the WSL, the actual Windows path will be returned.

View File

@ -1,6 +1,7 @@
require 'optparse'
require "vagrant/util/safe_puts"
require "vagrant/util/platform"
module VagrantPlugins
module CommandSSHConfig
@ -11,6 +12,10 @@ module VagrantPlugins
"outputs OpenSSH valid configuration to connect to the machine"
end
def convert_win_paths(paths)
paths.map! { |path| Vagrant::Util::Platform.format_windows_path(path, :disable_unc) }
end
def execute
options = {}
@ -32,6 +37,10 @@ module VagrantPlugins
ssh_info = machine.ssh_info
raise Vagrant::Errors::SSHNotReady if ssh_info.nil?
if Vagrant::Util::Platform.windows?
ssh_info[:private_key_path] = convert_win_paths(ssh_info[:private_key_path])
end
variables = {
host_key: options[:host] || machine.name || "vagrant",
ssh_host: ssh_info[:host],

View File

@ -24,7 +24,7 @@ describe VagrantPlugins::CommandSSHConfig::Command do
username: "testuser",
keys_only: true,
paranoid: false,
private_key_path: [],
private_key_path: ["/home/vagrant/.private/keys.key"],
forward_agent: false,
forward_x11: false
}}
@ -53,6 +53,7 @@ Host #{machine.name}
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /home/vagrant/.private/keys.key
IdentitiesOnly yes
LogLevel FATAL
SSHCONFIG
@ -136,5 +137,19 @@ Host #{machine.name}
expect(output).not_to include('StrictHostKeyChecking ')
expect(output).not_to include('UserKnownHostsFile ')
end
it "formats windows paths if windows" do
allow(machine).to receive(:ssh_info) { ssh_info.merge(private_key_path: ["C:\\path\\to\\vagrant\\home.key"]) }
allow(Vagrant::Util::Platform).to receive(:format_windows_path).and_return("/home/vagrant/home.key")
allow(Vagrant::Util::Platform).to receive(:windows?).and_return(true)
output = ""
allow(subject).to receive(:safe_puts) do |data|
output += data if data
end
subject.execute
expect(output).to include('IdentityFile /home/vagrant/home.key')
end
end
end

View File

@ -5,8 +5,27 @@ require "vagrant/util/platform"
describe Vagrant::Util::Platform do
include_context "unit"
subject { described_class }
describe "#cygwin_path" do
let(:path) { "C:\\msys2\\home\\vagrant" }
let(:updated_path) { "/home/vagrant" }
let(:subprocess_result) do
double("subprocess_result").tap do |result|
allow(result).to receive(:exit_code).and_return(0)
allow(result).to receive(:stdout).and_return(updated_path)
end
end
it "takes a windows path and returns a formatted path" do
allow(Vagrant::Util::Which).to receive(:which).and_return("C:/msys2/cygpath")
allow(Vagrant::Util::Subprocess).to receive(:execute).and_return(subprocess_result)
expect(subject.cygwin_path(path)).to eq("/home/vagrant")
end
end
describe "#cygwin?" do
before do
allow(subject).to receive(:platform).and_return("test")
@ -51,6 +70,50 @@ describe Vagrant::Util::Platform do
end
end
describe "#msys?" do
before do
allow(subject).to receive(:platform).and_return("test")
described_class.reset!
end
after do
described_class.reset!
end
around do |example|
with_temp_env(VAGRANT_DETECTED_OS: "nope", PATH: "") do
example.run
end
end
it "returns true if VAGRANT_DETECTED_OS includes msys" do
with_temp_env(VAGRANT_DETECTED_OS: "msys") do
expect(subject).to be_msys
end
end
it "returns true if OSTYPE includes msys" do
with_temp_env(OSTYPE: "msys") do
expect(subject).to be_msys
end
end
it "returns true if platform has msys" do
allow(subject).to receive(:platform).and_return("msys")
expect(subject).to be_msys
end
it "returns false if the PATH contains msys" do
with_temp_env(PATH: "C:/msys") do
expect(subject).to_not be_msys
end
end
it "returns false if nothing is available" do
expect(subject).to_not be_msys
end
end
describe "#fs_real_path" do
it "fixes drive letters on Windows", :windows do
expect(described_class.fs_real_path("c:/foo").to_s).to eql("C:/foo")