module Mixlib::ShellOut::Helper
Public Instance Methods
Source
# File lib/mixlib/shellout/helper.rb, line 38 def shell_out(*args, **options) options = options.dup options = __maybe_add_timeout(self, options) if options.empty? shell_out_compacted(*__clean_array(*args)) else shell_out_compacted(*__clean_array(*args), **options) end end
These APIs are considered public for use in ohai and chef (by cookbooks and plugins, etc) but are considered private/experimental for now for the direct users of mixlib-shellout.
You can see an example of how to handle the “dependency injection” in the rspec unit test. That backend API is left deliberately undocumented for now and may not follow SemVer and may break at any time (at least for the rest of 2020).
Source
# File lib/mixlib/shellout/helper.rb, line 48 def shell_out!(*args, **options) options = options.dup options = __maybe_add_timeout(self, options) if options.empty? shell_out_compacted!(*__clean_array(*args)) else shell_out_compacted!(*__clean_array(*args), **options) end end
Private Instance Methods
Source
# File lib/mixlib/shellout/helper.rb, line 81 def __apply_default_env(options) options = options.dup default_env = options.delete(:default_env) default_env = true if default_env.nil? if default_env env_key = options.key?(:env) ? :env : :environment options[env_key] = { "LC_ALL" => __config[:internal_locale], "LANGUAGE" => __config[:internal_locale], "LANG" => __config[:internal_locale], __env_path_name => default_paths, }.update(options[env_key] || {}) end options end
helper function to mangle options when ‘default_env` is true
@api private
Source
# File lib/mixlib/shellout/helper.rb, line 140 def __clean_array(*args) args.flatten.compact.map(&:to_s) end
Helper for subclasses to reject nil out of an array. It allows using the array form of shell_out (which avoids the need to surround arguments with quote marks to deal with shells).
@param args [String] variable number of string arguments @return [Array] array of strings with nil and null string rejection
Source
# File lib/mixlib/shellout/helper.rb, line 201 def __env_path_name if ChefUtils.windows? "Path" else "PATH" end end
Source
# File lib/mixlib/shellout/helper.rb, line 193 def __io_for_live_stream if !STDOUT.closed? && __log.trace? STDOUT else nil end end
Source
# File lib/mixlib/shellout/helper.rb, line 152 def __join_whitespace(*args, quote: false) args.map do |arg| if arg.is_a?(Array) __join_whitespace(*arg, quote: arg.count > 1) else arg = arg.include?(" ") ? sprintf('"%s"', arg) : arg if quote arg.strip end end.join(" ") end
Join arguments into a string.
Strips leading/trailing spaces from each argument. If an argument contains a space, it is quoted. Join into a single string with spaces between each argument.
@param args [String] variable number of string arguments @return [String] merged string
Source
# File lib/mixlib/shellout/helper.rb, line 64 def __maybe_add_timeout(obj, options) options = options.dup # historically resources have not properly declared defaults on their timeouts, so a default default of 900s was enforced here default_val = 900 return options if options.key?(:timeout) # FIXME: need to nuke descendent tracker out of Chef::Provider so we can just define that class here without requiring the # world, and then just use symbol lookup if obj.class.ancestors.map(&:name).include?("Chef::Provider") && obj.respond_to?(:new_resource) && obj.new_resource.respond_to?(:timeout) && !options.key?(:timeout) options[:timeout] = obj.new_resource.timeout ? obj.new_resource.timeout.to_f : default_val end options end
helper sugar for resources that support passing timeouts to shell_out
module method to not pollute namespaces, but that means we need self injected as an arg @api private
Source
# File lib/mixlib/shellout/helper.rb, line 163 def __shell_out_command(*args, **options) if __transport_connection command = __join_whitespace(args) unless ChefUtils.windows? if options[:cwd] # as `timeout` is used, commands need to be executed in a subshell command = "sh -c 'cd #{options[:cwd]}; #{command}'" end if options[:input] command.concat "<<'COMMANDINPUT'\n" command.concat __join_whitespace(options[:input]) command.concat "\nCOMMANDINPUT\n" end end # FIXME: train should accept run_command(*args) FakeShellOut.new(args, options, __transport_connection.run_command(command, options)) else cmd = if options.empty? Mixlib::ShellOut.new(*args) else Mixlib::ShellOut.new(*args, **options) end cmd.live_stream ||= __io_for_live_stream cmd.run_command cmd end end
Source
# File lib/mixlib/shellout/helper.rb, line 114 def shell_out_compacted(*args, **options) options = __apply_default_env(options) if options.empty? __shell_out_command(*args) else __shell_out_command(*args, **options) end end
The shell_out_compacted/shell_out_compacted! APIs are private but are intended for use in rspec tests. They should always be used in rspec tests instead of shell_out to allow for less brittle rspec tests.
This expectation:
allow(provider).to receive(:shell_out_compacted!).with(“foo”, “bar”, “baz”)
Is met by many different possible calling conventions that mean the same thing:
provider.shell_out!(“foo”, [ “bar”, nil, “baz”]) provider.shell_out!([“foo”, nil, “bar” ], [“baz”])
Note that when setting ‘default_env: false` that you should just setup an expectation on :shell_out_compacted for `default_env: false`, rather than the expanded env settings so that the default_env implementation can change without breaking unit tests.
Source
# File lib/mixlib/shellout/helper.rb, line 123 def shell_out_compacted!(*args, **options) options = __apply_default_env(options) cmd = if options.empty? __shell_out_command(*args) else __shell_out_command(*args, **options) end cmd.error! cmd end