[Pkg-puppet-devel] [facter] 140/352: Extract Facter execution methods to mixin
Stig Sandbeck Mathisen
ssm at debian.org
Sun Apr 6 22:21:39 UTC 2014
This is an automated email from the git hooks/post-receive script.
ssm pushed a commit to branch master
in repository facter.
commit d9449edb4a87dd3eb538126de792d0895aae9162
Author: Adrien Thebo <git at somethingsinistral.net>
Date: Mon Dec 30 17:35:39 2013 -0800
Extract Facter execution methods to mixin
The command execution methods in Facter::Util::Resolution were
cluttering up the class and breaking the single responsbility principle.
Leaving them around increases the complexity of refactoring the
Resolution class.
This commit extracts methods related to command execution to a mixin and
extends the Resolution class with the mixin to maintain compatibility.
In the long term we should deprecate the compatibility methods.
---
lib/facter/util/execution.rb | 214 +++++++++++++++++++++++++
lib/facter/util/resolution.rb | 211 ++-----------------------
spec/unit/util/execution_spec.rb | 209 ++++++++++++++++++++++++
spec/unit/util/resolution_spec.rb | 324 --------------------------------------
4 files changed, 432 insertions(+), 526 deletions(-)
diff --git a/lib/facter/util/execution.rb b/lib/facter/util/execution.rb
new file mode 100644
index 0000000..875470a
--- /dev/null
+++ b/lib/facter/util/execution.rb
@@ -0,0 +1,214 @@
+require 'facter/util/config'
+
+module Facter
+ module Util
+ module Execution
+
+ module_function
+
+ # Returns the locations to be searched when looking for a binary. This
+ # is currently determined by the +PATH+ environment variable plus
+ # `/sbin` and `/usr/sbin` when run on unix
+ #
+ # @return [Array<String>] the paths to be searched for binaries
+ # @api private
+ def search_paths
+ if Facter::Util::Config.is_windows?
+ ENV['PATH'].split(File::PATH_SEPARATOR)
+ else
+ # Make sure facter is usable even for non-root users. Most commands
+ # in /sbin (like ifconfig) can be run as non priviledged users as
+ # long as they do not modify anything - which we do not do with facter
+ ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/sbin', '/usr/sbin' ]
+ end
+ end
+
+ # Determines the full path to a binary. If the supplied filename does not
+ # already describe an absolute path then different locations (determined
+ # by {search_paths}) will be searched for a match.
+ #
+ # Returns nil if no matching executable can be found otherwise returns
+ # the expanded pathname.
+ #
+ # @param bin [String] the executable to locate
+ # @return [String,nil] the full path to the executable or nil if not
+ # found
+ #
+ # @api public
+ def which(bin)
+ if absolute_path?(bin)
+ return bin if File.executable?(bin)
+ if Facter::Util::Config.is_windows? and File.extname(bin).empty?
+ exts = ENV['PATHEXT']
+ exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
+ exts.each do |ext|
+ destext = bin + ext
+ if File.executable?(destext)
+ Facter.warnonce("Using Facter::Util::Execution.which with an absolute path like #{bin} but no fileextension is deprecated. Please add the correct extension (#{ext})")
+ return destext
+ end
+ end
+ end
+ else
+ search_paths.each do |dir|
+ dest = File.join(dir, bin)
+ if Facter::Util::Config.is_windows?
+ dest.gsub!(File::SEPARATOR, File::ALT_SEPARATOR)
+ if File.extname(dest).empty?
+ exts = ENV['PATHEXT']
+ exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
+ exts.each do |ext|
+ destext = dest + ext
+ return destext if File.executable?(destext)
+ end
+ end
+ end
+ return dest if File.executable?(dest)
+ end
+ end
+ nil
+ end
+
+ # Determine in a platform-specific way whether a path is absolute. This
+ # defaults to the local platform if none is specified.
+ #
+ # @param path [String] the path to check
+ # @param platform [:posix,:windows,nil] the platform logic to use
+ def absolute_path?(path, platform=nil)
+ # Escape once for the string literal, and once for the regex.
+ slash = '[\\\\/]'
+ name = '[^\\\\/]+'
+ regexes = {
+ :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
+ :posix => %r!^/!,
+ }
+ platform ||= Facter::Util::Config.is_windows? ? :windows : :posix
+
+ !! (path =~ regexes[platform])
+ end
+
+ # Given a command line, this returns the command line with the
+ # executable written as an absolute path. If the executable contains
+ # spaces, it has be but in double quotes to be properly recognized.
+ #
+ # @param command [String] the command line
+ #
+ # @return [String, nil] the command line with the executable's path
+ # expanded, or nil if the executable cannot be found.
+ def expand_command(command)
+ if match = /^"(.+?)"(?:\s+(.*))?/.match(command)
+ exe, arguments = match.captures
+ exe = which(exe) and [ "\"#{exe}\"", arguments ].compact.join(" ")
+ elsif match = /^'(.+?)'(?:\s+(.*))?/.match(command) and not Facter::Util::Config.is_windows?
+ exe, arguments = match.captures
+ exe = which(exe) and [ "'#{exe}'", arguments ].compact.join(" ")
+ else
+ exe, arguments = command.split(/ /,2)
+ if exe = which(exe)
+ # the binary was not quoted which means it contains no spaces. But the
+ # full path to the binary may do so.
+ exe = "\"#{exe}\"" if exe =~ /\s/ and Facter::Util::Config.is_windows?
+ exe = "'#{exe}'" if exe =~ /\s/ and not Facter::Util::Config.is_windows?
+ [ exe, arguments ].compact.join(" ")
+ end
+ end
+ end
+
+ # Overrides environment variables within a block of code. The
+ # specified values will be set for the duration of the block, after
+ # which the original values (if any) will be restored.
+ #
+ # @overload with_env(values, { || ... })
+ #
+ # @param values [Hash<String=>String>] A hash of the environment
+ # variables to override
+ #
+ # @return [void]
+ #
+ # @api public
+ def 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, capture the return value
+ rv = yield
+ # use an ensure block to make absolutely sure we restore the variables
+ ensure
+ # 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
+ # return the captured return value
+ rv
+ end
+
+ # Executes a program and return the output of that program.
+ #
+ # Returns nil if the program can't be found, or if there is a problem
+ # executing the code.
+ #
+ # @param code [String] the program to run
+ # @return [String, nil] the output of the program or nil
+ #
+ # @api public
+ #
+ # @note Since Facter 1.5.8 this strips trailing newlines from the
+ # returned value. If a fact will be used by versions of Facter older
+ # than 1.5.8 then you should call chomp the returned string.
+ #
+ # @overload exec(code)
+ # @overload exec(code, interpreter = nil)
+ # @param [String] interpreter unused, only exists for backwards
+ # compatibility
+ # @deprecated
+ def exec(code, interpreter = nil)
+ Facter.warnonce "The interpreter parameter to 'exec' is deprecated and will be removed in a future version." if interpreter
+
+ ## 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
+
+ if expanded_code = expand_command(code)
+ # if we can find the binary, we'll run the command with the expanded path to the binary
+ code = expanded_code
+ else
+ # if we cannot find the binary return nil on posix. On windows we'll still try to run the
+ # command in case it is a shell-builtin. In case it is not, windows will raise Errno::ENOENT
+ return nil unless Facter::Util::Config.is_windows?
+ return nil if absolute_path?(code)
+ end
+
+ out = nil
+
+ begin
+ out = %x{#{code}}.chomp
+ Facter.warnonce "Using Facter::Util::Execution.exec with a shell built-in is deprecated. Most built-ins can be replaced with native ruby commands. If you really have to run a built-in, pass \"cmd /c your_builtin\" as a command (command responsible for this message was \"#{code}\")" unless expanded_code
+ rescue Errno::ENOENT => detail
+ # command not found on Windows
+ return nil
+ rescue => detail
+ Facter.warn(detail)
+ return nil
+ end
+
+ if out == ""
+ return nil
+ else
+ return out
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/facter/util/resolution.rb b/lib/facter/util/resolution.rb
index 4160c9b..742bb98 100644
--- a/lib/facter/util/resolution.rb
+++ b/lib/facter/util/resolution.rb
@@ -1,6 +1,7 @@
require 'facter/util/confine'
require 'facter/util/config'
require 'facter/util/normalization'
+require 'facter/util/execution'
require 'timeout'
@@ -29,208 +30,14 @@ class Facter::Util::Resolution
INTERPRETER = Facter::Util::Config.is_windows? ? "cmd.exe" : "/bin/sh"
- # Returns the locations to be searched when looking for a binary. This
- # is currently determined by the +PATH+ environment variable plus
- # `/sbin` and `/usr/sbin` when run on unix
- #
- # @return [Array<String>] the paths to be searched for binaries
- # @api private
- def self.search_paths
- if Facter::Util::Config.is_windows?
- ENV['PATH'].split(File::PATH_SEPARATOR)
- else
- # Make sure facter is usable even for non-root users. Most commands
- # in /sbin (like ifconfig) can be run as non priviledged users as
- # long as they do not modify anything - which we do not do with facter
- ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/sbin', '/usr/sbin' ]
- end
- end
-
- # Determines the full path to a binary. If the supplied filename does not
- # already describe an absolute path then different locations (determined
- # by {search_paths}) will be searched for a match.
- #
- # Returns nil if no matching executable can be found otherwise returns
- # the expanded pathname.
- #
- # @param bin [String] the executable to locate
- # @return [String,nil] the full path to the executable or nil if not
- # found
- #
- # @api public
- def self.which(bin)
- if absolute_path?(bin)
- return bin if File.executable?(bin)
- if Facter::Util::Config.is_windows? and File.extname(bin).empty?
- exts = ENV['PATHEXT']
- exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
- exts.each do |ext|
- destext = bin + ext
- if File.executable?(destext)
- Facter.warnonce("Using Facter::Util::Resolution.which with an absolute path like #{bin} but no fileextension is deprecated. Please add the correct extension (#{ext})")
- return destext
- end
- end
- end
- else
- search_paths.each do |dir|
- dest = File.join(dir, bin)
- if Facter::Util::Config.is_windows?
- dest.gsub!(File::SEPARATOR, File::ALT_SEPARATOR)
- if File.extname(dest).empty?
- exts = ENV['PATHEXT']
- exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
- exts.each do |ext|
- destext = dest + ext
- return destext if File.executable?(destext)
- end
- end
- end
- return dest if File.executable?(dest)
- end
- end
- nil
- end
-
- # Determine in a platform-specific way whether a path is absolute. This
- # defaults to the local platform if none is specified.
- #
- # @param path [String] the path to check
- # @param platform [:posix,:windows,nil] the platform logic to use
- def self.absolute_path?(path, platform=nil)
- # Escape once for the string literal, and once for the regex.
- slash = '[\\\\/]'
- name = '[^\\\\/]+'
- regexes = {
- :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
- :posix => %r!^/!,
- }
- platform ||= Facter::Util::Config.is_windows? ? :windows : :posix
-
- !! (path =~ regexes[platform])
- end
-
- # Given a command line, this returns the command line with the
- # executable written as an absolute path. If the executable contains
- # spaces, it has be but in double quotes to be properly recognized.
- #
- # @param command [String] the command line
- #
- # @return [String, nil] the command line with the executable's path
- # expanded, or nil if the executable cannot be found.
- def self.expand_command(command)
- if match = /^"(.+?)"(?:\s+(.*))?/.match(command)
- exe, arguments = match.captures
- exe = which(exe) and [ "\"#{exe}\"", arguments ].compact.join(" ")
- elsif match = /^'(.+?)'(?:\s+(.*))?/.match(command) and not Facter::Util::Config.is_windows?
- exe, arguments = match.captures
- exe = which(exe) and [ "'#{exe}'", arguments ].compact.join(" ")
- else
- exe, arguments = command.split(/ /,2)
- if exe = which(exe)
- # the binary was not quoted which means it contains no spaces. But the
- # full path to the binary may do so.
- exe = "\"#{exe}\"" if exe =~ /\s/ and Facter::Util::Config.is_windows?
- exe = "'#{exe}'" if exe =~ /\s/ and not Facter::Util::Config.is_windows?
- [ exe, arguments ].compact.join(" ")
- end
- end
- end
-
- # Overrides environment variables within a block of code. The
- # specified values will be set for the duration of the block, after
- # which the original values (if any) will be restored.
- #
- # @overload with_env(values, { || ... })
- #
- # @param values [Hash<String=>String>] A hash of the environment
- # variables to override
- #
- # @return [void]
- #
- # @api public
- 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, capture the return value
- rv = yield
- # use an ensure block to make absolutely sure we restore the variables
- ensure
- # 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
- # return the captured return value
- rv
- end
-
- # Executes a program and return the output of that program.
- #
- # Returns nil if the program can't be found, or if there is a problem
- # executing the code.
- #
- # @param code [String] the program to run
- # @return [String, nil] the output of the program or nil
- #
- # @api public
- #
- # @note Since Facter 1.5.8 this strips trailing newlines from the
- # returned value. If a fact will be used by versions of Facter older
- # than 1.5.8 then you should call chomp the returned string.
- #
- # @overload exec(code)
- # @overload exec(code, interpreter = nil)
- # @param [String] interpreter unused, only exists for backwards
- # compatibility
- # @deprecated
- 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
-
- ## 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
-
- if expanded_code = expand_command(code)
- # if we can find the binary, we'll run the command with the expanded path to the binary
- code = expanded_code
- else
- # if we cannot find the binary return nil on posix. On windows we'll still try to run the
- # command in case it is a shell-builtin. In case it is not, windows will raise Errno::ENOENT
- return nil unless Facter::Util::Config.is_windows?
- return nil if absolute_path?(code)
- end
-
- out = nil
-
- begin
- out = %x{#{code}}.chomp
- Facter.warnonce "Using Facter::Util::Resolution.exec with a shell built-in is deprecated. Most built-ins can be replaced with native ruby commands. If you really have to run a built-in, pass \"cmd /c your_builtin\" as a command (command responsible for this message was \"#{code}\")" unless expanded_code
- rescue Errno::ENOENT => detail
- # command not found on Windows
- return nil
- rescue => detail
- Facter.warn(detail)
- return nil
- end
-
- if out == ""
- return nil
- else
- return out
- end
- end
+ extend Facter::Util::Execution
+ class << self
+ # Expose command execution methods that were extracted into
+ # Facter::Util::Execution from Facter::Util::Resolution in Facter 2.0.0 for
+ # compatibility.
+ #
+ # @deprecated
+ public :search_paths, :which, :absolute_path?, :expand_command, :with_env, :exec
end
# Sets the conditions for this resolution to be used. This takes a
diff --git a/spec/unit/util/execution_spec.rb b/spec/unit/util/execution_spec.rb
new file mode 100644
index 0000000..74dacf6
--- /dev/null
+++ b/spec/unit/util/execution_spec.rb
@@ -0,0 +1,209 @@
+require 'spec_helper'
+require 'facter/util/execution'
+
+describe Facter::Util::Execution do
+
+ describe "#search_paths" do
+ context "on windows", :as_platform => :windows do
+ it "should use the PATH environment variable to determine locations" do
+ ENV.expects(:[]).with('PATH').returns 'C:\Windows;C:\Windows\System32'
+ described_class.search_paths.should == %w{C:\Windows C:\Windows\System32}
+ end
+ end
+
+ context "on posix", :as_platform => :posix do
+ it "should use the PATH environment variable plus /sbin and /usr/sbin on unix" do
+ ENV.expects(:[]).with('PATH').returns "/bin:/usr/bin"
+ described_class.search_paths.should == %w{/bin /usr/bin /sbin /usr/sbin}
+ end
+ end
+ end
+
+ describe "#which" do
+ context "when run on posix", :as_platform => :posix do
+ before :each do
+ described_class.stubs(:search_paths).returns [ '/bin', '/sbin', '/usr/sbin']
+ end
+
+ context "and provided with an absolute path" do
+ it "should return the binary if executable" do
+ File.expects(:executable?).with('/opt/foo').returns true
+ described_class.which('/opt/foo').should == '/opt/foo'
+ end
+
+ it "should return nil if the binary is not executable" do
+ File.expects(:executable?).with('/opt/foo').returns false
+ described_class.which('/opt/foo').should be_nil
+ end
+ end
+
+ context "and not provided with an absolute path" do
+ it "should return the absolute path if found" do
+ File.expects(:executable?).with('/bin/foo').returns false
+ File.expects(:executable?).with('/sbin/foo').returns true
+ File.expects(:executable?).with('/usr/sbin/foo').never
+ described_class.which('foo').should == '/sbin/foo'
+ end
+
+ it "should return nil if not found" do
+ File.expects(:executable?).with('/bin/foo').returns false
+ File.expects(:executable?).with('/sbin/foo').returns false
+ File.expects(:executable?).with('/usr/sbin/foo').returns false
+ described_class.which('foo').should be_nil
+ end
+ end
+ end
+
+ context "when run on windows", :as_platform => :windows do
+ before :each do
+ described_class.stubs(:search_paths).returns ['C:\Windows\system32', 'C:\Windows', 'C:\Windows\System32\Wbem' ]
+ ENV.stubs(:[]).with('PATHEXT').returns nil
+ end
+
+ context "and provided with an absolute path" do
+ it "should return the binary if executable" do
+ File.expects(:executable?).with('C:\Tools\foo.exe').returns true
+ File.expects(:executable?).with('\\\\remote\dir\foo.exe').returns true
+ described_class.which('C:\Tools\foo.exe').should == 'C:\Tools\foo.exe'
+ described_class.which('\\\\remote\dir\foo.exe').should == '\\\\remote\dir\foo.exe'
+ end
+
+ it "should return the binary with added extension if executable" do
+ ['.COM', '.BAT', '.CMD', '' ].each do |ext|
+ File.stubs(:executable?).with('C:\Windows\system32\netsh'+ext).returns false
+ end
+ File.expects(:executable?).with('C:\Windows\system32\netsh.EXE').returns true
+
+ Facter.expects(:warnonce).with('Using Facter::Util::Execution.which with an absolute path like C:\\Windows\\system32\\netsh but no fileextension is deprecated. Please add the correct extension (.EXE)')
+ described_class.which('C:\Windows\system32\netsh').should == 'C:\Windows\system32\netsh.EXE'
+ end
+
+ it "should return nil if the binary is not executable" do
+ File.expects(:executable?).with('C:\Tools\foo.exe').returns false
+ File.expects(:executable?).with('\\\\remote\dir\foo.exe').returns false
+ described_class.which('C:\Tools\foo.exe').should be_nil
+ described_class.which('\\\\remote\dir\foo.exe').should be_nil
+ end
+ end
+
+ context "and not provided with an absolute path" do
+ it "should return the absolute path if found" do
+ File.expects(:executable?).with('C:\Windows\system32\foo.exe').returns false
+ File.expects(:executable?).with('C:\Windows\foo.exe').returns true
+ File.expects(:executable?).with('C:\Windows\System32\Wbem\foo.exe').never
+ described_class.which('foo.exe').should == 'C:\Windows\foo.exe'
+ end
+
+ it "should return the absolute path with file extension if found" do
+ ['.COM', '.EXE', '.BAT', '.CMD', '' ].each do |ext|
+ File.stubs(:executable?).with('C:\Windows\system32\foo'+ext).returns false
+ File.stubs(:executable?).with('C:\Windows\System32\Wbem\foo'+ext).returns false
+ end
+ ['.COM', '.BAT', '.CMD', '' ].each do |ext|
+ File.stubs(:executable?).with('C:\Windows\foo'+ext).returns false
+ end
+ File.stubs(:executable?).with('C:\Windows\foo.EXE').returns true
+
+ described_class.which('foo').should == 'C:\Windows\foo.EXE'
+ end
+
+ it "should return nil if not found" do
+ File.expects(:executable?).with('C:\Windows\system32\foo.exe').returns false
+ File.expects(:executable?).with('C:\Windows\foo.exe').returns false
+ File.expects(:executable?).with('C:\Windows\System32\Wbem\foo.exe').returns false
+ described_class.which('foo.exe').should be_nil
+ end
+ end
+ end
+
+ describe "#expand_command" do
+ context "on windows", :as_platform => :windows do
+ it "should expand binary" do
+ described_class.expects(:which).with('cmd').returns 'C:\Windows\System32\cmd'
+ described_class.expand_command(
+ 'cmd /c echo foo > C:\bar'
+ ).should == 'C:\Windows\System32\cmd /c echo foo > C:\bar'
+ end
+
+ it "should expand double quoted binary" do
+ described_class.expects(:which).with('my foo').returns 'C:\My Tools\my foo.exe'
+ described_class.expand_command('"my foo" /a /b').should == '"C:\My Tools\my foo.exe" /a /b'
+ end
+
+ it "should not expand single quoted binary" do
+ described_class.expects(:which).with('\'C:\My').returns nil
+ described_class.expand_command('\'C:\My Tools\foo.exe\' /a /b').should be_nil
+ end
+
+ it "should quote expanded binary if found in path with spaces" do
+ described_class.expects(:which).with('foo').returns 'C:\My Tools\foo.exe'
+ described_class.expand_command('foo /a /b').should == '"C:\My Tools\foo.exe" /a /b'
+ end
+
+ it "should return nil if not found" do
+ described_class.expects(:which).with('foo').returns nil
+ described_class.expand_command('foo /a | stuff >> /dev/null').should be_nil
+ end
+ end
+
+ context "on unix", :as_platform => :posix do
+ it "should expand binary" do
+ described_class.expects(:which).with('foo').returns '/bin/foo'
+ described_class.expand_command('foo -a | stuff >> /dev/null').should == '/bin/foo -a | stuff >> /dev/null'
+ end
+
+ it "should expand double quoted binary" do
+ described_class.expects(:which).with('/tmp/my foo').returns '/tmp/my foo'
+ described_class.expand_command(%q{"/tmp/my foo" bar}).should == %q{"/tmp/my foo" bar}
+ end
+
+ it "should expand single quoted binary" do
+ described_class.expects(:which).with('my foo').returns '/home/bob/my path/my foo'
+ described_class.expand_command(%q{'my foo' -a}).should == %q{'/home/bob/my path/my foo' -a}
+ end
+
+ it "should quote expanded binary if found in path with spaces" do
+ described_class.expects(:which).with('foo.sh').returns '/home/bob/my tools/foo.sh'
+ described_class.expand_command('foo.sh /a /b').should == %q{'/home/bob/my tools/foo.sh' /a /b}
+ end
+
+ it "should return nil if not found" do
+ described_class.expects(:which).with('foo').returns nil
+ described_class.expand_command('foo -a | stuff >> /dev/null').should be_nil
+ end
+ end
+ end
+
+ end
+
+ describe "#absolute_path?" do
+ context "when run on unix", :as_platform => :posix do
+ %w[/ /foo /foo/../bar //foo //Server/Foo/Bar //?/C:/foo/bar /\Server/Foo /foo//bar/baz].each do |path|
+ it "should return true for #{path}" do
+ described_class.should be_absolute_path(path)
+ end
+ end
+
+ %w[. ./foo \foo C:/foo \\Server\Foo\Bar \\?\C:\foo\bar \/?/foo\bar \/Server/foo foo//bar/baz].each do |path|
+ it "should return false for #{path}" do
+ described_class.should_not be_absolute_path(path)
+ end
+ end
+ end
+
+ context "when run on windows", :as_platform => :windows do
+ %w[C:/foo C:\foo \\\\Server\Foo\Bar \\\\?\C:\foo\bar //Server/Foo/Bar //?/C:/foo/bar /\?\C:/foo\bar \/Server\Foo/Bar c:/foo//bar//baz].each do |path|
+ it "should return true for #{path}" do
+ described_class.should be_absolute_path(path)
+ end
+ end
+
+ %w[/ . ./foo \foo /foo /foo/../bar //foo C:foo/bar foo//bar/baz].each do |path|
+ it "should return false for #{path}" do
+ described_class.should_not be_absolute_path(path)
+ end
+ end
+ end
+ end
+
+end
diff --git a/spec/unit/util/resolution_spec.rb b/spec/unit/util/resolution_spec.rb
index 78bc151..3ac79e0 100755
--- a/spec/unit/util/resolution_spec.rb
+++ b/spec/unit/util/resolution_spec.rb
@@ -391,328 +391,4 @@ describe Facter::Util::Resolution do
@resolve.should be_suitable
end
end
-
- it "should have a class method for executing code" do
- Facter::Util::Resolution.should respond_to(:exec)
- end
-
- # taken from puppet: spec/unit/util_spec.rb
- describe "#absolute_path?" do
- context "when run on unix", :as_platform => :posix do
- %w[/ /foo /foo/../bar //foo //Server/Foo/Bar //?/C:/foo/bar /\Server/Foo /foo//bar/baz].each do |path|
- it "should return true for #{path}" do
- Facter::Util::Resolution.should be_absolute_path(path)
- end
- end
-
- %w[. ./foo \foo C:/foo \\Server\Foo\Bar \\?\C:\foo\bar \/?/foo\bar \/Server/foo foo//bar/baz].each do |path|
- it "should return false for #{path}" do
- Facter::Util::Resolution.should_not be_absolute_path(path)
- end
- end
- end
-
- context "when run on windows", :as_platform => :windows do
- %w[C:/foo C:\foo \\\\Server\Foo\Bar \\\\?\C:\foo\bar //Server/Foo/Bar //?/C:/foo/bar /\?\C:/foo\bar \/Server\Foo/Bar c:/foo//bar//baz].each do |path|
- it "should return true for #{path}" do
- Facter::Util::Resolution.should be_absolute_path(path)
- end
- end
-
- %w[/ . ./foo \foo /foo /foo/../bar //foo C:foo/bar foo//bar/baz].each do |path|
- it "should return false for #{path}" do
- Facter::Util::Resolution.should_not be_absolute_path(path)
- end
- end
- end
- end
-
- describe "#search_paths" do
- context "on windows", :as_platform => :windows do
- it "should use the PATH environment variable to determine locations" do
- ENV.expects(:[]).with('PATH').returns 'C:\Windows;C:\Windows\System32'
- Facter::Util::Resolution.search_paths.should == %w{C:\Windows C:\Windows\System32}
- end
- end
-
- context "on posix", :as_platform => :posix do
- it "should use the PATH environment variable plus /sbin and /usr/sbin on unix" do
- ENV.expects(:[]).with('PATH').returns "/bin:/usr/bin"
- Facter::Util::Resolution.search_paths.should == %w{/bin /usr/bin /sbin /usr/sbin}
- end
- end
- end
-
- describe "#which" do
- context "when run on posix", :as_platform => :posix do
- before :each do
- Facter::Util::Resolution.stubs(:search_paths).returns [ '/bin', '/sbin', '/usr/sbin']
- end
-
- context "and provided with an absolute path" do
- it "should return the binary if executable" do
- File.expects(:executable?).with('/opt/foo').returns true
- Facter::Util::Resolution.which('/opt/foo').should == '/opt/foo'
- end
-
- it "should return nil if the binary is not executable" do
- File.expects(:executable?).with('/opt/foo').returns false
- Facter::Util::Resolution.which('/opt/foo').should be_nil
- end
- end
-
- context "and not provided with an absolute path" do
- it "should return the absolute path if found" do
- File.expects(:executable?).with('/bin/foo').returns false
- File.expects(:executable?).with('/sbin/foo').returns true
- File.expects(:executable?).with('/usr/sbin/foo').never
- Facter::Util::Resolution.which('foo').should == '/sbin/foo'
- end
-
- it "should return nil if not found" do
- File.expects(:executable?).with('/bin/foo').returns false
- File.expects(:executable?).with('/sbin/foo').returns false
- File.expects(:executable?).with('/usr/sbin/foo').returns false
- Facter::Util::Resolution.which('foo').should be_nil
- end
- end
- end
-
- context "when run on windows", :as_platform => :windows do
- before :each do
- Facter::Util::Resolution.stubs(:search_paths).returns ['C:\Windows\system32', 'C:\Windows', 'C:\Windows\System32\Wbem' ]
- ENV.stubs(:[]).with('PATHEXT').returns nil
- end
-
- context "and provided with an absolute path" do
- it "should return the binary if executable" do
- File.expects(:executable?).with('C:\Tools\foo.exe').returns true
- File.expects(:executable?).with('\\\\remote\dir\foo.exe').returns true
- Facter::Util::Resolution.which('C:\Tools\foo.exe').should == 'C:\Tools\foo.exe'
- Facter::Util::Resolution.which('\\\\remote\dir\foo.exe').should == '\\\\remote\dir\foo.exe'
- end
-
- it "should return the binary with added extension if executable" do
- ['.COM', '.BAT', '.CMD', '' ].each do |ext|
- File.stubs(:executable?).with('C:\Windows\system32\netsh'+ext).returns false
- end
- File.expects(:executable?).with('C:\Windows\system32\netsh.EXE').returns true
-
- Facter.expects(:warnonce).with('Using Facter::Util::Resolution.which with an absolute path like C:\\Windows\\system32\\netsh but no fileextension is deprecated. Please add the correct extension (.EXE)')
- Facter::Util::Resolution.which('C:\Windows\system32\netsh').should == 'C:\Windows\system32\netsh.EXE'
- end
-
- it "should return nil if the binary is not executable" do
- File.expects(:executable?).with('C:\Tools\foo.exe').returns false
- File.expects(:executable?).with('\\\\remote\dir\foo.exe').returns false
- Facter::Util::Resolution.which('C:\Tools\foo.exe').should be_nil
- Facter::Util::Resolution.which('\\\\remote\dir\foo.exe').should be_nil
- end
- end
-
- context "and not provided with an absolute path" do
- it "should return the absolute path if found" do
- File.expects(:executable?).with('C:\Windows\system32\foo.exe').returns false
- File.expects(:executable?).with('C:\Windows\foo.exe').returns true
- File.expects(:executable?).with('C:\Windows\System32\Wbem\foo.exe').never
- Facter::Util::Resolution.which('foo.exe').should == 'C:\Windows\foo.exe'
- end
-
- it "should return the absolute path with file extension if found" do
- ['.COM', '.EXE', '.BAT', '.CMD', '' ].each do |ext|
- File.stubs(:executable?).with('C:\Windows\system32\foo'+ext).returns false
- File.stubs(:executable?).with('C:\Windows\System32\Wbem\foo'+ext).returns false
- end
- ['.COM', '.BAT', '.CMD', '' ].each do |ext|
- File.stubs(:executable?).with('C:\Windows\foo'+ext).returns false
- end
- File.stubs(:executable?).with('C:\Windows\foo.EXE').returns true
-
- Facter::Util::Resolution.which('foo').should == 'C:\Windows\foo.EXE'
- end
-
- it "should return nil if not found" do
- File.expects(:executable?).with('C:\Windows\system32\foo.exe').returns false
- File.expects(:executable?).with('C:\Windows\foo.exe').returns false
- File.expects(:executable?).with('C:\Windows\System32\Wbem\foo.exe').returns false
- Facter::Util::Resolution.which('foo.exe').should be_nil
- end
- end
- end
-
- describe "#expand_command" do
- context "on windows", :as_platform => :windows do
- it "should expand binary" do
- Facter::Util::Resolution.expects(:which).with('cmd').returns 'C:\Windows\System32\cmd'
- Facter::Util::Resolution.expand_command(
- 'cmd /c echo foo > C:\bar'
- ).should == 'C:\Windows\System32\cmd /c echo foo > C:\bar'
- end
-
- it "should expand double quoted binary" do
- Facter::Util::Resolution.expects(:which).with('my foo').returns 'C:\My Tools\my foo.exe'
- Facter::Util::Resolution.expand_command('"my foo" /a /b').should == '"C:\My Tools\my foo.exe" /a /b'
- end
-
- it "should not expand single quoted binary" do
- Facter::Util::Resolution.expects(:which).with('\'C:\My').returns nil
- Facter::Util::Resolution.expand_command('\'C:\My Tools\foo.exe\' /a /b').should be_nil
- end
-
- it "should quote expanded binary if found in path with spaces" do
- Facter::Util::Resolution.expects(:which).with('foo').returns 'C:\My Tools\foo.exe'
- Facter::Util::Resolution.expand_command('foo /a /b').should == '"C:\My Tools\foo.exe" /a /b'
- end
-
- it "should return nil if not found" do
- Facter::Util::Resolution.expects(:which).with('foo').returns nil
- Facter::Util::Resolution.expand_command('foo /a | stuff >> /dev/null').should be_nil
- end
- end
-
- context "on unix", :as_platform => :posix do
- it "should expand binary" do
- Facter::Util::Resolution.expects(:which).with('foo').returns '/bin/foo'
- Facter::Util::Resolution.expand_command('foo -a | stuff >> /dev/null').should == '/bin/foo -a | stuff >> /dev/null'
- end
-
- it "should expand double quoted binary" do
- Facter::Util::Resolution.expects(:which).with('/tmp/my foo').returns '/tmp/my foo'
- Facter::Util::Resolution.expand_command(%q{"/tmp/my foo" bar}).should == %q{"/tmp/my foo" bar}
- end
-
- it "should expand single quoted binary" do
- Facter::Util::Resolution.expects(:which).with('my foo').returns '/home/bob/my path/my foo'
- Facter::Util::Resolution.expand_command(%q{'my foo' -a}).should == %q{'/home/bob/my path/my foo' -a}
- end
-
- it "should quote expanded binary if found in path with spaces" do
- Facter::Util::Resolution.expects(:which).with('foo.sh').returns '/home/bob/my tools/foo.sh'
- Facter::Util::Resolution.expand_command('foo.sh /a /b').should == %q{'/home/bob/my tools/foo.sh' /a /b}
- end
-
- it "should return nil if not found" do
- Facter::Util::Resolution.expects(:which).with('foo').returns nil
- Facter::Util::Resolution.expand_command('foo -a | stuff >> /dev/null').should be_nil
- end
- end
- end
-
- end
-
- # It's not possible, AFAICT, to mock %x{}, so I can't really test this bit.
- describe "when executing code" do
- # set up some command strings, making sure we get the right version for both unix and windows
- echo_command = Facter::Util::Config.is_windows? ? 'cmd.exe /c "echo foo"' : 'echo foo'
- echo_env_var_command = Facter::Util::Config.is_windows? ? 'cmd.exe /c "echo %%%s%%"' : 'echo $%s'
-
- it "should deprecate the interpreter parameter" do
- Facter.expects(:warnonce).with("The interpreter parameter to 'exec' is deprecated and will be removed in a future version.")
- Facter::Util::Resolution.exec("/something", "/bin/perl")
- end
-
- # execute a simple echo command
- it "should execute the binary" do
- Facter::Util::Resolution.exec(echo_command).should == "foo"
- end
-
- it "should override the LANG environment variable" do
- Facter::Util::Resolution.exec(echo_env_var_command % 'LANG').should == "C"
- end
-
- it "should respect other overridden environment variables" do
- Facter::Util::Resolution.with_env( {"FOO" => "foo"} ) do
- Facter::Util::Resolution.exec(echo_env_var_command % 'FOO').should == "foo"
- end
- end
-
- it "should restore overridden LANG environment variable after execution" do
- # we're going to call with_env in a nested fashion, to make sure that the environment gets restored properly
- # at each level
- Facter::Util::Resolution.with_env( {"LANG" => "foo"} ) do
- # Resolution.exec always overrides 'LANG' for its own execution scope
- Facter::Util::Resolution.exec(echo_env_var_command % 'LANG').should == "C"
- # But after 'exec' completes, we should see our value restored
- ENV['LANG'].should == "foo"
- # Now we'll do a nested call to with_env
- Facter::Util::Resolution.with_env( {"LANG" => "bar"} ) do
- # During 'exec' it should still be 'C'
- Facter::Util::Resolution.exec(echo_env_var_command % 'LANG').should == "C"
- # After exec it should be restored to our current value for this level of the nesting...
- ENV['LANG'].should == "bar"
- end
- # Now we've dropped out of one level of nesting,
- ENV['LANG'].should == "foo"
- # Call exec one more time just for kicks
- Facter::Util::Resolution.exec(echo_env_var_command % 'LANG').should == "C"
- # One last check at our current nesting level.
- ENV['LANG'].should == "foo"
- end
- end
-
- context "when run on unix", :as_platform => :posix do
- context "binary is present" do
- it "should run the command if path to binary is absolute" do
- Facter::Util::Resolution.expects(:expand_command).with('/usr/bin/uname -m').returns('/usr/bin/uname -m')
- Facter::Util::Resolution.expects(:`).with('/usr/bin/uname -m').returns 'x86_64'
- Facter::Util::Resolution.exec('/usr/bin/uname -m').should == 'x86_64'
- end
-
- it "should run the expanded command if path to binary not absolute" do
- Facter::Util::Resolution.expects(:expand_command).with('uname -m').returns('/usr/bin/uname -m')
- Facter::Util::Resolution.expects(:`).with('/usr/bin/uname -m').returns 'x86_64'
- Facter::Util::Resolution.exec('uname -m').should == 'x86_64'
- end
- end
-
- context "binary is not present" do
- it "should not run the command if path to binary is absolute" do
- Facter::Util::Resolution.expects(:expand_command).with('/usr/bin/uname -m').returns nil
- Facter::Util::Resolution.expects(:`).with('/usr/bin/uname -m').never
- Facter::Util::Resolution.exec('/usr/bin/uname -m').should be_nil
- end
- it "should not run the command if path to binary is not absolute" do
- Facter::Util::Resolution.expects(:expand_command).with('uname -m').returns nil
- Facter::Util::Resolution.expects(:`).with('uname -m').never
- Facter::Util::Resolution.exec('uname -m').should be_nil
- end
- end
- end
-
- context "when run on windows", :as_platform => :windows do
- context "binary is present" do
- it "should run the command if path to binary is absolute" do
- Facter::Util::Resolution.expects(:expand_command).with(%q{C:\Windows\foo.exe /a /b}).returns(%q{C:\Windows\foo.exe /a /b})
- Facter::Util::Resolution.expects(:`).with(%q{C:\Windows\foo.exe /a /b}).returns 'bar'
- Facter::Util::Resolution.exec(%q{C:\Windows\foo.exe /a /b}).should == 'bar'
- end
-
- it "should run the expanded command if path to binary not absolute" do
- Facter::Util::Resolution.expects(:expand_command).with(%q{foo.exe /a /b}).returns(%q{C:\Windows\foo.exe /a /b})
- Facter::Util::Resolution.expects(:`).with(%q{C:\Windows\foo.exe /a /b}).returns 'bar'
- Facter::Util::Resolution.exec(%q{foo.exe /a /b}).should == 'bar'
- end
- end
-
- context "binary is not present" do
- it "should not run the command if path to binary is absolute" do
- Facter::Util::Resolution.expects(:expand_command).with(%q{C:\Windows\foo.exe /a /b}).returns nil
- Facter::Util::Resolution.expects(:`).with(%q{C:\Windows\foo.exe /a /b}).never
- Facter::Util::Resolution.exec(%q{C:\Windows\foo.exe /a /b}).should be_nil
- end
- it "should try to run the command and return output of a shell-builtin" do
- Facter::Util::Resolution.expects(:expand_command).with(%q{echo foo}).returns nil
- Facter::Util::Resolution.expects(:`).with(%q{echo foo}).returns 'foo'
- Facter.expects(:warnonce).with 'Using Facter::Util::Resolution.exec with a shell built-in is deprecated. Most built-ins can be replaced with native ruby commands. If you really have to run a built-in, pass "cmd /c your_builtin" as a command (command responsible for this message was "echo foo")'
- Facter::Util::Resolution.exec(%q{echo foo}).should == 'foo'
- end
- it "should try to run the command and return nil if not shell-builtin" do
- Facter::Util::Resolution.expects(:expand_command).with(%q{echo foo}).returns nil
- Facter::Util::Resolution.stubs(:`).with(%q{echo foo}).raises Errno::ENOENT, 'some_error_message'
- Facter.expects(:warnonce).never
- Facter::Util::Resolution.exec(%q{echo foo}).should be_nil
- end
- end
- end
- end
end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-puppet/facter.git
More information about the Pkg-puppet-devel
mailing list