mixlib-shellout 3.0.4-universal-mingw32 → 3.1.2-universal-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="