mixlib-shellout 1.3.0-x86-mingw32 → 1.4.0.rc.0-x86-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 +7 -0
- data/lib/mixlib/shellout.rb +12 -8
- data/lib/mixlib/shellout/unix.rb +48 -12
- data/lib/mixlib/shellout/version.rb +1 -1
- data/lib/mixlib/shellout/windows.rb +2 -2
- data/lib/mixlib/shellout/windows/core_ext.rb +25 -16
- metadata +16 -24
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e6982a3f776c89a117273e34a9207226ae91d430
|
4
|
+
data.tar.gz: bed2f4cda27c43e7f4a8bd1265089bf7b8016065
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dd33a078724263f3aec8d63518c0b7c67883e0fca6b8a359b3ca573228ba6a194032305dfa85b2f55b901c4c0b9dcdf877908170d590bcebb30f947e3777cd1f
|
7
|
+
data.tar.gz: 5c7af3ef8b2bb9f5e7ef9e36dce50f94afc0d3ce56702ac6e6bd45343cc367fe057ea7ad8b04881e6d0aaaebcaffd45ae95f9d69bf3e36ea385127f2f023b61b
|
data/lib/mixlib/shellout.rb
CHANGED
@@ -49,8 +49,8 @@ module Mixlib
|
|
49
49
|
# Working directory for the subprocess. Normally set via options to new
|
50
50
|
attr_accessor :cwd
|
51
51
|
|
52
|
-
# An Array of acceptable exit codes. #error!
|
53
|
-
# the command was successful. Normally set via options to new
|
52
|
+
# An Array of acceptable exit codes. #error? (and #error!) use this list
|
53
|
+
# to determine if the command was successful. Normally set via options to new
|
54
54
|
attr_accessor :valid_exit_codes
|
55
55
|
|
56
56
|
# When live_stream is set, stdout of the subprocess will be copied to it as
|
@@ -227,17 +227,21 @@ module Mixlib
|
|
227
227
|
super
|
228
228
|
end
|
229
229
|
|
230
|
-
# Checks the +exitstatus+ against the set of +valid_exit_codes+.
|
231
|
-
#
|
232
|
-
#
|
230
|
+
# Checks the +exitstatus+ against the set of +valid_exit_codes+.
|
231
|
+
# === Returns
|
232
|
+
# +true+ if +exitstatus+ is not in the list of +valid_exit_codes+, false
|
233
|
+
# otherwise.
|
234
|
+
def error?
|
235
|
+
!Array(valid_exit_codes).include?(exitstatus)
|
236
|
+
end
|
237
|
+
|
238
|
+
# If #error? is true, calls +invalid!+, which raises an Exception.
|
233
239
|
# === Returns
|
234
240
|
# nil::: always returns nil when it does not raise
|
235
241
|
# === Raises
|
236
242
|
# ::ShellCommandFailed::: via +invalid!+
|
237
243
|
def error!
|
238
|
-
|
239
|
-
invalid!("Expected process to exit with #{valid_exit_codes.inspect}, but received '#{exitstatus}'")
|
240
|
-
end
|
244
|
+
invalid!("Expected process to exit with #{valid_exit_codes.inspect}, but received '#{exitstatus}'") if error?
|
241
245
|
end
|
242
246
|
|
243
247
|
# Raises a ShellCommandFailed exception, appending the
|
data/lib/mixlib/shellout/unix.rb
CHANGED
@@ -20,6 +20,11 @@ module Mixlib
|
|
20
20
|
class ShellOut
|
21
21
|
module Unix
|
22
22
|
|
23
|
+
# "1.8.7" as a frozen string. We use this with a hack that disables GC to
|
24
|
+
# avoid segfaults on Ruby 1.8.7, so we need to allocate the fewest
|
25
|
+
# objects we possibly can.
|
26
|
+
ONE_DOT_EIGHT_DOT_SEVEN = "1.8.7".freeze
|
27
|
+
|
23
28
|
# Option validation that is unix specific
|
24
29
|
def validate_options(opts)
|
25
30
|
# No options to validate, raise exceptions here if needed
|
@@ -29,13 +34,20 @@ module Mixlib
|
|
29
34
|
# to +stdout+ and +stderr+, and saving its exit status object to +status+
|
30
35
|
# === Returns
|
31
36
|
# returns +self+; +stdout+, +stderr+, +status+, and +exitstatus+ will be
|
32
|
-
# populated with results of the command
|
37
|
+
# populated with results of the command.
|
33
38
|
# === Raises
|
34
39
|
# * Errno::EACCES when you are not privileged to execute the command
|
35
40
|
# * Errno::ENOENT when the command is not available on the system (or not
|
36
41
|
# in the current $PATH)
|
37
42
|
# * Chef::Exceptions::CommandTimeout when the command does not complete
|
38
|
-
# within +timeout+ seconds (default: 600s)
|
43
|
+
# within +timeout+ seconds (default: 600s). When this happens, ShellOut
|
44
|
+
# will send a TERM and then KILL to the entire process group to ensure
|
45
|
+
# that any grandchild processes are terminated. If the invocation of
|
46
|
+
# the child process spawned multiple child processes (which commonly
|
47
|
+
# happens if the command is passed as a single string to be interpreted
|
48
|
+
# by bin/sh, and bin/sh is not bash), the exit status object may not
|
49
|
+
# contain the correct exit code of the process (of course there is no
|
50
|
+
# exit code if the command is killed by SIGKILL, also).
|
39
51
|
def run_command
|
40
52
|
@child_pid = fork_subprocess
|
41
53
|
@reaped = false
|
@@ -43,14 +55,15 @@ module Mixlib
|
|
43
55
|
configure_parent_process_file_descriptors
|
44
56
|
|
45
57
|
# Ruby 1.8.7 and 1.8.6 from mid 2009 try to allocate objects during GC
|
46
|
-
# when calling IO.select and IO#read.
|
47
|
-
#
|
48
|
-
#
|
49
|
-
GC.disable
|
58
|
+
# when calling IO.select and IO#read. Disabling GC works around the
|
59
|
+
# segfault, but obviously it's a bad workaround. We no longer support
|
60
|
+
# 1.8.6 so we only need this hack for 1.8.7.
|
61
|
+
GC.disable if RUBY_VERSION == ONE_DOT_EIGHT_DOT_SEVEN
|
50
62
|
|
51
63
|
# CHEF-3390: Marshall.load on Ruby < 1.8.7p369 also has a GC bug related
|
52
64
|
# to Marshall.load, so try disabling GC first.
|
53
65
|
propagate_pre_exec_failure
|
66
|
+
@child_pgid = -Process.getpgid(@child_pid)
|
54
67
|
|
55
68
|
@result = nil
|
56
69
|
@execution_time = 0
|
@@ -122,6 +135,12 @@ module Mixlib
|
|
122
135
|
Dir.chdir(cwd) if cwd
|
123
136
|
end
|
124
137
|
|
138
|
+
# Process group id of the child. Returned as a negative value so you can
|
139
|
+
# put it directly in arguments to kill, wait, etc.
|
140
|
+
def child_pgid
|
141
|
+
@child_pgid
|
142
|
+
end
|
143
|
+
|
125
144
|
def initialize_ipc
|
126
145
|
@stdin_pipe, @stdout_pipe, @stderr_pipe, @process_status_pipe = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
127
146
|
@process_status_pipe.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
@@ -263,6 +282,14 @@ module Mixlib
|
|
263
282
|
initialize_ipc
|
264
283
|
|
265
284
|
fork do
|
285
|
+
# Child processes may themselves fork off children. A common case
|
286
|
+
# is when the command is given as a single string (instead of
|
287
|
+
# command name plus Array of arguments) and /bin/sh does not
|
288
|
+
# support the "ONESHOT" optimization (where sh -c does exec without
|
289
|
+
# forking). To support cleaning up all the children, we need to
|
290
|
+
# ensure they're in a unique process group.
|
291
|
+
Process.setsid
|
292
|
+
|
266
293
|
configure_subprocess_file_descriptors
|
267
294
|
|
268
295
|
clean_parent_file_descriptors
|
@@ -302,14 +329,13 @@ module Mixlib
|
|
302
329
|
|
303
330
|
def reap_errant_child
|
304
331
|
return if attempt_reap
|
305
|
-
@terminate_reason = "Command execeded allowed execution time,
|
332
|
+
@terminate_reason = "Command execeded allowed execution time, process terminated"
|
306
333
|
logger.error("Command execeded allowed execution time, sending TERM") if logger
|
307
|
-
Process.kill(:TERM,
|
334
|
+
Process.kill(:TERM, child_pgid)
|
308
335
|
sleep 3
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
Process.kill(:KILL, @child_pid)
|
336
|
+
attempt_reap
|
337
|
+
logger.error("Command execeded allowed execution time, sending KILL") if logger
|
338
|
+
Process.kill(:KILL, child_pgid)
|
313
339
|
reap
|
314
340
|
|
315
341
|
# Should not hit this but it's possible if something is calling waitall
|
@@ -323,12 +349,22 @@ module Mixlib
|
|
323
349
|
@child_pid && !@reaped
|
324
350
|
end
|
325
351
|
|
352
|
+
# Unconditionally reap the child process. This is used in scenarios where
|
353
|
+
# we can be confident the child will exit quickly, and has not spawned
|
354
|
+
# and grandchild processes.
|
326
355
|
def reap
|
327
356
|
results = Process.waitpid2(@child_pid)
|
328
357
|
@reaped = true
|
329
358
|
@status = results.last
|
359
|
+
rescue Errno::ECHILD
|
360
|
+
# When cleaning up timed-out processes, we might send SIGKILL to the
|
361
|
+
# whole process group after we've cleaned up the direct child. In that
|
362
|
+
# case the grandchildren will have been adopted by init so we can't
|
363
|
+
# reap them even if we wanted to (we don't).
|
364
|
+
nil
|
330
365
|
end
|
331
366
|
|
367
|
+
# Try to reap the child process but don't block if it isn't dead yet.
|
332
368
|
def attempt_reap
|
333
369
|
if results = Process.waitpid2(@child_pid, Process::WNOHANG)
|
334
370
|
@reaped = true
|
@@ -122,8 +122,8 @@ module Mixlib
|
|
122
122
|
end
|
123
123
|
|
124
124
|
ensure
|
125
|
-
CloseHandle(process.thread_handle)
|
126
|
-
CloseHandle(process.process_handle)
|
125
|
+
CloseHandle(process.thread_handle) if process.thread_handle
|
126
|
+
CloseHandle(process.process_handle) if process.process_handle
|
127
127
|
end
|
128
128
|
|
129
129
|
ensure
|
@@ -288,19 +288,23 @@ module Process
|
|
288
288
|
|
289
289
|
token = token.read_ulong
|
290
290
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
291
|
+
begin
|
292
|
+
bool = CreateProcessAsUserW(
|
293
|
+
token, # User token handle
|
294
|
+
app, # App name
|
295
|
+
cmd, # Command line
|
296
|
+
process_security, # Process attributes
|
297
|
+
thread_security, # Thread attributes
|
298
|
+
inherit, # Inherit handles
|
299
|
+
hash['creation_flags'], # Creation Flags
|
300
|
+
env, # Environment
|
301
|
+
cwd, # Working directory
|
302
|
+
startinfo, # Startup Info
|
303
|
+
procinfo # Process Info
|
304
|
+
)
|
305
|
+
ensure
|
306
|
+
CloseHandle(token)
|
307
|
+
end
|
304
308
|
|
305
309
|
unless bool
|
306
310
|
raise SystemCallError.new("CreateProcessAsUserW (You must hold the 'Replace a process level token' permission)", FFI.errno)
|
@@ -346,9 +350,14 @@ module Process
|
|
346
350
|
# Automatically close the process and thread handles in the
|
347
351
|
# PROCESS_INFORMATION struct unless explicitly told not to.
|
348
352
|
if hash['close_handles']
|
349
|
-
CloseHandle(procinfo[:hProcess])
|
350
|
-
CloseHandle(procinfo[:hThread])
|
351
|
-
|
353
|
+
CloseHandle(procinfo[:hProcess]) if procinfo[:hProcess]
|
354
|
+
CloseHandle(procinfo[:hThread]) if procinfo[:hThread]
|
355
|
+
|
356
|
+
# Set fields to nil so callers don't attempt to close the handle
|
357
|
+
# which can result in the wrong handle being closed or an
|
358
|
+
# exception in some circumstances
|
359
|
+
procinfo[:hProcess] = nil
|
360
|
+
procinfo[:hThread] = nil
|
352
361
|
end
|
353
362
|
|
354
363
|
ProcessInfo.new(
|
metadata
CHANGED
@@ -1,62 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixlib-shellout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.4.0.rc.0
|
6
5
|
platform: x86-mingw32
|
7
6
|
authors:
|
8
7
|
- Opscode
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-03-30 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '2.0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '2.0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: win32-process
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 0.7.1
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 0.7.1
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: windows-pr
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- - ~>
|
45
|
+
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 1.2.2
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- - ~>
|
52
|
+
- - "~>"
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 1.2.2
|
62
55
|
description: Run external commands on Unix or Windows
|
@@ -69,34 +62,33 @@ extra_rdoc_files:
|
|
69
62
|
files:
|
70
63
|
- LICENSE
|
71
64
|
- README.md
|
65
|
+
- lib/mixlib/shellout.rb
|
72
66
|
- lib/mixlib/shellout/exceptions.rb
|
73
67
|
- lib/mixlib/shellout/unix.rb
|
74
68
|
- lib/mixlib/shellout/version.rb
|
75
|
-
- lib/mixlib/shellout/windows/core_ext.rb
|
76
69
|
- lib/mixlib/shellout/windows.rb
|
77
|
-
- lib/mixlib/shellout.rb
|
70
|
+
- lib/mixlib/shellout/windows/core_ext.rb
|
78
71
|
homepage: http://wiki.opscode.com/
|
79
72
|
licenses: []
|
73
|
+
metadata: {}
|
80
74
|
post_install_message:
|
81
75
|
rdoc_options: []
|
82
76
|
require_paths:
|
83
77
|
- lib
|
84
78
|
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
-
none: false
|
86
79
|
requirements:
|
87
|
-
- -
|
80
|
+
- - ">="
|
88
81
|
- !ruby/object:Gem::Version
|
89
82
|
version: '0'
|
90
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
-
none: false
|
92
84
|
requirements:
|
93
|
-
- -
|
85
|
+
- - ">"
|
94
86
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
87
|
+
version: 1.3.1
|
96
88
|
requirements: []
|
97
89
|
rubyforge_project:
|
98
|
-
rubygems_version:
|
90
|
+
rubygems_version: 2.2.2
|
99
91
|
signing_key:
|
100
|
-
specification_version:
|
92
|
+
specification_version: 4
|
101
93
|
summary: Run external commands on Unix or Windows
|
102
94
|
test_files: []
|