mixlib-shellout 3.0.9-universal-mingw32 → 3.1.6-universal-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bccf795560a590295f3efb38b5febff8d1a949809cbd399f8610d14a51f56aa
4
- data.tar.gz: e223541817b4f3c367b75ea1d4dfe52ba1036734785e60f937aad283b575d32d
3
+ metadata.gz: dceb80e3fced860900c612e990a7dcec95a3bbc940520fbe984407f6989cf795
4
+ data.tar.gz: 7250e65e3ed3ccb0c157563daef66d6cab98f04162fab1e2a6f8984f7cc16f06
5
5
  SHA512:
6
- metadata.gz: 6e20eac99960f5a53cc7626bc0e8d8595e61058488d0aff1dfbbecbed8bca74277b1c342a64784624ff027d63c80c68cfe231ff6a5e5b2ff608ae1cdde045b06
7
- data.tar.gz: 58ab5e2fb4911c5a7d3bab6a7a5d314270351a355601d9971382a8bbc321885f92223983e3850e259b701f90d2ef584d88f0a14e8f36cf3a80e5bf00e95d5b1b
6
+ metadata.gz: 509f7ab8d7abb0edc51ac6e7bf46e503c03ffc3a6b5ba112c6c5e81bbf85d9af7a52a1217985d409903e7cf16442e118609cee0a99fd44fefcee0c64ce8c4ac1
7
+ data.tar.gz: f7b814ff519e2d5836d9b554bd33b0bf0882a4f8627521d0673ea9efd195be5899e73fb0db90fe0505741b153b2a194320367d0b973d14c8e55c78dfe920376d
@@ -16,8 +16,8 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- require "etc"
20
- require "tmpdir"
19
+ require "etc" unless defined?(Etc)
20
+ require "tmpdir" unless defined?(Dir.mktmpdir)
21
21
  require "fcntl"
22
22
  require_relative "shellout/exceptions"
23
23
 
@@ -65,7 +65,7 @@ module Mixlib
65
65
  # as the subprocess is running.
66
66
  attr_accessor :live_stderr
67
67
 
68
- # ShellOut will push data from :input down the stdin of the subprocss.
68
+ # ShellOut will push data from :input down the stdin of the subprocess.
69
69
  # Normally set via options passed to new.
70
70
  # Default: nil
71
71
  attr_accessor :input
@@ -122,7 +122,7 @@ module Mixlib
122
122
  # === Options:
123
123
  # If the last argument is a Hash, it is removed from the list of args passed
124
124
  # to exec and used as an options hash. The following options are available:
125
- # * +user+: the user the commmand should run as. if an integer is given, it is
125
+ # * +user+: the user the command should run as. if an integer is given, it is
126
126
  # used as a uid. A string is treated as a username and resolved to a uid
127
127
  # with Etc.getpwnam
128
128
  # * +group+: the group the command should run as. works similarly to +user+
@@ -248,7 +248,7 @@ module Mixlib
248
248
  # running or died without setting an exit status (e.g., terminated by
249
249
  # `kill -9`).
250
250
  def exitstatus
251
- @status && @status.exitstatus
251
+ @status&.exitstatus
252
252
  end
253
253
 
254
254
  # Run the command, writing the command's standard out and standard error
