Merge pull request #7359 from mitchellh/sethvargo/cache_platform

Cache the results of common operations
This commit is contained in:
Seth Vargo 2016-05-31 11:03:46 -04:00
commit cf02135290
2 changed files with 69 additions and 39 deletions

View File

@ -1,6 +1,6 @@
require 'rbconfig' require "rbconfig"
require 'shellwords' require "shellwords"
require 'tmpdir' require "tmpdir"
require "vagrant/util/subprocess" require "vagrant/util/subprocess"
@ -10,17 +10,21 @@ module Vagrant
class Platform class Platform
class << self class << self
def cygwin? def cygwin?
# Installer detects Cygwin return @_cygwin if defined?(@_cygwin)
return true if ENV["VAGRANT_DETECTED_OS"] && @_cygwin = -> {
ENV["VAGRANT_DETECTED_OS"].downcase.include?("cygwin") # Installer detects Cygwin
return true if ENV["VAGRANT_DETECTED_OS"] &&
ENV["VAGRANT_DETECTED_OS"].downcase.include?("cygwin")
# Ruby running in Cygwin # Ruby running in Cygwin
return true if platform.include?("cygwin") return true if platform.include?("cygwin")
# Heuristic. If the path contains Cygwin, we just assume we're # Heuristic. If the path contains Cygwin, we just assume we're
# in Cygwin. It is generally a safe bet. # in Cygwin. It is generally a safe bet.
path = ENV["PATH"] || "" path = ENV["PATH"] || ""
return path.include?("cygwin") return path.include?("cygwin")
}.call
return @_cygwin
end end
[:darwin, :bsd, :freebsd, :linux, :solaris].each do |type| [:darwin, :bsd, :freebsd, :linux, :solaris].each do |type|
@ -30,11 +34,9 @@ module Vagrant
end end
def windows? def windows?
%W[mingw mswin].each do |text| return @_windows if defined?(@_windows)
return true if platform.include?(text) @_windows = %w[mingw mswin].any? { |t| platform.include?(t) }
end return @_windows
false
end end
# Checks if the user running Vagrant on Windows has administrative # Checks if the user running Vagrant on Windows has administrative
@ -42,23 +44,28 @@ module Vagrant
# #
# @return [Boolean] # @return [Boolean]
def windows_admin? def windows_admin?
return @_windows_admin if defined?(@_windows_admin)
# We lazily-load this because it is only available on Windows # We lazily-load this because it is only available on Windows
require 'win32/registry' require "win32/registry"
# Verify that we have administrative privileges. The odd method of # Verify that we have administrative privileges. The odd method of
# detecting this is based on this StackOverflow question: # detecting this is based on this StackOverflow question:
# #
# https://stackoverflow.com/questions/560366/ # https://stackoverflow.com/questions/560366/
# detect-if-running-with-administrator-privileges-under-windows-xp # detect-if-running-with-administrator-privileges-under-windows-xp
begin @_windows_admin = -> {
Win32::Registry::HKEY_USERS.open("S-1-5-19") {} begin
rescue Win32::Registry::Error Win32::Registry::HKEY_USERS.open("S-1-5-19") {}
return false
end
# If we made it this far then we try a fallback approach # The above doesn't seem to be 100% bullet proof. See GH-5616.
# since the above doesn't seem to be bullet proof. See GH-5616 return (`reg query HKU\\S-1-5-19 2>&1` =~ /ERROR/).nil?
(`reg query HKU\\S-1-5-19 2>&1` =~ /ERROR/).nil? rescue Win32::Registry::Error
return false
end
}.call
return @_windows_admin
end end
# Checks if the user running Vagrant on Windows is a member of the # Checks if the user running Vagrant on Windows is a member of the
@ -70,14 +77,17 @@ module Vagrant
# #
# @return [Boolean] # @return [Boolean]
def windows_hyperv_admin? def windows_hyperv_admin?
return @_windows_hyperv_admin if defined?(@_windows_hyperv_admin)
@_windows_hyperv_admin = -> {
begin begin
username = ENV["USERNAME"] username = ENV["USERNAME"]
process = Subprocess.execute("net", "localgroup", "Hyper-V Administrators") process = Subprocess.execute("net", "localgroup", "Hyper-V Administrators")
output = process.stdout.chomp return process.include?(username)
return output.include?(username)
rescue Errors::CommandUnavailableWindows rescue Errors::CommandUnavailableWindows
return false return false
end end
}.call
return @_windows_hyperv_admin
end end
# This takes any path and converts it from a Windows path to a # This takes any path and converts it from a Windows path to a
@ -125,16 +135,18 @@ module Vagrant
# directory runs a different filesystem than the root directory. # directory runs a different filesystem than the root directory.
# However, this works in many cases. # However, this works in many cases.
def fs_case_sensitive? def fs_case_sensitive?
Dir.mktmpdir("vagrant-fs-case-sensitive") do |tmp_dir| return @_fs_case_sensitive if defined?(@_fs_case_sensitive)
tmp_file = File.join(tmp_dir, "FILE") @_fs_case_sensitive = Dir.mktmpdir("vagrant-fs-case-sensitive") do |dir|
tmp_file = File.join(dir, "FILE")
File.open(tmp_file, "w") do |f| File.open(tmp_file, "w") do |f|
f.write("foo") f.write("foo")
end end
# The filesystem is case sensitive if the lowercased version # The filesystem is case sensitive if the lowercased version
# of the filename is NOT reported as existing. # of the filename is NOT reported as existing.
!File.file?(File.join(tmp_dir, "file")) !File.file?(File.join(dir, "file"))
end end
return @_fs_case_sensitive
end end
# This expands the path and ensures proper casing of each part # This expands the path and ensures proper casing of each part
@ -197,18 +209,31 @@ module Vagrant
# Returns a boolean noting whether the terminal supports color. # Returns a boolean noting whether the terminal supports color.
# output. # output.
def terminal_supports_colors? def terminal_supports_colors?
if windows? return @_terminal_supports_colors if defined?(@_terminal_supports_colors)
return true if ENV.key?("ANSICON") @_terminal_supports_colors = -> {
return true if cygwin? if windows?
return true if ENV["TERM"] == "cygwin" return true if ENV.key?("ANSICON")
return false return true if cygwin?
end return true if ENV["TERM"] == "cygwin"
return false
end
true return true
}.call
return @_terminal_supports_colors
end end
def platform def platform
RbConfig::CONFIG["host_os"].downcase return @_platform if defined?(@_platform)
@_platform = RbConfig::CONFIG["host_os"].downcase
return @_platform
end
# @private
# Reset the cached values for platform. This is not considered a public
# API and should only be used for testing.
def reset!
instance_variables.each(&method(:remove_instance_variable))
end end
end end
end end

View File

@ -10,6 +10,11 @@ describe Vagrant::Util::Platform do
describe "#cygwin?" do describe "#cygwin?" do
before do before do
allow(subject).to receive(:platform).and_return("test") allow(subject).to receive(:platform).and_return("test")
described_class.reset!
end
after do
described_class.reset!
end end
around do |example| around do |example|