mixlib-shellout 3.2.7-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,373 @@
1
+ #--
2
+ # Author:: Daniel DeLeo (<dan@chef.io>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "etc" unless defined?(Etc)
20
+ require "tmpdir" unless defined?(Dir.mktmpdir)
21
+ require "fcntl"
22
+ require_relative "shellout/exceptions"
23
+
24
+ module Mixlib
25
+
26
+ class ShellOut
27
+ READ_WAIT_TIME = 0.01
28
+ READ_SIZE = 4096
29
+ DEFAULT_READ_TIMEOUT = 600
30
+
31
+ if RUBY_PLATFORM =~ /mswin|mingw|windows/
32
+ require_relative "shellout/windows"
33
+ include ShellOut::Windows
34
+ else
35
+ require_relative "shellout/unix"
36
+ include ShellOut::Unix
37
+ end
38
+
39
+ # User the command will run as. Normally set via options passed to new
40
+ attr_accessor :user
41
+ attr_accessor :domain
42
+ attr_accessor :password
43
+ # TODO remove
44
+ attr_accessor :with_logon
45
+
46
+ # Whether to simulate logon as the user. Normally set via options passed to new
47
+ # Always enabled on windows
48
+ attr_accessor :login
49
+
50
+ # Group the command will run as. Normally set via options passed to new
51
+ attr_accessor :group
52
+
53
+ # Working directory for the subprocess. Normally set via options to new
54
+ attr_accessor :cwd
55
+
56
+ # An Array of acceptable exit codes. #error? (and #error!) use this list
57
+ # to determine if the command was successful. Normally set via options to new
58
+ attr_accessor :valid_exit_codes
59
+
60
+ # When live_stdout is set, the stdout of the subprocess will be copied to it
61
+ # as the subprocess is running.
62
+ attr_accessor :live_stdout
63
+
64
+ # When live_stderr is set, the stderr of the subprocess will be copied to it
65
+ # as the subprocess is running.
66
+ attr_accessor :live_stderr
67
+
68
+ # ShellOut will push data from :input down the stdin of the subprocess.
69
+ # Normally set via options passed to new.
70
+ # Default: nil
71
+ attr_accessor :input
72
+
73
+ # If a logger is set, ShellOut will log a message before it executes the
74
+ # command.
75
+ attr_accessor :logger
76
+
77
+ # The log level at which ShellOut should log.
78
+ attr_accessor :log_level
79
+
80
+ # A string which will be prepended to the log message.
81
+ attr_accessor :log_tag
82
+
83
+ # The command to be executed.
84
+ attr_reader :command
85
+
86
+ # The umask that will be set for the subcommand.
87
+ attr_reader :umask
88
+
89
+ # Environment variables that will be set for the subcommand. Refer to the
90
+ # documentation of new to understand how ShellOut interprets this.
91
+ attr_accessor :environment
92
+
93
+ # The maximum time this command is allowed to run. Usually set via options
94
+ # to new
95
+ attr_writer :timeout
96
+
97
+ # The amount of time the subcommand took to execute
98
+ attr_reader :execution_time
99
+
100
+ # Data written to stdout by the subprocess
101
+ attr_reader :stdout
102
+
103
+ # Data written to stderr by the subprocess
104
+ attr_reader :stderr
105
+
106
+ # A Process::Status (or ducktype) object collected when the subprocess is
107
+ # reaped.
108
+ attr_reader :status
109
+
110
+ attr_reader :stdin_pipe, :stdout_pipe, :stderr_pipe, :process_status_pipe
111
+
112
+ # Runs windows process with elevated privileges. Required for Powershell commands which need elevated privileges
113
+ attr_accessor :elevated
114
+
115
+ attr_accessor :sensitive
116
+
117
+ # === Arguments:
118
+ # Takes a single command, or a list of command fragments. These are used
119
+ # as arguments to Kernel.exec. See the Kernel.exec documentation for more
120
+ # explanation of how arguments are evaluated. The last argument can be an
121
+ # options Hash.
122
+ # === Options:
123
+ # If the last argument is a Hash, it is removed from the list of args passed
124
+ # to exec and used as an options hash. The following options are available:
125
+ # * +user+: the user the command should run as. if an integer is given, it is
126
+ # used as a uid. A string is treated as a username and resolved to a uid
127
+ # with Etc.getpwnam
128
+ # * +group+: the group the command should run as. works similarly to +user+
129
+ # * +cwd+: the directory to chdir to before running the command
130
+ # * +umask+: a umask to set before running the command. If given as an Integer,
131
+ # be sure to use two leading zeros so it's parsed as Octal. A string will
132
+ # be treated as an octal integer
133
+ # * +returns+: one or more Integer values to use as valid exit codes for the
134
+ # subprocess. This only has an effect if you call +error!+ after
135
+ # +run_command+.
136
+ # * +environment+: a Hash of environment variables to set before the command
137
+ # is run.
138
+ # * +timeout+: a Numeric value for the number of seconds to wait on the
139
+ # child process before raising an Exception. This is calculated as the
140
+ # total amount of time that ShellOut waited on the child process without
141
+ # receiving any output (i.e., IO.select returned nil). Default is 600
142
+ # seconds. Note: the stdlib Timeout library is not used.
143
+ # * +input+: A String of data to be passed to the subcommand. This is
144
+ # written to the child process' stdin stream before the process is
145
+ # launched. The child's stdin stream will be a pipe, so the size of input
146
+ # data should not exceed the system's default pipe capacity (4096 bytes
147
+ # is a safe value, though on newer Linux systems the capacity is 64k by
148
+ # default).
149
+ # * +live_stream+: An IO or Logger-like object (must respond to the append
150
+ # operator +<<+) that will receive data as ShellOut reads it from the
151
+ # child process. Generally this is used to copy data from the child to
152
+ # the parent's stdout so that users may observe the progress of
153
+ # long-running commands.
154
+ # * +login+: Whether to simulate a login (set secondary groups, primary group, environment
155
+ # variables etc) as done by the OS in an actual login
156
+ # === Examples:
157
+ # Invoke find(1) to search for .rb files:
158
+ # find = Mixlib::ShellOut.new("find . -name '*.rb'")
159
+ # find.run_command
160
+ # # If all went well, the results are on +stdout+
161
+ # puts find.stdout
162
+ # # find(1) prints diagnostic info to STDERR:
163
+ # puts "error messages" + find.stderr
164
+ # # Raise an exception if it didn't exit with 0
165
+ # find.error!
166
+ # Run a command as the +www+ user with no extra ENV settings from +/tmp+
167
+ # cmd = Mixlib::ShellOut.new("apachectl", "start", :user => 'www', :env => nil, :cwd => '/tmp')
168
+ # cmd.run_command # etc.
169
+ def initialize(*command_args)
170
+ @stdout, @stderr, @process_status = "", "", ""
171
+ @live_stdout = @live_stderr = nil
172
+ @input = nil
173
+ @log_level = :debug
174
+ @log_tag = nil
175
+ @environment = {}
176
+ @cwd = nil
177
+ @valid_exit_codes = [0]
178
+ @terminate_reason = nil
179
+ @timeout = nil
180
+ @elevated = false
181
+ @sensitive = false
182
+
183
+ if command_args.last.is_a?(Hash)
184
+ parse_options(command_args.pop)
185
+ end
186
+
187
+ @command = command_args.size == 1 ? command_args.first : command_args
188
+ end
189
+
190
+ # Returns the stream that both is being used by both live_stdout and live_stderr, or nil
191
+ def live_stream
192
+ live_stdout == live_stderr ? live_stdout : nil
193
+ end
194
+
195
+ # A shortcut for setting both live_stdout and live_stderr, so that both the
196
+ # stdout and stderr from the subprocess will be copied to the same stream as
197
+ # the subprocess is running.
198
+ def live_stream=(stream)
199
+ @live_stdout = @live_stderr = stream
200
+ end
201
+
202
+ # Set the umask that the subprocess will have. If given as a string, it
203
+ # will be converted to an integer by String#oct.
204
+ def umask=(new_umask)
205
+ @umask = (new_umask.respond_to?(:oct) ? new_umask.oct : new_umask.to_i) & 007777
206
+ end
207
+
208
+ # The uid that the subprocess will switch to. If the user attribute was
209
+ # given as a username, it is converted to a uid by Etc.getpwnam
210
+ # TODO migrate to shellout/unix.rb
211
+ def uid
212
+ return nil unless user
213
+
214
+ user.is_a?(Integer) ? user : Etc.getpwnam(user.to_s).uid
215
+ end
216
+
217
+ # The gid that the subprocess will switch to. If the group attribute is
218
+ # given as a group name, it is converted to a gid by Etc.getgrnam
219
+ # TODO migrate to shellout/unix.rb
220
+ def gid
221
+ return group.is_a?(Integer) ? group : Etc.getgrnam(group.to_s).gid if group
222
+ return Etc.getpwuid(uid).gid if using_login?
223
+
224
+ nil
225
+ end
226
+
227
+ def timeout
228
+ @timeout || DEFAULT_READ_TIMEOUT
229
+ end
230
+
231
+ # Creates a String showing the output of the command, including a banner
232
+ # showing the exact command executed. Used by +invalid!+ to show command
233
+ # results when the command exited with an unexpected status.
234
+ def format_for_exception
235
+ return "Command execution failed. STDOUT/STDERR suppressed for sensitive resource" if sensitive
236
+
237
+ msg = ""
238
+ msg << "#{@terminate_reason}\n" if @terminate_reason
239
+ msg << "---- Begin output of #{command} ----\n"
240
+ msg << "STDOUT: #{stdout.strip}\n"
241
+ msg << "STDERR: #{stderr.strip}\n"
242
+ msg << "---- End output of #{command} ----\n"
243
+ msg << "Ran #{command} returned #{status.exitstatus}" if status
244
+ msg
245
+ end
246
+
247
+ # The exit status of the subprocess. Will be nil if the command is still
248
+ # running or died without setting an exit status (e.g., terminated by
249
+ # `kill -9`).
250
+ def exitstatus
251
+ @status&.exitstatus
252
+ end
253
+
254
+ # Run the command, writing the command's standard out and standard error
255
+ # to +stdout+ and +stderr+, and saving its exit status object to +status+
256
+ # === Returns
257
+ # returns +self+; +stdout+, +stderr+, +status+, and +exitstatus+ will be
258
+ # populated with results of the command
259
+ # === Raises
260
+ # * Errno::EACCES when you are not privileged to execute the command
261
+ # * Errno::ENOENT when the command is not available on the system (or not
262
+ # in the current $PATH)
263
+ # * CommandTimeout when the command does not complete
264
+ # within +timeout+ seconds (default: 600s)
265
+ def run_command
266
+ if logger
267
+ log_message = (log_tag.nil? ? "" : "#{@log_tag} ") << "sh(#{@command})"
268
+ logger.send(log_level, log_message)
269
+ end
270
+ super
271
+ end
272
+
273
+ # Checks the +exitstatus+ against the set of +valid_exit_codes+.
274
+ # === Returns
275
+ # +true+ if +exitstatus+ is not in the list of +valid_exit_codes+, false
276
+ # otherwise.
277
+ def error?
278
+ !Array(valid_exit_codes).include?(exitstatus)
279
+ end
280
+
281
+ # If #error? is true, calls +invalid!+, which raises an Exception.
282
+ # === Returns
283
+ # nil::: always returns nil when it does not raise
284
+ # === Raises
285
+ # ::ShellCommandFailed::: via +invalid!+
286
+ def error!
287
+ invalid!("Expected process to exit with #{valid_exit_codes.inspect}, but received '#{exitstatus}'") if error?
288
+ end
289
+
290
+ # Raises a ShellCommandFailed exception, appending the
291
+ # command's stdout, stderr, and exitstatus to the exception message.
292
+ # === Arguments
293
+ # +msg+: A String to use as the basis of the exception message. The
294
+ # default explanation is very generic, providing a more informative message
295
+ # is highly encouraged.
296
+ # === Raises
297
+ # ShellCommandFailed always
298
+ def invalid!(msg = nil)
299
+ msg ||= "Command produced unexpected results"
300
+ raise ShellCommandFailed, msg + "\n" + format_for_exception
301
+ end
302
+
303
+ def inspect
304
+ "<#{self.class.name}##{object_id}: command: '#{@command}' process_status: #{@status.inspect} " +
305
+ "stdout: '#{stdout.strip}' stderr: '#{stderr.strip}' child_pid: #{@child_pid.inspect} " +
306
+ "environment: #{@environment.inspect} timeout: #{timeout} user: #{@user} group: #{@group} working_dir: #{@cwd} >"
307
+ end
308
+
309
+ private
310
+
311
+ def parse_options(opts)
312
+ opts.each do |option, setting|
313
+ case option.to_s
314
+ when "cwd"
315
+ self.cwd = setting
316
+ when "domain"
317
+ self.domain = setting
318
+ when "password"
319
+ self.password = setting
320
+ when "user"
321
+ self.user = setting
322
+ self.with_logon = setting
323
+ when "group"
324
+ self.group = setting
325
+ when "umask"
326
+ self.umask = setting
327
+ when "timeout"
328
+ self.timeout = setting
329
+ when "returns"
330
+ self.valid_exit_codes = Array(setting)
331
+ when "live_stream"
332
+ self.live_stdout = self.live_stderr = setting
333
+ when "live_stdout"
334
+ self.live_stdout = setting
335
+ when "live_stderr"
336
+ self.live_stderr = setting
337
+ when "input"
338
+ self.input = setting
339
+ when "logger"
340
+ self.logger = setting
341
+ when "log_level"
342
+ self.log_level = setting
343
+ when "log_tag"
344
+ self.log_tag = setting
345
+ when "environment", "env"
346
+ if setting
347
+ self.environment = Hash[setting.map { |(k, v)| [k.to_s, v] }]
348
+ else
349
+ self.environment = {}
350
+ end
351
+ when "login"
352
+ self.login = setting
353
+ when "elevated"
354
+ self.elevated = setting
355
+ when "sensitive"
356
+ self.sensitive = setting
357
+ else
358
+ raise InvalidCommandOption, "option '#{option.inspect}' is not a valid option for #{self.class.name}"
359
+ end
360
+ end
361
+
362
+ validate_options(opts)
363
+ end
364
+
365
+ def validate_options(opts)
366
+ if login && !user
367
+ raise InvalidCommandOption, "cannot set login without specifying a user"
368
+ end
369
+
370
+ super
371
+ end
372
+ end
373
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mixlib-shellout
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.2.7
5
+ platform: x64-mingw-ucrt
6
+ authors:
7
+ - Chef Software Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef-utils
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: win32-process
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.9'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: wmi-lite
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ffi-win32-extensions
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.0.3
69
+ description: Run external commands on Unix or Windows
70
+ email: info@chef.io
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - LICENSE
76
+ - lib/mixlib/shellout.rb
77
+ - lib/mixlib/shellout/exceptions.rb
78
+ - lib/mixlib/shellout/helper.rb
79
+ - lib/mixlib/shellout/unix.rb
80
+ - lib/mixlib/shellout/version.rb
81
+ - lib/mixlib/shellout/windows.rb
82
+ - lib/mixlib/shellout/windows/core_ext.rb
83
+ homepage: https://github.com/chef/mixlib-shellout
84
+ licenses:
85
+ - Apache-2.0
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '2.5'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.1.4
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Run external commands on Unix or Windows
106
+ test_files: []