@@ -0,0 +1,197 @@
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
+ require_relative "../shellout"
19
+ require "chef-utils" unless defined?(ChefUtils)
20
+ require "chef-utils/dsl/default_paths"
21
+ require "chef-utils/internal"
22
+
23
+ module Mixlib
24
+ class ShellOut
25
+ module Helper
26
+ include ChefUtils::Internal
27
+ include ChefUtils::DSL::DefaultPaths
28
+
29
+ #
30
+ # These APIs are considered public for use in ohai and chef (by cookbooks and plugins, etc)
31
+ # but are considered private/experimental for now for the direct users of mixlib-shellout.
32
+ #
33
+ # You can see an example of how to handle the "dependency injection" in the rspec unit test.
34
+ # That backend API is left deliberately undocumented for now and may not follow SemVer and may
35
+ # break at any time (at least for the rest of 2020).
36
+ #
37
+
38
+ def shell_out(*args, **options)
39
+ options = options.dup
40
+ options = __maybe_add_timeout(self, options)
41
+ if options.empty?
42
+ shell_out_compacted(*__clean_array(*args))
43
+ else
44
+ shell_out_compacted(*__clean_array(*args), **options)
45
+ end
46
+ end
47
+
48
+ def shell_out!(*args, **options)
49
+ options = options.dup
50
+ options = __maybe_add_timeout(self, options)
51
+ if options.empty?
52
+ shell_out_compacted!(*__clean_array(*args))
53
+ else
54
+ shell_out_compacted!(*__clean_array(*args), **options)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # helper sugar for resources that support passing timeouts to shell_out
61
+ #
62
+ # module method to not pollute namespaces, but that means we need self injected as an arg
63
+ # @api private
64
+ def __maybe_add_timeout(obj, options)
65
+ options = options.dup
66
+ # historically resources have not properly declared defaults on their timeouts, so a default default of 900s was enforced here
67
+ default_val = 900
68
+ return options if options.key?(:timeout)
69
+
70
+ # FIXME: need to nuke descendent tracker out of Chef::Provider so we can just define that class here without requiring the
71
+ # world, and then just use symbol lookup
72
+ if obj.class.ancestors.map(&:name).include?("Chef::Provider") && obj.respond_to?(:new_resource) && obj.new_resource.respond_to?(:timeout) && !options.key?(:timeout)
73
+ options[:timeout] = obj.new_resource.timeout ? obj.new_resource.timeout.to_f : default_val
74
+ end
75
+ options
76
+ end
77
+
78
+ # helper function to mangle options when `default_env` is true
79
+ #
80
+ # @api private
81
+ def __apply_default_env(options)
82
+ options = options.dup
83
+ default_env = options.delete(:default_env)
84
+ default_env = true if default_env.nil?
85
+ if default_env
86
+ env_key = options.key?(:env) ? :env : :environment
87
+ options[env_key] = {
88
+ "LC_ALL" => __config[:internal_locale],
89
+ "LANGUAGE" => __config[:internal_locale],
90
+ "LANG" => __config[:internal_locale],
91
+ __env_path_name => default_paths,
92
+ }.update(options[env_key] || {})
93
+ end
94
+ options
95
+ end
96
+
97
+ # The shell_out_compacted/shell_out_compacted! APIs are private but are intended for use
98
+ # in rspec tests. They should always be used in rspec tests instead of shell_out to allow
99
+ # for less brittle rspec tests.
100
+ #
101
+ # This expectation:
102
+ #
103
+ # allow(provider).to receive(:shell_out_compacted!).with("foo", "bar", "baz")
104
+ #
105
+ # Is met by many different possible calling conventions that mean the same thing:
106
+ #
107
+ # provider.shell_out!("foo", [ "bar", nil, "baz"])
108
+ # provider.shell_out!(["foo", nil, "bar" ], ["baz"])
109
+ #
110
+ # Note that when setting `default_env: false` that you should just setup an expectation on
111
+ # :shell_out_compacted for `default_env: false`, rather than the expanded env settings so
112
+ # that the default_env implementation can change without breaking unit tests.
113
+ #
114
+ def shell_out_compacted(*args, **options)
115
+ options = __apply_default_env(options)
116
+ if options.empty?
117
+ __shell_out_command(*args)
118
+ else
119
+ __shell_out_command(*args, **options)
120
+ end
121
+ end
122
+
123
+ def shell_out_compacted!(*args, **options)
124
+ options = __apply_default_env(options)
125
+ cmd = if options.empty?
126
+ __shell_out_command(*args)
127
+ else
128
+ __shell_out_command(*args, **options)
129
+ end
130
+ cmd.error!
131
+ cmd
132
+ end
133
+
134
+ # Helper for subclasses to reject nil out of an array. It allows using the array form of
135
+ # shell_out (which avoids the need to surround arguments with quote marks to deal with shells).
136
+ #
137
+ # @param args [String] variable number of string arguments
138
+ # @return [Array] array of strings with nil and null string rejection
139
+ #
140
+ def __clean_array(*args)
141
+ args.flatten.compact.map(&:to_s)
142
+ end
143
+
144
+ def __shell_out_command(*args, **options)
145
+ if __transport_connection
146
+ FakeShellOut.new(args, options, __transport_connection.run_command(args.join(" "))) # FIXME: train should accept run_command(*args)
147
+ else
148
+ cmd = if options.empty?
149
+ Mixlib::ShellOut.new(*args)
150
+ else
151
+ Mixlib::ShellOut.new(*args, **options)
152
+ end
153
+ cmd.live_stream ||= __io_for_live_stream
154
+ cmd.run_command
155
+ cmd
156
+ end
157
+ end
158
+
159
+ def __io_for_live_stream
160
+ if !STDOUT.closed? && __log.trace?
161
+ STDOUT
162
+ else
163
+ nil
164
+ end
165
+ end
166
+
167
+ def __env_path_name
168
+ if ChefUtils.windows?
169
+ "Path"
170
+ else
171
+ "PATH"
172
+ end
173
+ end
174
+
175
+ class FakeShellOut
176
+ attr_reader :stdout, :stderr, :exitstatus, :status
177
+
178
+ def initialize(args, options, result)
179
+ @args = args
180
+ @options = options
181
+ @stdout = result.stdout
182
+ @stderr = result.stderr
183
+ @exitstatus = result.exit_status
184
+ @status = OpenStruct.new(success?: ( exitstatus == 0 ))
185
+ end
186
+
187
+ def error?
188
+ exitstatus != 0
189
+ end
190
+
191
+ def error!
192
+ raise Mixlib::ShellOut::ShellCommandFailed, "Unexpected exit status of #{exitstatus} running #{@args}" if error?
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -370,11 +370,11 @@ module Mixlib
370
370
  return if attempt_reap
