mixlib-shellout 3.0.4-universal-mingw32 → 3.1.2-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: 68567052a253b4c6bba0f3ff4c884402a41dd3175a00a3a4cef1d9fab8ca753a
4
- data.tar.gz: ca9b2511628cb6655397abf24ea39a9d49a7c72f5550708e1daa2fe553328e91
3
+ metadata.gz: ff0d68faea99e58c39edacd851b596bfd5a39d53fb778b9e12da8abb3bab8a46
4
+ data.tar.gz: b9e6f5efb5f63c8767dda3f47b46fac20829dc7bfd6de35c3317d5f02fe98652
5
5
  SHA512:
6
- metadata.gz: 215b9612e24919b285530b202cb3e62ab27436f82fb5cb95efc0bccfc4538794800c57c88a66cfab978479c3718d5b9d5fa40de43833fd05c61a8a769831c571
7
- data.tar.gz: 40458ab0286b067c4811be58fa4ad4c93568f25c5ca036137023690588c0b65e84f2f8dd034e0b0dc1f7070113305a6a262242207cab0eb8f9c53b38ffa125fe
6
+ metadata.gz: ba31783f95a5db34698906f43591e649eb1615e1eee536f94e61f27e87622aed9e1b7714c9c00602d64e529ccd8b9d7db2061525d7142ded0580b6760cbbca28
7
+ data.tar.gz: bdf404d7c0ab0ce145170428388c5a02994cea8088a880fc2a71865896fdc75c9b562bc65eb9131e855dd0bf8190e30a6553c246fb5eb2863723e0f786560ae8
@@ -19,7 +19,7 @@
19
19
  require "etc"
20
20
  require "tmpdir"
21
21
  require "fcntl"
22
- require "mixlib/shellout/exceptions"
22
+ require_relative "shellout/exceptions"
23
23
 
24
24
  module Mixlib
25
25
 
@@ -29,10 +29,10 @@ module Mixlib
29
29
  DEFAULT_READ_TIMEOUT = 600
30
30
 
31
31
  if RUBY_PLATFORM =~ /mswin|mingw32|windows/
32
- require "mixlib/shellout/windows"
32
+ require_relative "shellout/windows"
33
33
  include ShellOut::Windows
34
34
  else
35
- require "mixlib/shellout/unix"
35
+ require_relative "shellout/unix"
36
36
  include ShellOut::Unix
37
37
  end
38
38
 
@@ -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
@@ -210,15 +210,17 @@ module Mixlib
210
210
  # TODO migrate to shellout/unix.rb
211
211
  def uid
212
212
  return nil unless user
213
- user.kind_of?(Integer) ? user : Etc.getpwnam(user.to_s).uid
213
+
214
+ user.is_a?(Integer) ? user : Etc.getpwnam(user.to_s).uid
214
215
  end
215
216
 
216
217
  # The gid that the subprocess will switch to. If the group attribute is
217
218
  # given as a group name, it is converted to a gid by Etc.getgrnam
218
219
  # TODO migrate to shellout/unix.rb
219
220
  def gid
220
- return group.kind_of?(Integer) ? group : Etc.getgrnam(group.to_s).gid if group
221
+ return group.is_a?(Integer) ? group : Etc.getgrnam(group.to_s).gid if group
221
222
  return Etc.getpwuid(uid).gid if using_login?
223
+
222
224
  nil
223
225
  end
224
226
 
@@ -231,6 +233,7 @@ module Mixlib
231
233
  # results when the command exited with an unexpected status.
232
234
  def format_for_exception
233
235
  return "Command execution failed. STDOUT/STDERR suppressed for sensitive resource" if sensitive
236
+
234
237
  msg = ""
235
238
  msg << "#{@terminate_reason}\n" if @terminate_reason
236
239
  msg << "---- Begin output of #{command} ----\n"
@@ -363,6 +366,7 @@ module Mixlib
363
366
  if login && !user
364
367
  raise InvalidCommandOption, "cannot set login without specifying a user"
365
368
  end
369
+
366
370
  super
367
371
  end
368
372
  end
@@ -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"
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 "dependenecy 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.tty? && !__config[:daemon] && __log.debug?
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
@@ -53,14 +53,16 @@ module Mixlib
53
53
  # to the user's secondary groups
