Class: Mixlib::ShellOut
- Inherits:
-
Object
- Object
- Mixlib::ShellOut
- Defined in:
- lib/mixlib/shellout.rb,
lib/mixlib/shellout/unix.rb,
lib/mixlib/shellout/version.rb,
lib/mixlib/shellout/windows.rb,
lib/mixlib/shellout/exceptions.rb
Defined Under Namespace
Modules: Unix, Windows Classes: CommandTimeout, InvalidCommandOption, ShellCommandFailed
Constant Summary collapse
- READ_WAIT_TIME =
0.01
- READ_SIZE =
4096- DEFAULT_READ_TIMEOUT =
600- VERSION =
"2.0.1"
Constants included from Unix
Constants included from Windows
Instance Attribute Summary collapse
-
#command ⇒ Object
readonly
The command to be executed.
-
#cwd ⇒ Object
Working directory for the subprocess.
-
#domain ⇒ Object
Returns the value of attribute domain.
-
#environment ⇒ Object
Environment variables that will be set for the subcommand.
-
#execution_time ⇒ Object
readonly
The amount of time the subcommand took to execute.
-
#group ⇒ Object
Group the command will run as.
-
#input ⇒ Object
ShellOut will push data from :input down the stdin of the subprocss.
-
#live_stderr ⇒ Object
When live_stderr is set, the stderr of the subprocess will be copied to it as the subprocess is running.
-
#live_stdout ⇒ Object
When live_stdout is set, the stdout of the subprocess will be copied to it as the subprocess is running.
-
#log_level ⇒ Object
The log level at which ShellOut should log.
-
#log_tag ⇒ Object
A string which will be prepended to the log message.
-
#logger ⇒ Object
If a logger is set, ShellOut will log a message before it executes the command.
-
#password ⇒ Object
Returns the value of attribute password.
-
#process_status_pipe ⇒ Object
readonly
Returns the value of attribute process_status_pipe.
-
#status ⇒ Object
readonly
A Process::Status (or ducktype) object collected when the subprocess is reaped.
-
#stderr ⇒ Object
readonly
Data written to stderr by the subprocess.
-
#stderr_pipe ⇒ Object
readonly
Returns the value of attribute stderr_pipe.
-
#stdin_pipe ⇒ Object
readonly
Returns the value of attribute stdin_pipe.
-
#stdout ⇒ Object
readonly
Data written to stdout by the subprocess.
-
#stdout_pipe ⇒ Object
readonly
Returns the value of attribute stdout_pipe.
- #timeout ⇒ Object
-
#umask ⇒ Object
The umask that will be set for the subcommand.
-
#user ⇒ Object
User the command will run as.
-
#valid_exit_codes ⇒ Object
An Array of acceptable exit codes.
-
#with_logon ⇒ Object
Returns the value of attribute with_logon.
Instance Method Summary collapse
-
#error! ⇒ Object
If #error? is true, calls
invalid!, which raises an Exception. -
#error? ⇒ Boolean
Checks the
exitstatusagainst the set ofvalid_exit_codes. -
#exitstatus ⇒ Object
The exit status of the subprocess.
-
#format_for_exception ⇒ Object
Creates a String showing the output of the command, including a banner showing the exact command executed.
-
#gid ⇒ Object
The gid that the subprocess will switch to.
-
#initialize(*command_args) ⇒ ShellOut
constructor
Arguments: Takes a single command, or a list of command fragments.
- #inspect ⇒ Object
-
#invalid!(msg = nil) ⇒ Object
Raises a ShellCommandFailed exception, appending the command’s stdout, stderr, and exitstatus to the exception message.
-
#live_stream ⇒ Object
Returns the stream that both is being used by both live_stdout and live_stderr, or nil.
-
#live_stream=(stream) ⇒ Object
A shortcut for setting both live_stdout and live_stderr, so that both the stdout and stderr from the subprocess will be copied to the same stream as the subprocess is running.
-
#run_command ⇒ Object
Run the command, writing the command’s standard out and standard error to
stdoutandstderr, and saving its exit status object tostatus=== Returns returnsself;stdout,stderr,status, andexitstatuswill be populated with results of the command === Raises * Errno::EACCES when you are not privileged to execute the command * Errno::ENOENT when the command is not available on the system (or not in the current $PATH) * CommandTimeout when the command does not complete withintimeoutseconds (default: 600s). -
#uid ⇒ Object
The uid that the subprocess will switch to.
Constructor Details
#initialize(*command_args) ⇒ ShellOut
Arguments:
Takes a single command, or a list of command fragments. These are used as arguments to Kernel.exec. See the Kernel.exec documentation for more explanation of how arguments are evaluated. The last argument can be an options Hash.
Options:
If the last argument is a Hash, it is removed from the list of args passed to exec and used as an options hash. The following options are available:
-
user: the user the commmand should run as. if an integer is given, it is used as a uid. A string is treated as a username and resolved to a uid with Etc.getpwnam -
group: the group the command should run as. works similarly touser -
cwd: the directory to chdir to before running the command -
umask: a umask to set before running the command. If given as an Integer, be sure to use two leading zeros so it’s parsed as Octal. A string will be treated as an octal integer -
returns: one or more Integer values to use as valid exit codes for the subprocess. This only has an effect if you callerror!afterrun_command. -
environment: a Hash of environment variables to set before the command is run. -
timeout: a Numeric value for the number of seconds to wait on the child process before raising an Exception. This is calculated as the total amount of time that ShellOut waited on the child process without receiving any output (i.e., IO.select returned nil). Default is 60 seconds. Note: the stdlib Timeout library is not used. -
input: A String of data to be passed to the subcommand. This is written to the child process’ stdin stream before the process is launched. The child’s stdin stream will be a pipe, so the size of input data should not exceed the system’s default pipe capacity (4096 bytes is a safe value, though on newer Linux systems the capacity is 64k by default). -
live_stream: An IO or Logger-like object (must respond to the append operator <<) that will receive data as ShellOut reads it from the child process. Generally this is used to copy data from the child to the parent’s stdout so that users may observe the progress of long-running commands.
Examples:
Invoke find(1) to search for .rb files:
find = Mixlib::ShellOut.new("find . -name '*.rb'")
find.run_command
# If all went well, the results are on +stdout+
puts find.stdout
# find(1) prints diagnostic info to STDERR:
puts "error messages" + find.stderr
# Raise an exception if it didn't exit with 0
find.error!
Run a command as the www user with no extra ENV settings from /tmp
cmd = Mixlib::ShellOut.new("apachectl", "start", :user => 'www', :env => nil, :cwd => '/tmp')
cmd.run_command # etc.
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/mixlib/shellout.rb', line 157 def initialize(*command_args) @stdout, @stderr, @process_status = '', '', '' @live_stdout = @live_stderr = nil @input = nil @log_level = :debug @log_tag = nil @environment = {} @cwd = nil @valid_exit_codes = [0] @terminate_reason = nil if command_args.last.is_a?(Hash) (command_args.pop) end @command = command_args.size == 1 ? command_args.first : command_args end |
Instance Attribute Details
#command ⇒ Object (readonly)
The command to be executed.
79 80 81 |
# File 'lib/mixlib/shellout.rb', line 79 def command @command end |
#cwd ⇒ Object
Working directory for the subprocess. Normally set via options to new
49 50 51 |
# File 'lib/mixlib/shellout.rb', line 49 def cwd @cwd end |
#domain ⇒ Object
Returns the value of attribute domain.
41 42 43 |
# File 'lib/mixlib/shellout.rb', line 41 def domain @domain end |
#environment ⇒ Object
Environment variables that will be set for the subcommand. Refer to the documentation of new to understand how ShellOut interprets this.
86 87 88 |
# File 'lib/mixlib/shellout.rb', line 86 def environment @environment end |
#execution_time ⇒ Object (readonly)
The amount of time the subcommand took to execute
93 94 95 |
# File 'lib/mixlib/shellout.rb', line 93 def execution_time @execution_time end |
#group ⇒ Object
Group the command will run as. Normally set via options passed to new
46 47 48 |
# File 'lib/mixlib/shellout.rb', line 46 def group @group end |
#input ⇒ Object
ShellOut will push data from :input down the stdin of the subprocss. Normally set via options passed to new. Default: nil
66 67 68 |
# File 'lib/mixlib/shellout.rb', line 66 def input @input end |
#live_stderr ⇒ Object
When live_stderr is set, the stderr of the subprocess will be copied to it as the subprocess is running.
61 62 63 |
# File 'lib/mixlib/shellout.rb', line 61 def live_stderr @live_stderr end |
#live_stdout ⇒ Object
When live_stdout is set, the stdout of the subprocess will be copied to it as the subprocess is running.
57 58 59 |
# File 'lib/mixlib/shellout.rb', line 57 def live_stdout @live_stdout end |
#log_level ⇒ Object
The log level at which ShellOut should log.
73 74 75 |
# File 'lib/mixlib/shellout.rb', line 73 def log_level @log_level end |
#log_tag ⇒ Object
A string which will be prepended to the log message.
76 77 78 |
# File 'lib/mixlib/shellout.rb', line 76 def log_tag @log_tag end |
#logger ⇒ Object
If a logger is set, ShellOut will log a message before it executes the command.
70 71 72 |
# File 'lib/mixlib/shellout.rb', line 70 def logger @logger end |
#password ⇒ Object
Returns the value of attribute password.
42 43 44 |
# File 'lib/mixlib/shellout.rb', line 42 def password @password end |
#process_status_pipe ⇒ Object (readonly)
Returns the value of attribute process_status_pipe.
105 106 107 |
# File 'lib/mixlib/shellout.rb', line 105 def process_status_pipe @process_status_pipe end |
#status ⇒ Object (readonly)
A Process::Status (or ducktype) object collected when the subprocess is reaped.
103 104 105 |
# File 'lib/mixlib/shellout.rb', line 103 def status @status end |
#stderr ⇒ Object (readonly)
Data written to stderr by the subprocess
99 100 101 |
# File 'lib/mixlib/shellout.rb', line 99 def stderr @stderr end |
#stderr_pipe ⇒ Object (readonly)
Returns the value of attribute stderr_pipe.
105 106 107 |
# File 'lib/mixlib/shellout.rb', line 105 def stderr_pipe @stderr_pipe end |
#stdin_pipe ⇒ Object (readonly)
Returns the value of attribute stdin_pipe.
105 106 107 |
# File 'lib/mixlib/shellout.rb', line 105 def stdin_pipe @stdin_pipe end |
#stdout ⇒ Object (readonly)
Data written to stdout by the subprocess
96 97 98 |
# File 'lib/mixlib/shellout.rb', line 96 def stdout @stdout end |
#stdout_pipe ⇒ Object (readonly)
Returns the value of attribute stdout_pipe.
105 106 107 |
# File 'lib/mixlib/shellout.rb', line 105 def stdout_pipe @stdout_pipe end |
#timeout ⇒ Object
207 208 209 |
# File 'lib/mixlib/shellout.rb', line 207 def timeout @timeout || DEFAULT_READ_TIMEOUT end |
#umask ⇒ Object
The umask that will be set for the subcommand.
82 83 84 |
# File 'lib/mixlib/shellout.rb', line 82 def umask @umask end |
#user ⇒ Object
User the command will run as. Normally set via options passed to new
40 41 42 |
# File 'lib/mixlib/shellout.rb', line 40 def user @user end |
#valid_exit_codes ⇒ Object
An Array of acceptable exit codes. #error? (and #error!) use this list to determine if the command was successful. Normally set via options to new
53 54 55 |
# File 'lib/mixlib/shellout.rb', line 53 def valid_exit_codes @valid_exit_codes end |
#with_logon ⇒ Object
Returns the value of attribute with_logon.
43 44 45 |
# File 'lib/mixlib/shellout.rb', line 43 def with_logon @with_logon end |
Instance Method Details
#error! ⇒ Object
If #error? is true, calls invalid!, which raises an Exception.
Returns
- nil:
-
always returns nil when it does not raise
Raises
- ::ShellCommandFailed:
-
via
invalid!
264 265 266 |
# File 'lib/mixlib/shellout.rb', line 264 def error! invalid!("Expected process to exit with #{valid_exit_codes.inspect}, but received '#{exitstatus}'") if error? end |
#error? ⇒ Boolean
Checks the exitstatus against the set of valid_exit_codes.
Returns
true if exitstatus is not in the list of valid_exit_codes, false otherwise.
255 256 257 |
# File 'lib/mixlib/shellout.rb', line 255 def error? !Array(valid_exit_codes).include?(exitstatus) end |
#exitstatus ⇒ Object
The exit status of the subprocess. Will be nil if the command is still running or died without setting an exit status (e.g., terminated by ‘kill -9`).
228 229 230 |
# File 'lib/mixlib/shellout.rb', line 228 def exitstatus @status && @status.exitstatus end |
#format_for_exception ⇒ Object
Creates a String showing the output of the command, including a banner showing the exact command executed. Used by invalid! to show command results when the command exited with an unexpected status.
214 215 216 217 218 219 220 221 222 223 |
# File 'lib/mixlib/shellout.rb', line 214 def format_for_exception msg = "" msg << "#{@terminate_reason}\n" if @terminate_reason msg << "---- Begin output of #{command} ----\n" msg << "STDOUT: #{stdout.strip}\n" msg << "STDERR: #{stderr.strip}\n" msg << "---- End output of #{command} ----\n" msg << "Ran #{command} returned #{status.exitstatus}" if status msg end |
#gid ⇒ Object
The gid that the subprocess will switch to. If the group attribute is given as a group name, it is converted to a gid by Etc.getgrnam
202 203 204 205 |
# File 'lib/mixlib/shellout.rb', line 202 def gid return nil unless group group.kind_of?(Integer) ? group : Etc.getgrnam(group.to_s).gid end |
#inspect ⇒ Object
281 282 283 284 285 |
# File 'lib/mixlib/shellout.rb', line 281 def inspect "<#{self.class.name}##{object_id}: command: '#@command' process_status: #{@status.inspect} " + "stdout: '#{stdout.strip}' stderr: '#{stderr.strip}' child_pid: #{@child_pid.inspect} " + "environment: #{@environment.inspect} timeout: #{timeout} user: #@user group: #@group working_dir: #@cwd >" end |
#invalid!(msg = nil) ⇒ Object
Raises a ShellCommandFailed exception, appending the command’s stdout, stderr, and exitstatus to the exception message.
Arguments
msg: A String to use as the basis of the exception message. The default explanation is very generic, providing a more informative message is highly encouraged.
Raises
ShellCommandFailed always
276 277 278 279 |
# File 'lib/mixlib/shellout.rb', line 276 def invalid!(msg=nil) msg ||= "Command produced unexpected results" raise ShellCommandFailed, msg + "\n" + format_for_exception end |
#live_stream ⇒ Object
Returns the stream that both is being used by both live_stdout and live_stderr, or nil
176 177 178 |
# File 'lib/mixlib/shellout.rb', line 176 def live_stream live_stdout == live_stderr ? live_stdout : nil end |
#live_stream=(stream) ⇒ Object
A shortcut for setting both live_stdout and live_stderr, so that both the stdout and stderr from the subprocess will be copied to the same stream as the subprocess is running.
183 184 185 |
# File 'lib/mixlib/shellout.rb', line 183 def live_stream=(stream) @live_stdout = @live_stderr = stream end |
#run_command ⇒ Object
Run the command, writing the command’s standard out and standard error to stdout and stderr, and saving its exit status object to status
Returns
returns self; stdout, stderr, status, and exitstatus will be populated with results of the command
Raises
-
Errno::EACCES when you are not privileged to execute the command
-
Errno::ENOENT when the command is not available on the system (or not in the current $PATH)
-
CommandTimeout when the command does not complete within
timeoutseconds (default: 600s)
243 244 245 246 247 248 249 |
# File 'lib/mixlib/shellout.rb', line 243 def run_command if logger = (log_tag.nil? ? "" : "#@log_tag ") << "sh(#@command)" logger.send(log_level, ) end super end |
#uid ⇒ Object
The uid that the subprocess will switch to. If the user attribute was given as a username, it is converted to a uid by Etc.getpwnam
195 196 197 198 |
# File 'lib/mixlib/shellout.rb', line 195 def uid return nil unless user user.kind_of?(Integer) ? user : Etc.getpwnam(user.to_s).uid end |