371
371
 
372
372
  @terminate_reason = "Command exceeded allowed execution time, process terminated"
373
- logger.error("Command exceeded allowed execution time, sending TERM") if logger
373
+ logger&.error("Command exceeded allowed execution time, sending TERM")
374
374
  Process.kill(:TERM, child_pgid)
375
375
  sleep 3
376
376
  attempt_reap
377
- logger.error("Command exceeded allowed execution time, sending KILL") if logger
377
+ logger&.error("Command exceeded allowed execution time, sending KILL")
378
378
  Process.kill(:KILL, child_pgid)
379
379
  reap
380
380
 
@@ -1,5 +1,5 @@
1
1
  module Mixlib
2
2
  class ShellOut
3
- VERSION = "3.0.9".freeze
3
+ VERSION = "3.1.6".freeze
4
4
  end
5
5
  end
@@ -89,7 +89,7 @@ module Mixlib
89
89
  # Start the process
90
90
  #
91
91
  process, profile, token = Process.create3(create_process_args)
92
- logger.debug(format_process(process, app_name, command_line, timeout)) if logger
92
+ logger&.debug(format_process(process, app_name, command_line, timeout))
93
93
  begin
94
94
  # Start pushing data into input
95
95
  stdin_write << input if input
@@ -124,7 +124,7 @@ module Mixlib
124
124
  kill_process_tree(process.process_id, wmi, logger)
125
125
  Process.kill(:KILL, process.process_id)
126
126
  rescue SystemCallError
127
- logger.warn("Failed to kill timed out process #{process.process_id}") if logger
127
+ logger&.warn("Failed to kill timed out process #{process.process_id}")
128
128
  end
129
129
 