54
54
  def sgids
55
55
  return nil unless using_login?
56
+
56
57
  user_name = Etc.getpwuid(uid).name
57
- all_seconderies.select { |g| g.mem.include?(user_name) }.map { |g| g.gid }
58
+ all_seconderies.select { |g| g.mem.include?(user_name) }.map(&:gid)
58
59
  end
59
60
 
60
61
  # The environment variables that are deduced from simulating logon
61
62
  # Only valid if login is used
62
63
  def logon_environment
63
64
  return {} unless using_login?
65
+
64
66
  entry = Etc.getpwuid(uid)
65
67
  # According to `man su`, the set fields are:
66
68
  # $HOME, $SHELL, $USER, $LOGNAME, $PATH, and $IFS
@@ -269,6 +271,7 @@ module Mixlib
269
271
  # Keep this unbuffered for now
270
272
  def write_to_child_stdin
271
273
  return unless input
274
+
272
275
  child_stdin << input
273
276
  child_stdin.close # Kick things off
274
277
  end
@@ -337,7 +340,7 @@ module Mixlib
337
340
  set_cwd
338
341
 
339
342
  begin
340
- command.kind_of?(Array) ? exec(*command, close_others: true) : exec(command, close_others: true)
343
+ command.is_a?(Array) ? exec(*command, close_others: true) : exec(command, close_others: true)
341
344
 
342
345
  raise "forty-two" # Should never get here
343
346
  rescue Exception => e
@@ -365,6 +368,7 @@ module Mixlib
365
368
 
366
369
  def reap_errant_child
367
370
  return if attempt_reap
371
+
368
372
  @terminate_reason = "Command exceeded allowed execution time, process terminated"
369
373
  logger.error("Command exceeded allowed execution time, sending TERM") if logger
370
374
  Process.kill(:TERM, child_pgid)
@@ -1,5 +1,5 @@
1
1
  module Mixlib
2
2
  class ShellOut
3
- VERSION = "3.0.4".freeze
3
+ VERSION = "3.1.2".freeze
4
4
  end
5
5
  end
@@ -19,7 +19,7 @@
19
19
  #
20
20
 
21
21
  require "win32/process"
22
- require "mixlib/shellout/windows/core_ext"
22
+ require_relative "windows/core_ext"
23
23
 
24
24
  module Mixlib
25
25
  class ShellOut
@@ -88,7 +88,7 @@ module Mixlib
88
88
  #
89
89
  # Start the process
90
90
  #
91
- process, profile, token = Process.create(create_process_args)
91
+ process, profile, token = Process.create3(create_process_args)
92
92
  logger.debug(format_process(process, app_name, command_line, timeout)) if logger
93
93
  begin
94
94
  # Start pushing data into input
@@ -110,6 +110,7 @@ module Mixlib
110
110
  unless GetExitCodeProcess(process.process_handle, exit_code)
111
111
  raise get_last_error
112
112
  end
113
+
113
114
  @status = ThingThatLooksSortOfLikeAProcessStatus.new
114
115
  @status.exitstatus = exit_code.unpack("l").first
115
116
 
@@ -170,8 +171,9 @@ module Mixlib
170
171
 
171
172
  def consume_output(open_streams, stdout_read, stderr_read)
172
173
  return false if open_streams.length == 0
174
+
173
175
  ready = IO.select(open_streams, nil, nil, READ_WAIT_TIME)
174
- return true if ! ready
176
+ return true unless ready
175
177
 
176
178
  if ready.first.include?(stdout_read)
177
179
  begin
@@ -227,6 +229,7 @@ module Mixlib
227
229
  # @return String
228
230
  def combine_args(*args)
229
231
  return args[0] if args.length == 1
232
+
230
233
  args.map do |arg|
