mixlib-shellout 1.2.0-x86-mingw32 → 1.3.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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NmI4YTJhYTFjMDhjY2YzZDY3Njk3ZDdhZjg5ZGFhMmFjM2NhODNhNA==
5
+ data.tar.gz: !binary |-
6
+ YmU5Y2E4NDgyMDQxZjIzMzRkMmNhNDFiZTVhNmI1MzIwZTM1OTQxMQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDQ0ZjlmMzllMTM5ZDJkYTI1ZTY0ZGY1YTRmOTUzMGRlNDUwMmM0YjAyOWI2
10
+ NjFhYWIzYzJhMTc1NzZjOGJlMDhmMDc4YTYwNjk5YWU3NzJkZDJkYmQxN2Fj
11
+ M2FlN2VjZjY3YjBlM2ZlNDkxZWZjY2M5MjNmM2Q1NWExOGEwOTQ=
12
+ data.tar.gz: !binary |-
13
+ ZWVkYTc1M2E1YjM5NWVlOTgzMDQyM2Y5YmY0NGMwMWM2MDFhNGNkNjY2YjU0
14
+ NzQ0MTRjNTViOTA4OGZhZGViMjhmNDhjNTI0ODQyMDkxOTNmNDRkODE4MjA3
15
+ ZDRkOWY5NmMwNDI0ODQwZjUyZWIzNzE5YWIzMDJhNDdkODcyYjQ=
@@ -154,6 +154,7 @@ module Mixlib
154
154
  @environment = DEFAULT_ENVIRONMENT
155
155
  @cwd = nil
156
156
  @valid_exit_codes = [0]
157
+ @terminate_reason = nil
157
158
 
158
159
  if command_args.last.is_a?(Hash)
159
160
  parse_options(command_args.pop)
@@ -191,6 +192,7 @@ module Mixlib
191
192
  # results when the command exited with an unexpected status.
192
193
  def format_for_exception
193
194
  msg = ""
195
+ msg << "#{@terminate_reason}\n" if @terminate_reason
194
196
  msg << "---- Begin output of #{command} ----\n"
195
197
  msg << "STDOUT: #{stdout.strip}\n"
196
198
  msg << "STDERR: #{stderr.strip}\n"
@@ -38,6 +38,7 @@ module Mixlib
38
38
  # within +timeout+ seconds (default: 600s)
39
39
  def run_command
40
40
  @child_pid = fork_subprocess
41
+ @reaped = false
41
42
 
42
43
  configure_parent_process_file_descriptors
43
44
 
@@ -57,36 +58,33 @@ module Mixlib
57
58
  write_to_child_stdin
58
59
 
59
60
  until @status
60
- ready = IO.select(open_pipes, nil, nil, READ_WAIT_TIME)
61
- unless ready
61
+ ready_buffers = attempt_buffer_read
62
+ unless ready_buffers
62
63
  @execution_time += READ_WAIT_TIME
63
64
  if @execution_time >= timeout && !@result
64
- raise CommandTimeout, "command timed out:\n#{format_for_exception}"
65
+ # kill the bad proccess
66
+ reap_errant_child
67
+ # read anything it wrote when we killed it
68
+ attempt_buffer_read
69
+ # raise
70
+ raise CommandTimeout, "Command timed out after #{@execution_time.to_i}s:\n#{format_for_exception}"
65
71
  end
66
72
  end
67
73
 
68
- if ready && ready.first.include?(child_stdout)
69
- read_stdout_to_buffer
70
- end
71
- if ready && ready.first.include?(child_stderr)
72
- read_stderr_to_buffer
73
- end
74
-
75
- unless @status
76
- # make one more pass to get the last of the output after the
77
- # child process dies
78
- if results = Process.waitpid2(@child_pid, Process::WNOHANG)
79
- @status = results.last
80
- redo
81
- end
82
- end
74
+ attempt_reap
83
75
  end
76
+
84
77
  self
85
- rescue Exception
86
- # do our best to kill zombies
87
- Process.waitpid2(@child_pid, Process::WNOHANG) rescue nil
78
+ rescue Errno::ENOENT
79
+ # When ENOENT happens, we can be reasonably sure that the child process
80
+ # is going to exit quickly, so we use the blocking variant of waitpid2
81
+ reap
88
82
  raise
89
83
  ensure
84
+ reap_errant_child if should_reap?
85
+ # make one more pass to get the last of the output after the
86
+ # child process dies
87
+ attempt_buffer_read
90
88
  # no matter what happens, turn the GC back on, and hope whatever busted
91
89
  # version of ruby we're on doesn't allocate some objects during the next
92
90
  # GC run.
@@ -231,6 +229,17 @@ module Mixlib
231
229
  child_stdin.close # Kick things off
232
230
  end
233
231
 
