Fix LANG value used for VirtualBox driver
The VirtualBox driver sets the LANG env var to prevent localized output being returned when executing CLI commands. If the `locale` command is present, do a best effort lookup to determine the properly value to use for the LANG environment variable.
This commit is contained in:
parent
62c40e7395
commit
d53d8e61bc
@ -462,7 +462,7 @@ module VagrantPlugins
|
||||
# Append in the options for subprocess
|
||||
# NOTE: We include the LANG env var set to C to prevent command output
|
||||
# from being localized
|
||||
command << { notify: [:stdout, :stderr], env: {LANG: "C"}}
|
||||
command << { notify: [:stdout, :stderr], env: env_lang}
|
||||
|
||||
Vagrant::Util::Busy.busy(int_callback) do
|
||||
Vagrant::Util::Subprocess.execute(@vboxmanage_path, *command, &block)
|
||||
@ -471,6 +471,52 @@ module VagrantPlugins
|
||||
raise Vagrant::Errors::VBoxManageLaunchError,
|
||||
message: e.to_s
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# List of LANG values to attempt to use
|
||||
LANG_VARIATIONS = %w(C C.UTF-8 C.utf8 en_US.UTF-8 en_US.utf8 POSIX).map(&:freeze).freeze
|
||||
|
||||
# By default set the LANG to C. If the host has the locale command
|
||||
# available, check installed locales and verify C is included (or
|
||||
# use C variant if available).
|
||||
def env_lang
|
||||
# If already set, just return immediately
|
||||
return @env_lang if @env_lang
|
||||
|
||||
# Default the LANG to C
|
||||
@env_lang = {LANG: "C"}
|
||||
|
||||
# If the locale command is not available, return default
|
||||
return @env_lang if !Vagrant::Util::Which.which("locale")
|
||||
|
||||
@logger.debug("validating LANG value for virtualbox cli commands")
|
||||
# Get list of available locales on the system
|
||||
result = Vagrant::Util::Subprocess.execute("locale", "-a")
|
||||
|
||||
# If the command results in an error, just log the error
|
||||
# and return the default value
|
||||
if result.exit_code != 0
|
||||
@logger.warn("locale command failed (exit code: #{result.exit_code}): #{result.stderr}")
|
||||
return @env_lang
|
||||
end
|
||||
available = result.stdout.lines.map(&:chomp).find_all { |l|
|
||||
l == "C" || l == "POSIX" || l.start_with?("C.") || l.start_with?("en_US.")
|
||||
}
|
||||
@logger.debug("list of available C locales: #{available.inspect}")
|
||||
|
||||
# Attempt to find a valid LANG from locale list
|
||||
lang = LANG_VARIATIONS.detect { |l| available.include?(l) }
|
||||
|
||||
if lang
|
||||
@logger.debug("valid variation found for LANG value: #{lang}")
|
||||
@env_lang[:LANG] = lang
|
||||
end
|
||||
|
||||
@logger.debug("LANG value set: #{@env_lang[:LANG].inspect}")
|
||||
|
||||
@env_lang
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
99
test/unit/plugins/providers/virtualbox/driver/base.rb
Normal file
99
test/unit/plugins/providers/virtualbox/driver/base.rb
Normal file
@ -0,0 +1,99 @@
|
||||
require_relative "../base"
|
||||
require Vagrant.source_root.join("plugins/providers/virtualbox/driver/base")
|
||||
|
||||
describe VagrantPlugins::ProviderVirtualBox::Driver::Base do
|
||||
describe "#env_lang" do
|
||||
context "when locale command is not available" do
|
||||
before do
|
||||
allow(Vagrant::Util::Which).to receive(:which).with("locale").and_return(false)
|
||||
end
|
||||
|
||||
it "should return default value" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "C"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when the locale command is available" do
|
||||
let(:result) { Vagrant::Util::Subprocess::Result.new(exit_code, stdout, stderr) }
|
||||
let(:stderr) { "" }
|
||||
let(:stdout) { "C.default" }
|
||||
let(:exit_code) { 0 }
|
||||
|
||||
before do
|
||||
allow(Vagrant::Util::Which).to receive(:which).with("locale").and_return(true)
|
||||
allow(Vagrant::Util::Subprocess).to receive(:execute).with("locale", "-a").and_return(result)
|
||||
end
|
||||
|
||||
context "when locale command errors" do
|
||||
let(:exit_code) { 1 }
|
||||
|
||||
it "should return default value" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "C"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when locale command does not error" do
|
||||
let(:exit_code) { 0 }
|
||||
let(:base) { "de_AT.utf8\nde_BE.utf8\nde_CH.utf8\nde_DE.utf8\nde_IT.utf8\nde_LI.utf8\nde_LU.utf8\nen_AG\nen_AG.utf8\nen_AU.utf8\nen_BW.utf8\nen_CA.utf8\nen_DK.utf8\nen_GB.utf8\nen_HK.utf8\nen_IE.utf8\nen_IL\nen_IL.utf8\nen_IN\nen_IN.utf8\nen_NG\n" }
|
||||
|
||||
context "when stdout includes C" do
|
||||
let(:stdout) { "#{base}C\n" }
|
||||
|
||||
it "should use C for the lang" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "C"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when stdout does not include C" do
|
||||
context "when stdout includes C.UTF-8" do
|
||||
let(:stdout) { "#{base}C.UTF-8\n"}
|
||||
|
||||
it "should use C.UTF-8 for the lang" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "C.UTF-8"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when stdout includes C.utf8" do
|
||||
let(:stdout) { "#{base}C.utf8\n"}
|
||||
|
||||
it "should use C.utf8 for the lang" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "C.utf8"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when stdout includes POSIX" do
|
||||
let(:stdout) { "#{base}POSIX\n"}
|
||||
|
||||
it "should use POSIX for the lang" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "POSIX"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when stdout includes en_US.UTF-8" do
|
||||
let(:stdout) { "#{base}en_US.UTF-8\n"}
|
||||
|
||||
it "should use en_US.UTF-8 for the lang" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "en_US.UTF-8"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when stdout includes en_US.utf8" do
|
||||
let(:stdout) { "#{base}en_US.utf8\n"}
|
||||
|
||||
it "should use en_US.utf8 for the lang" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "en_US.utf8"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when stdout does not include any variations" do
|
||||
let(:stdout) { base }
|
||||
|
||||
it "should default to C" do
|
||||
expect(subject.send(:env_lang)).to eq({LANG: "C"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -28,6 +28,9 @@ shared_context "virtualbox" do
|
||||
allow(subprocess).to receive(:execute).
|
||||
with("VBoxManage", "showvminfo", kind_of(String), kind_of(Hash)).
|
||||
and_return(subprocess_result(exit_code: 0))
|
||||
|
||||
allow(Vagrant::Util::Which).to receive(:which).and_call_original
|
||||
allow(Vagrant::Util::Which).to receive(:which).with("locale").and_return(false)
|
||||
end
|
||||
|
||||
around do |example|
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user