Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Windows users with SSH installed to use 'vagrant ssh' #933

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 11 additions & 7 deletions lib/vagrant/ssh.rb
@@ -1,5 +1,6 @@
require 'log4r' require 'log4r'


require 'vagrant/util/file_util'
require 'vagrant/util/file_mode' require 'vagrant/util/file_mode'
require 'vagrant/util/platform' require 'vagrant/util/platform'
require 'vagrant/util/safe_exec' require 'vagrant/util/safe_exec'
Expand Down Expand Up @@ -55,15 +56,18 @@ def exec(opts={})
# Get the SSH information and cache it here # Get the SSH information and cache it here
ssh_info = info ssh_info = info


if Util::Platform.windows? # Ensure the platform supports ssh. On Windows there are several programs which
raise Errors::SSHUnavailableWindows, :host => ssh_info[:host], # include ssh, notably git, mingw and cygwin, but make sure ssh is in the path!
:port => ssh_info[:port], if !Util::FileUtil.which("ssh")
:username => ssh_info[:username], if Util::Platform.windows?
:key_path => ssh_info[:private_key_path] raise Errors::SSHUnavailableWindows, :host => ssh_info[:host],
:port => ssh_info[:port],
:username => ssh_info[:username],
:key_path => ssh_info[:private_key_path]
end
raise Errors::SSHUnavailable
end end


raise Errors::SSHUnavailable if !Kernel.system("which ssh > /dev/null 2>&1")

# If plain mode is enabled then we don't do any authentication (we don't # If plain mode is enabled then we don't do any authentication (we don't
# set a user or an identity file) # set a user or an identity file)
plain_mode = opts[:plain_mode] plain_mode = opts[:plain_mode]
Expand Down
36 changes: 36 additions & 0 deletions lib/vagrant/util/file_util.rb
@@ -0,0 +1,36 @@
module Vagrant
module Util
class FileUtil
# Cross-platform way of finding an executable in the $PATH.
#
# which('ruby') #=> /usr/bin/ruby
# by http://stackoverflow.com/users/11687/mislav
#
# This code is adapted from the following post by mislav:
# http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
def self.which(cmd)

# If the PATHEXT variable is empty, we're on *nix and need to find the exact filename
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webcoyote

Would the following perhaps be safer?:

Config::CONFIG['host_os'].include? 'mswin'

It may prove to be safer to go with a system flag such as this over a mutable environment variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right that using the PATHEXT variable as a way to detect Windows is
lame, but Config (deprecated) and RbConfig also seems to be fairly broken:

RbConfig::CONFIG['host_os'] =~ /mswin|windows|cygwin/i ==> nil (bogus!)

RbConfig::CONFIG['host_os'] =~ /mswin|windows|cygwin|mingw/i ==> 0 (found)

RUBY_PLATFORM ==> "i386-mingw32"

sigh.

However, it turns out that there is a "windows?" function in Util, part of
the vagrant project, so I'll use that.

Pat

On Mon, Jun 4, 2012 at 12:43 PM, Wil Moore III <
reply@reply.github.com

wrote:

@@ -0,0 +1,36 @@
+module Vagrant

@webcoyote

Would the following perhaps be safer?:

Config::CONFIG['host_os'].include? 'mswin'

It may prove to be safer to go with a system flag such as this over a
mutable environment variable.


Reply to this email directly or view it on GitHub:
https://github.com/mitchellh/vagrant/pull/933/files#r924609

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@webcoyote Yeah, that's a bummer about RbConfig and RUBY_PLATFORM...but good call on the Util stuff :)

exts = nil
if !Util::Platform.windows? || ENV['PATHEXT'].nil?
exts = ['']
# On Windows: if filename contains an extension, we must match that exact filename
elsif File.extname(cmd).length != 0
exts = ['']
# On Windows: otherwise try to match all possible executable file extensions (.EXE .COM .BAT etc.)
else
exts = ENV['PATHEXT'].split(';')
end

ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
exts.each do |ext|
exe = "#{path}#{File::SEPARATOR}#{cmd}#{ext}"
return exe if File.executable? exe
end
end

return nil
end
end
end
end
7 changes: 4 additions & 3 deletions templates/locales/en.yml
Expand Up @@ -149,9 +149,10 @@ en:
guest port value, or specify an explicit SSH port with `config.ssh.port`. guest port value, or specify an explicit SSH port with `config.ssh.port`.
ssh_unavailable: "`ssh` binary could not be found. Is an SSH client installed?" ssh_unavailable: "`ssh` binary could not be found. Is an SSH client installed?"
ssh_unavailable_windows: |- ssh_unavailable_windows: |-
`vagrant ssh` isn't available on the Windows platform. You are still able `ssh` executable not found in any directories in the %PATH% variable. Is an
to SSH into the virtual machine if you get a Windows SSH client (such as SSH client installed? Try installing Cygwin, MinGW or Git, all of which
PuTTY). The authentication information is shown below: contain an SSH client. Or use the PuTTY SSH client with the following
authentication information shown below:


Host: %{host} Host: %{host}
Port: %{port} Port: %{port}
Expand Down
46 changes: 46 additions & 0 deletions test/unit/vagrant/util/file_util_test.rb
@@ -0,0 +1,46 @@
require File.expand_path("../../../base", __FILE__)

require 'vagrant/util/file_util'
require 'vagrant/util/platform'

describe Vagrant::Util::FileUtil do

def tester (file_extension, test_extension, mode, &block)
# create file in temp directory
filename = '__vagrant_unit_test__'
dir = Dir.tmpdir
file = Pathname(dir) + (filename + file_extension)
file.open("w") { |f| f.write("#") }
file.chmod(mode)

# set the path to the directory where the file is located
savepath = ENV['PATH']
ENV['PATH'] = dir.to_s
block.call filename + test_extension
ENV['PATH'] = savepath

file.unlink
end

it "should return a path for an executable file" do
tester '.bat', '.bat', 0755 do |name|
Vagrant::Util::FileUtil.which(name).should_not be_nil
end
end

if Vagrant::Util::Platform.windows?
it "should return a path for a Windows executable file" do
tester '.bat', '', 0755 do |name|
Vagrant::Util::FileUtil.which(name).should_not be_nil
end
end
end

it "should return nil for a non-executable file" do
tester '.txt', '.txt', 0644 do |name|
Vagrant::Util::FileUtil.which(name).should be_nil
end
end

end