232
+ def attempt_buffer_read
233
+ ready = IO.select(open_pipes, nil, nil, READ_WAIT_TIME)
234
+ if ready && ready.first.include?(child_stdout)
235
+ read_stdout_to_buffer
236
+ end
237
+ if ready && ready.first.include?(child_stderr)
238
+ read_stderr_to_buffer
239
+ end
240
+ ready
241
+ end
242
+
234
243
  def read_stdout_to_buffer
235
244
  while chunk = child_stdout.read_nonblock(READ_SIZE)
236
245
  @stdout << chunk
@@ -291,6 +300,44 @@ module Mixlib
291
300
  end
292
301
  end
293
302
 
303
+ def reap_errant_child
304
+ return if attempt_reap
305
+ @terminate_reason = "Command execeded allowed execution time, killed by TERM signal."
306
+ logger.error("Command execeded allowed execution time, sending TERM") if logger
307
+ Process.kill(:TERM, @child_pid)
308
+ sleep 3
309
+ return if attempt_reap
310
+ @terminate_reason = "Command execeded allowed execution time, did not respond to TERM. Killed by KILL signal."
311
+ logger.error("Command did not exit from TERM, sending KILL") if logger
312
+ Process.kill(:KILL, @child_pid)
313
+ reap
314
+
315
+ # Should not hit this but it's possible if something is calling waitall
316
+ # in a separate thread.
317
+ rescue Errno::ESRCH
318
+ nil
319
+ end
320
+
321
+ def should_reap?
322
+ # if we fail to fork, no child pid so nothing to reap
323
+ @child_pid && !@reaped
324
+ end
325
+
326
+ def reap
327
+ results = Process.waitpid2(@child_pid)
328
+ @reaped = true
329
+ @status = results.last
330
+ end
331
+
332
+ def attempt_reap
333
+ if results = Process.waitpid2(@child_pid, Process::WNOHANG)
334
+ @reaped = true
335
+ @status = results.last
336
+ else
337
+ nil
338
+ end
339
+ end
340
+
294
341
  end
295
342
  end
296
343
  end
@@ -1,5 +1,5 @@
1
1
  module Mixlib
2
2
  class ShellOut
3
- VERSION = "1.2.0"
3
+ VERSION = "1.3.0.rc.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,68 +1,46 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixlib-shellout
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
5
- prerelease:
4
+ version: 1.3.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: 2013-07-19 00:00:00.000000000 Z
11
+ date: 2013-11-19 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
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- - !ruby/object:Gem::Dependency
31
- name: ap
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
17
+ - - ~>
36
18
  - !ruby/object:Gem::Version
37
- version: '0'
19
+ version: '2.0'
38
20
  type: :development
39
21
  prerelease: false
40
22
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
23
  requirements:
43
- - - ! '>='
24
+ - - ~>
44
25
  - !ruby/object:Gem::Version
45
- version: '0'
26
+ version: '2.0'
46
27
  - !ruby/object:Gem::Dependency
47
28
  name: win32-process
48
29
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
30
  requirements:
51
31
  - - ~>
52
32
  - !ruby/object:Gem::Version
53
- version: 0.7.0
33
+ version: 0.7.1
54
34
  type: :runtime
55
35
  prerelease: false
56
36
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
37
  requirements:
59
38
  - - ~>
60
39
  - !ruby/object:Gem::Version
61
- version: 0.7.0
40
+ version: 0.7.1
62
41
  - !ruby/object:Gem::Dependency
63
42
  name: windows-pr
64
43
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
44
  requirements:
67
45
  - - ~>
68
46
  - !ruby/object:Gem::Version
@@ -70,7 +48,6 @@ dependencies:
70
48
  type: :runtime
71
49
  prerelease: false
72
50
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
51
  requirements:
75
52
  - - ~>
76
53
  - !ruby/object:Gem::Version
@@ -93,26 +70,25 @@ files:
93
70
  - lib/mixlib/shellout.rb
94
71
  homepage: http://wiki.opscode.com/
95
72
  licenses: []
73
+ metadata: {}
96
74
  post_install_message:
97
75
  rdoc_options: []
98
76
  require_paths:
99
77
  - lib
100
78
  required_ruby_version: !ruby/object:Gem::Requirement
101
- none: false
102
79
  requirements:
103
80
  - - ! '>='
104
81
  - !ruby/object:Gem::Version
105
82
  version: '0'
106
83
  required_rubygems_version: !ruby/object:Gem::Requirement
107
- none: false
108
84
  requirements:
109
- - - ! '>='
85
+ - - ! '>'
110
86
  - !ruby/object:Gem::Version
111
- version: '0'
87
+ version: 1.3.1
112
88
  requirements: []
113
89
  rubyforge_project:
114
- rubygems_version: 1.8.23
90
+ rubygems_version: 2.0.3
115
91
  signing_key:
116
- specification_version: 3
92
+ specification_version: 4
117
93
  summary: Run external commands on Unix or Windows
118
94
  test_files: []