130
130
  raise Mixlib::ShellOut::CommandTimeout, [
@@ -208,7 +208,7 @@ module Mixlib
208
208
  # 4. if the argument must be quoted by #1 and terminates in a sequence of backslashes then all the backlashes must themselves
209
209
  # be backslash excaped (double the backslashes).
210
210
  # 5. if an interior quote that must be escaped by #2 has a sequence of backslashes before it then all the backslashes must
211
- # themselves be backslash excaped along with the backslash ecape of the interior quote (double plus one backslashes).
211
+ # themselves be backslash excaped along with the backslash escape of the interior quote (double plus one backslashes).
212
212
  #
213
213
  # And to restate. We are constructing a string which will be parsed by the windows parser into arguments, and we want those
214
214
  # arguments to match the *args array we are passed here. So call the windows parser operation A then we need to apply A^-1 to
@@ -398,20 +398,16 @@ module Mixlib
398
398
 
399
399
  def kill_process(instance, logger)
400
400
  child_pid = instance.wmi_ole_object.processid
401
- if logger
402
- logger.debug([
401
+ logger&.debug([
403
402
  "killing child process #{child_pid}::",
404
403
  "#{instance.wmi_ole_object.Name} of parent #{pid}",
405
404
  ].join)
406
- end
407
405
  Process.kill(:KILL, instance.wmi_ole_object.processid)
408
406
  rescue SystemCallError
409
- if logger
410
- logger.debug([
407
+ logger&.debug([
411
408
  "Failed to kill child process #{child_pid}::",
412
409
  "#{instance.wmi_ole_object.Name} of parent #{pid}",
413
410
  ].join)
414
- end
415
411
  end
416
412
 
417
413
  def format_process(process, app_name, command_line, timeout)
@@ -21,7 +21,6 @@ require "win32/process"
21
21
 
22
22
  # Add new constants for Logon
23
23
  module Process::Constants
24
- private
25
24
 
26
25
  LOGON32_LOGON_INTERACTIVE = 0x00000002
27
26
  LOGON32_LOGON_BATCH = 0x00000004
@@ -148,15 +147,13 @@ module Process
148
147
  si_hash = {}
149
148
 
150
149
  # If the startup_info key is present, validate its subkeys
151
- if hash["startup_info"]
152
- hash["startup_info"].each do |key, val|
153
- key = key.to_s.downcase
154
- unless valid_si_keys.include?(key)
155
- raise ArgumentError, "invalid startup_info key '#{key}'"
156
- end
157
-
158
- si_hash[key] = val
150
+ hash["startup_info"]&.each do |key, val|
151
+ key = key.to_s.downcase
152
+ unless valid_si_keys.include?(key)
153
+ raise ArgumentError, "invalid startup_info key '#{key}'"
159
154
  end
155
+
156
+ si_hash[key] = val
160
157
  end
161
158
 
162
159
  # The +command_line+ key is mandatory unless the +app_name+ key
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixlib-shellout
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.9
4
+ version: 3.1.6
5
5
  platform: universal-mingw32
6
6
  authors:
7
7
  - Chef Software Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-30 00:00:00.000000000 Z
11
+ date: 2020-09-10 00:00:00.000000000 Z
12
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'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: win32-process
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -47,6 +61,7 @@ files:
47
61
  - LICENSE
48
62
  - lib/mixlib/shellout.rb
49
63
  - lib/mixlib/shellout/exceptions.rb
64
+ - lib/mixlib/shellout/helper.rb
50
65
  - lib/mixlib/shellout/unix.rb
51
66
  - lib/mixlib/shellout/version.rb
52
67
  - lib/mixlib/shellout/windows.rb
@@ -62,7 +77,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
62
77
  requirements:
63
78
  - - ">="
64
79
  - !ruby/object:Gem::Version
65
- version: '2.2'
80
+ version: '2.4'
66
81
  required_rubygems_version: !ruby/object:Gem::Requirement
67
82
  requirements:
68
83
  - - ">="