231
234
  if arg =~ /[ \t\n\v"]/
232
235
  arg = arg.gsub(/(\\*)"/, '\1\1\"') # interior quotes with N preceeding backslashes need 2N+1 backslashes
@@ -321,10 +324,12 @@ module Mixlib
321
324
  return true unless quote
322
325
  when "%"
323
326
  return true if env
327
+
324
328
  env = env_first_char = true
325
329
  next
326
330
  else
327
331
  next unless env
332
+
328
333
  if env_first_char
329
334
  env_first_char = false
330
335
  (env = false) && next if c !~ /[A-Za-z_]/
@@ -370,6 +375,7 @@ module Mixlib
370
375
 
371
376
  def unsafe_process?(name, logger)
372
377
  return false unless system_required_processes.include? name
378
+
373
379
  logger.debug(
374
380
  "A request to kill a critical system process - #{name} - was received and skipped."
375
381
  )
@@ -383,6 +389,7 @@ module Mixlib
383
389
  def kill_process_tree(pid, wmi, logger)
384
390
  wmi.query("select * from Win32_Process where ParentProcessID=#{pid}").each do |instance|
385
391
  next if unsafe_process?(instance.wmi_ole_object.name, logger)
392
+
386
393
  child_pid = instance.wmi_ole_object.processid
387
394
  kill_process_tree(child_pid, wmi, logger)
388
395
  kill_process(instance, logger)
@@ -73,19 +73,19 @@ module Process::Functions
73
73
  [:pointer], :bool
74
74
 
75
75
  attach_pfunc :LoadUserProfileW,
76
- [:handle, :pointer], :bool
76
+ %i{handle pointer}, :bool
77
77
 
78
78
  attach_pfunc :UnloadUserProfile,
79
- [:handle, :handle], :bool
79
+ %i{handle handle}, :bool
80
80
 
81
81
  ffi_lib :advapi32
82
82
 
83
83
  attach_pfunc :LogonUserW,
84
- [:buffer_in, :buffer_in, :buffer_in, :ulong, :ulong, :pointer], :bool
84
+ %i{buffer_in buffer_in buffer_in ulong ulong pointer}, :bool
85
85
 
86
86
  attach_pfunc :CreateProcessAsUserW,
87
- [:ulong, :buffer_in, :buffer_inout, :pointer, :pointer, :int,
88
- :ulong, :buffer_in, :buffer_in, :pointer, :pointer], :bool
87
+ %i{ulong buffer_in buffer_inout pointer pointer int
88
+ ulong buffer_in buffer_in pointer pointer}, :bool
89
89
 
90
90
  ffi_lib :user32
91
91
 
@@ -93,7 +93,7 @@ module Process::Functions
93
93
  [], :ulong
94
94
 
95
95
  attach_pfunc :GetUserObjectInformationA,
96
- [:ulong, :uint, :buffer_out, :ulong, :pointer], :bool
96
+ %i{ulong uint buffer_out ulong pointer}, :bool
97
97
  end
98
98
 
99
99
  # Override Process.create to check for running in the Service window station and doing
@@ -109,7 +109,11 @@ module Process
109
109
  class << self
110
110
 
111
111
  def create(args)
112
- unless args.kind_of?(Hash)
112
+ create3(args).first
113
+ end
114
+
115
+ def create3(args)
116
+ unless args.is_a?(Hash)
113
117
  raise TypeError, "hash keyword arguments expected"
114
118
  end
115
119
 
@@ -137,6 +141,7 @@ module Process
137
141
  unless valid_keys.include?(key)
138
142
  raise ArgumentError, "invalid key '#{key}'"
139
143
  end
144
+
140
145
  hash[key] = val
141
146
  end
142
147
 
@@ -149,6 +154,7 @@ module Process
149
154
  unless valid_si_keys.include?(key)
150
155
  raise ArgumentError, "invalid startup_info key '#{key}'"
151
156
  end
157
+
152
158
  si_hash[key] = val
153
159
  end
154
160
  end
@@ -367,6 +373,7 @@ module Process
367
373
  unless GetProfileType(ptr)
368
374
  raise SystemCallError.new("GetProfileType", FFI.errno)
369
375
  end
376
+
370
377
  ptr.read_uint
371
378
  end
372
379
 
@@ -374,6 +381,7 @@ module Process
374
381
  unless LoadUserProfileW(token, profile_ptr)
375
382
  raise SystemCallError.new("LoadUserProfileW", FFI.errno)
376
383
  end
384
+
377
385
  true
378
386
  end
379
387
 
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.4
4
+ version: 3.1.2
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-06-06 00:00:00.000000000 Z
11
+ date: 2020-07-23 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
  - - ">="