Please review pull request #149: Bug/master/12012 global env lang override opened by (cprice-puppet)
Description:
Fix for Facter ticket #12012; basically stop globally overriding the LANG environment variable whenever facter.rb gets 'require'd.
- Opened: Fri Jan 20 01:15:46 UTC 2012
- Based on: puppetlabs:master (4b0c12bf5965e998c48a2b4d66676f0d7a561168)
- Requested merge: cprice-puppet:bug/master/12012-global-ENV-LANG-override (810c465653869c6cacca009aaa477ca389314456)
Diff follows:
diff --git a/lib/facter.rb b/lib/facter.rb index 5cbf74d..ec7827d 100644 --- a/lib/facter.rb +++ b/lib/facter.rb @@ -39,10 +39,6 @@ module Util; end # puts Facter['operatingsystem'] # - # Set LANG to force i18n to C - # - ENV['LANG'] = 'C' - GREEN = " [0;32m" RESET = " [0m" @@debug = 0 diff --git a/lib/facter/util/resolution.rb b/lib/facter/util/resolution.rb index dc58cb5..4913fe2 100644 --- a/lib/facter/util/resolution.rb +++ b/lib/facter/util/resolution.rb @@ -26,6 +26,36 @@ def self.have_which @have_which end + # + # Call this method with a block of code for which you would like to temporarily modify + # one or more environment variables; the specified values will be set for the duration + # of your block, after which the original values (if any) will be restored. + # + # [values] a Hash containing the key/value pairs of any environment variables that you + # would like to temporarily override + def self.with_env(values) + old = {} + values.each do |var, value| + # save the old value if it exists + if old_val = ENV[var] + old[var] = old_val + end + # set the new (temporary) value for the environment variable + ENV[var] = value + end + # execute the caller's block + yield + # restore the old values + values.each do |var, value| + if old.include?(var) + ENV[var] = old[var] + else + # if there was no old value, delete the key from the current environment variables hash + ENV.delete(var) + end + end + end + # Execute a program and return the output of that program. # # Returns nil if the program can't be found, or if there is a problem @@ -34,47 +64,55 @@ def self.have_which def self.exec(code, interpreter = nil) Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter - # Try to guess whether the specified code can be executed by looking at the - # first word. If it cannot be found on the PATH defer on resolving the fact - # by returning nil. - # This only fails on shell built-ins, most of which are masked by stuff in - # /bin or of dubious value anyways. In the worst case, "sh -c 'builtin'" can - # be used to work around this limitation - # - # Windows' %x{} throws Errno::ENOENT when the command is not found, so we - # can skip the check there. This is good, since builtins cannot be found - # elsewhere. - if have_which and !Facter::Util::Config.is_windows? - path = nil - binary = code.split.first - if code =~ /^\// - path = binary - else - path = %x{which #{binary} 2>/dev/null}.chomp - # we don't have the binary necessary - return nil if path == "" or path.match(/Command not found\./) + + ## Set LANG to force i18n to C for the duration of this exec; this ensures that any code that parses the + ## output of the command can expect it to be in a consistent / predictable format / locale + with_env "LANG" => "C" do + + # Try to guess whether the specified code can be executed by looking at the + # first word. If it cannot be found on the PATH defer on resolving the fact + # by returning nil. + # This only fails on shell built-ins, most of which are masked by stuff in + # /bin or of dubious value anyways. In the worst case, "sh -c 'builtin'" can + # be used to work around this limitation + # + # Windows' %x{} throws Errno::ENOENT when the command is not found, so we + # can skip the check there. This is good, since builtins cannot be found + # elsewhere. + if have_which and !Facter::Util::Config.is_windows? + path = nil + binary = code.split.first + if code =~ /^\// + path = binary + else + path = %x{which #{binary} 2>/dev/null}.chomp + # we don't have the binary necessary + return nil if path == "" or path.match(/Command not found\./) + end + + return nil unless FileTest.exists?(path) end - return nil unless FileTest.exists?(path) - end + out = nil - out = nil + begin + out = %x{#{code}}.chomp + rescue Errno::ENOENT => detail + # command not found on Windows + return nil + rescue => detail + $stderr.puts detail + return nil + end - begin - out = %x{#{code}}.chomp - rescue Errno::ENOENT => detail - # command not found on Windows - return nil - rescue => detail - $stderr.puts detail - return nil - end + if out == "" + return nil + else + return out + end - if out == "" - return nil - else - return out end + end # Add a new confine to the resolution mechanism. diff --git a/spec/unit/util/loader_spec.rb b/spec/unit/util/loader_spec.rb index 3a83f16..7653484 100755 --- a/spec/unit/util/loader_spec.rb +++ b/spec/unit/util/loader_spec.rb @@ -21,24 +21,6 @@ def load_file(file) Facter::Util::Loader.any_instance.unstub(:load_all) end - def with_env(values) - old = {} - values.each do |var, value| - if old_val = ENV[var] - old[var] = old_val - end - ENV[var] = value - end - yield - values.each do |var, value| - if old.include?(var) - ENV[var] = old[var] - else - ENV.delete(var) - end - end - end - it "should have a method for loading individual facts by name" do Facter::Util::Loader.new.should respond_to(:load) end @@ -76,7 +58,7 @@ def with_env(values) describe "and the FACTERLIB environment variable is set" do it "should include all paths in FACTERLIB" do - with_env "FACTERLIB" => "/one/path:/two/path" do + Facter::Util::Resolution.with_env "FACTERLIB" => "/one/path:/two/path" do paths = @loader.search_path %w{/one/path /two/path}.each do |dir| paths.should be_include(dir) @@ -95,7 +77,7 @@ def with_env(values) it "should load values from the matching environment variable if one is present" do Facter.expects(:add).with("testing") - with_env "facter_testing" => "yayness" do + Facter::Util::Resolution.with_env "facter_testing" => "yayness" do @loader.load(:testing) end end @@ -267,7 +249,7 @@ def with_env(values) Facter.expects(:add).with('one') Facter.expects(:add).with('two') - with_env "facter_one" => "yayness", "facter_two" => "boo" do + Facter::Util::Resolution.with_env "facter_one" => "yayness", "facter_two" => "boo" do @loader.load_all end end @@ -281,7 +263,7 @@ def with_env(values) it "should load facts on the facter search path only once" do facterlibdir = File.expand_path(File.dirname(__FILE__) + '../../../fixtures/unit/util/loader') - with_env 'FACTERLIB' => facterlibdir do + Facter::Util::Resolution.with_env 'FACTERLIB' => facterlibdir do Facter::Util::Loader.new.load_all Facter.value(:nosuchfact).should be_nil end
--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To post to this group, send email to puppet-dev@googlegroups.com.
To unsubscribe from this group, send email to puppet-dev+unsubscr...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.