Skip to content

Commit 503c50b

Browse files
committed
(PUP-11348) Remove Windows ENV monkeypatches
Ruby 3 no longer relies on the current code page when reading/writing env vars[1]. Instead it uses wide Win32 APIs and transcodes them to UTF-8. Ruby's implementation also excludes env var that start with `=` ruby/ruby@ca76337
1 parent 1fba884 commit 503c50b

File tree

2 files changed

+52
-72
lines changed

2 files changed

+52
-72
lines changed

lib/puppet/util.rb

+19-69
Original file line numberDiff line numberDiff line change
@@ -39,103 +39,53 @@ def create_erb(content)
3939
end
4040
module_function :create_erb
4141

42-
# @param name [String] The name of the environment variable to retrieve
43-
# @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
44-
# @return [String] Value of the specified environment variable. nil if it does not exist
42+
# @deprecated Use ENV instead
4543
# @api private
4644
def get_env(name, mode = default_env)
47-
if mode == :windows
48-
Puppet::Util::Windows::Process.get_environment_strings.each do |key, value |
49-
if name.casecmp(key) == 0 then
50-
return value
51-
end
52-
end
53-
return nil
54-
else
55-
ENV[name]
56-
end
45+
ENV[name]
5746
end
5847
module_function :get_env
5948

60-
# @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
61-
# @return [Hash] A hashtable of all environment variables
49+
# @deprecated Use ENV instead
6250
# @api private
6351
def get_environment(mode = default_env)
64-
case mode
65-
when :posix
66-
ENV.to_hash
67-
when :windows
68-
Puppet::Util::Windows::Process.get_environment_strings
69-
else
70-
raise _("Unable to retrieve the environment for mode %{mode}") % { mode: mode }
71-
end
52+
ENV.to_hash
7253
end
7354
module_function :get_environment
7455

75-
# Removes all environment variables
76-
# @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
56+
# @deprecated Use ENV instead
7757
# @api private
7858
def clear_environment(mode = default_env)
79-
case mode
80-
when :posix
81-
ENV.clear
82-
when :windows
83-
Puppet::Util::Windows::Process.get_environment_strings.each do |key, _|
84-
Puppet::Util::Windows::Process.set_environment_variable(key, nil)
85-
end
86-
else
87-
raise _("Unable to clear the environment for mode %{mode}") % { mode: mode }
88-
end
59+
ENV.clear
8960
end
9061
module_function :clear_environment
9162

92-
# @param name [String] The name of the environment variable to set
93-
# @param value [String] The value to set the variable to. nil deletes the environment variable
94-
# @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
63+
# @deprecated Use ENV instead
9564
# @api private
9665
def set_env(name, value = nil, mode = default_env)
97-
case mode
98-
when :posix
99-
ENV[name] = value
100-
when :windows
101-
Puppet::Util::Windows::Process.set_environment_variable(name,value)
102-
else
103-
raise _("Unable to set the environment variable %{name} for mode %{mode}") % { name: name, mode: mode }
104-
end
66+
ENV[name] = value
10567
end
10668
module_function :set_env
10769

108-
# @param name [Hash] Environment variables to merge into the existing environment. nil values will remove the variable
109-
# @param mode [Symbol] Which operating system mode to use e.g. :posix or :windows. Use nil to autodetect
70+
# @deprecated Use ENV instead
11071
# @api private
11172
def merge_environment(env_hash, mode = default_env)
112-
case mode
113-
when :posix
114-
env_hash.each { |name, val| ENV[name.to_s] = val }
115-
when :windows
116-
env_hash.each do |name, val|
117-
Puppet::Util::Windows::Process.set_environment_variable(name.to_s, val)
118-
end
119-
else
120-
raise _("Unable to merge given values into the current environment for mode %{mode}") % { mode: mode }
121-
end
73+
ENV.merge!(hash.transform_keys(&:to_s))
12274
end
12375
module_function :merge_environment
12476

12577
# Run some code with a specific environment. Resets the environment back to
12678
# what it was at the end of the code.
127-
# Windows can store Unicode chars in the environment as keys or values, but
128-
# Ruby's ENV tries to roundtrip them through the local codepage, which can
129-
# cause encoding problems - underlying helpers use Windows APIs on Windows
130-
# see https://bugs.ruby-lang.org/issues/8822
79+
#
80+
# @param hash [Hash{String,Symbol => String}] Environment variables to override the current environment.
81+
# @param mode [Symbol] ignored
13182
def withenv(hash, mode = :posix)
132-
saved = get_environment(mode)
133-
merge_environment(hash, mode)
134-
yield
135-
ensure
136-
if saved
137-
clear_environment(mode)
138-
merge_environment(saved, mode)
83+
saved = ENV.to_hash
84+
begin
85+
ENV.merge!(hash.transform_keys(&:to_s))
86+
yield
87+
ensure
88+
ENV.replace(saved)
13989
end
14090
end
14191
module_function :withenv

spec/unit/util_spec.rb

+33-3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,31 @@ def get_mode(file)
6565
end
6666
expect(ENV["FOO"]).to eq(nil)
6767
end
68+
69+
it "accepts symbolic keys" do
70+
Puppet::Util.withenv(:FOO => "bar") do
71+
expect(ENV["FOO"]).to eq("bar")
72+
end
73+
end
74+
75+
it "coerces invalid keys to strings" do
76+
Puppet::Util.withenv(12345678 => "bar") do
77+
expect(ENV["12345678"]).to eq("bar")
78+
end
79+
end
80+
81+
it "rejects keys with leading equals" do
82+
expect {
83+
Puppet::Util.withenv("=foo" => "bar") {}
84+
}.to raise_error(Errno::EINVAL, /Invalid argument/)
85+
end
86+
87+
it "includes keys with unicode replacement characters" do
88+
Puppet::Util.withenv("foo\uFFFD" => "bar") do
89+
expect(ENV).to be_include("foo\uFFFD")
90+
end
91+
end
92+
6893
it "accepts a unicode key" do
6994
key = "\u16A0\u16C7\u16BB\u16EB\u16D2\u16E6\u16A6\u16EB\u16A0\u16B1\u16A9\u16A0\u16A2\u16B1\u16EB\u16A0\u16C1\u16B1\u16AA\u16EB\u16B7\u16D6\u16BB\u16B9\u16E6\u16DA\u16B3\u16A2\u16D7"
7095

@@ -81,16 +106,21 @@ def get_mode(file)
81106
end
82107
end
83108

109+
it "rejects a non-string value" do
110+
expect {
111+
Puppet::Util.withenv("reject" => 123) {}
112+
}.to raise_error(TypeError, /no implicit conversion of Integer into String/)
113+
end
114+
84115
it "accepts a nil value" do
85116
Puppet::Util.withenv("foo" => nil) do
86117
expect(ENV["foo"]).to eq(nil)
87118
end
88119
end
89-
90120
end
91121

92122
describe "#withenv on POSIX", :unless => Puppet::Util::Platform.windows? do
93-
it "should preserve case" do
123+
it "compares keys case sensitively" do
94124
# start with lower case key,
95125
env_key = SecureRandom.uuid.downcase
96126

@@ -115,7 +145,7 @@ def get_mode(file)
115145
describe "#withenv on Windows", :if => Puppet::Util::Platform.windows? do
116146
let(:process) { Puppet::Util::Windows::Process }
117147

118-
it "should ignore case" do
148+
it "compares keys case-insensitively" do
119149
# start with lower case key, ensuring string is not entirely numeric
120150
env_key = SecureRandom.uuid.downcase + 'a'
121151

0 commit comments

Comments
 (0)