process_executer 0.4.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/lib/process_executer/monitored_pipe.rb +37 -8
- data/lib/process_executer/version.rb +1 -1
- data/lib/process_executer.rb +17 -10
- data/process_executer.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ac0d1397bbe7c4f632a017f4b66ccdfba6860eed0bb616e65b385ef43bcd613
|
4
|
+
data.tar.gz: 3b4430d7c79739767bcf8f24ab644834eb4a43e89876ef27c1b40032621b72e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63766977ee0f62f6f8ef705c5bc47ecc5358bf06bb9764245ca7c4d6114adf7d0cfef443fac5c89597b5f504ef0b52d8444cf03436c8aae00c0e6ed6fc1d22ad
|
7
|
+
data.tar.gz: 1e8d38c8b4a1169177cd41a8767da33c2b15e2c7a45c3d7ef042aeafc7ba46b19bebfc63ef1bc0b8cd781b312300fbf51363b2305207d0d752895dd0a0dca735
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,29 @@ All notable changes to the process_executer gem will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## v0.6.0 (2023-02-12)
|
9
|
+
|
10
|
+
[Full Changelog](https://github.com/main-branch/process_executer/compare/v0.5.0..v0.6.0)
|
11
|
+
|
12
|
+
Changes since v0.5.0:
|
13
|
+
|
14
|
+
* 2a22dbd Fix intermittent test failures (#21)
|
15
|
+
* e3afaa3 Add build for MRI Ruby 3.2 on unbuntu-latest (#20)
|
16
|
+
* 17522ac Use latest create_release_version gem (#19)
|
17
|
+
* ba1fb2d Read remaining data from pipe_reader when closing a MonitoredPipe (#17)
|
18
|
+
* 8422aa9 Release v0.5.0
|
19
|
+
|
20
|
+
## v0.5.0 (2022-12-12)
|
21
|
+
|
22
|
+
[Full Changelog](https://github.com/main-branch/process_executer/compare/v0.4.0...v0.5.0)
|
23
|
+
|
24
|
+
* c6d8de9 Workaround a problem with SimpleCov / JRuby
|
25
|
+
* c480b5f Increase time to wait for results from a writer throwing an exception
|
26
|
+
* 1934563 Handle exceptions from writers within MonitoredPipe
|
27
|
+
* e948ada Increase default chunk_size to 100_000 bytes
|
28
|
+
* 5eb2c24 Update documentation for ProcessExecuter#spawn
|
29
|
+
* a3a4217 Release v0.4.0
|
30
|
+
|
8
31
|
## v0.4.0 (2022-12-06)
|
9
32
|
|
10
33
|
[Full Changelog](https://github.com/main-branch/process_executer/compare/v0.3.0...v0.4.0)
|
@@ -12,6 +12,9 @@ module ProcessExecuter
|
|
12
12
|
# Data that is read from that pipe is written one or more writers passed to
|
13
13
|
# `#initialize`.
|
14
14
|
#
|
15
|
+
# If any of the writers raise an exception, the monitoring thread will exit, the
|
16
|
+
# pipe will be closed, and the exception will be saved in `#exception`.
|
17
|
+
#
|
15
18
|
# `#close` must be called to ensure that (1) the pipe is closed, (2) all data is
|
16
19
|
# read from the pipe and written to the writers, and (3) the monitoring thread is
|
17
20
|
# killed.
|
@@ -52,12 +55,16 @@ module ProcessExecuter
|
|
52
55
|
# @param writers [Array<#write>] as data is read from the pipe, it is written to these writers
|
53
56
|
# @param chunk_size [Integer] the size of the chunks to read from the pipe
|
54
57
|
#
|
55
|
-
def initialize(*writers, chunk_size:
|
58
|
+
def initialize(*writers, chunk_size: 100_000)
|
56
59
|
@writers = writers
|
57
60
|
@chunk_size = chunk_size
|
58
61
|
@pipe_reader, @pipe_writer = IO.pipe
|
59
62
|
@state = :open
|
60
|
-
@thread = Thread.new
|
63
|
+
@thread = Thread.new do
|
64
|
+
Thread.current.report_on_exception = false
|
65
|
+
Thread.current.abort_on_exception = false
|
66
|
+
monitor
|
67
|
+
end
|
61
68
|
end
|
62
69
|
|
63
70
|
# Set the state to `:closing` and wait for the state to be set to `:closed`
|
@@ -76,6 +83,8 @@ module ProcessExecuter
|
|
76
83
|
# @return [void]
|
77
84
|
#
|
78
85
|
def close
|
86
|
+
return unless state == :open
|
87
|
+
|
79
88
|
@state = :closing
|
80
89
|
sleep 0.01 until state == :closed
|
81
90
|
end
|
@@ -233,6 +242,19 @@ module ProcessExecuter
|
|
233
242
|
#
|
234
243
|
attr_reader :state
|
235
244
|
|
245
|
+
# @!attribute [r]
|
246
|
+
#
|
247
|
+
# The exception raised by a writer
|
248
|
+
#
|
249
|
+
# If an exception is raised by a writer, it is stored here. Otherwise, it is `nil`.
|
250
|
+
#
|
251
|
+
# @example
|
252
|
+
# pipe.exception #=> nil
|
253
|
+
#
|
254
|
+
# @return [Exception, nil] the exception raised by a writer or `nil` if no exception was raised
|
255
|
+
#
|
256
|
+
attr_reader :exception
|
257
|
+
|
236
258
|
private
|
237
259
|
|
238
260
|
# Read data from the pipe until `#state` is changed to `:closing`
|
@@ -257,10 +279,17 @@ module ProcessExecuter
|
|
257
279
|
# @api private
|
258
280
|
def monitor_pipe
|
259
281
|
new_data = pipe_reader.read_nonblock(chunk_size)
|
282
|
+
# SimpleCov under JRuby reports the begin statement as not covered, but it is
|
283
|
+
# :nocov:
|
284
|
+
begin
|
285
|
+
# :nocov:
|
286
|
+
writers.each { |w| w.write(new_data) }
|
287
|
+
rescue StandardError => e
|
288
|
+
@exception = e
|
289
|
+
@state = :closing
|
290
|
+
end
|
260
291
|
rescue IO::WaitReadable
|
261
292
|
pipe_reader.wait_readable(0.01)
|
262
|
-
else
|
263
|
-
writers.each { |w| w.write(new_data) }
|
264
293
|
end
|
265
294
|
|
266
295
|
# Read any remaining data from the pipe and close it
|
@@ -270,11 +299,11 @@ module ProcessExecuter
|
|
270
299
|
def close_pipe
|
271
300
|
# Close the write end of the pipe so no more data can be written to it
|
272
301
|
pipe_writer.close
|
302
|
+
|
273
303
|
# Read remaining data from pipe_reader (if any)
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
end
|
304
|
+
# If an exception was already raised by the last call to #write, then don't try to read remaining data
|
305
|
+
monitor_pipe while exception.nil? && !pipe_reader.eof?
|
306
|
+
|
278
307
|
# Close the read end of the pipe
|
279
308
|
pipe_reader.close
|
280
309
|
end
|
data/lib/process_executer.rb
CHANGED
@@ -10,15 +10,17 @@ require 'timeout'
|
|
10
10
|
# @api public
|
11
11
|
#
|
12
12
|
module ProcessExecuter
|
13
|
-
# Execute the specified command and return the exit status
|
13
|
+
# Execute the specified command as a subprocess and return the exit status
|
14
14
|
#
|
15
|
-
# This method blocks until the command has terminated
|
15
|
+
# This method blocks until the command has terminated.
|
16
|
+
#
|
17
|
+
# The command will be send the SIGKILL signal if it does not terminate within
|
18
|
+
# the specified timeout.
|
16
19
|
#
|
17
20
|
# @example
|
18
21
|
# status = ProcessExecuter.spawn('echo hello')
|
19
22
|
# status.exited? # => true
|
20
23
|
# status.success? # => true
|
21
|
-
# stdout.string # => "hello\n"
|
22
24
|
#
|
23
25
|
# @example with a timeout
|
24
26
|
# status = ProcessExecuter.spawn('sleep 10', timeout: 0.01)
|
@@ -27,6 +29,11 @@ module ProcessExecuter
|
|
27
29
|
# status.signaled? # => true
|
28
30
|
# status.termsig # => 9
|
29
31
|
#
|
32
|
+
# @example capturing stdout to a string
|
33
|
+
# stdout = StringIO.new
|
34
|
+
# status = ProcessExecuter.spawn('echo hello', out: stdout)
|
35
|
+
# stdout.string # => "hello"
|
36
|
+
#
|
30
37
|
# @see https://ruby-doc.org/core-3.1.2/Kernel.html#method-i-spawn Kernel.spawn
|
31
38
|
# documentation for valid command and options
|
32
39
|
#
|
@@ -34,13 +41,13 @@ module ProcessExecuter
|
|
34
41
|
# for additional options that may be specified
|
35
42
|
#
|
36
43
|
# @param command [Array<String>] the command to execute
|
37
|
-
# @param options_hash [Hash] the options to use
|
44
|
+
# @param options_hash [Hash] the options to use when exectuting the command
|
38
45
|
#
|
39
|
-
# @return [
|
46
|
+
# @return [Process::Status] the exit status of the proceess
|
40
47
|
#
|
41
48
|
def self.spawn(*command, **options_hash)
|
42
49
|
options = ProcessExecuter::Options.new(**options_hash)
|
43
|
-
pid =
|
50
|
+
pid = Process.spawn(*command, **options.spawn_options)
|
44
51
|
wait_for_process(pid, options)
|
45
52
|
end
|
46
53
|
|
@@ -51,16 +58,16 @@ module ProcessExecuter
|
|
51
58
|
# @param pid [Integer] the process id
|
52
59
|
# @param options [ProcessExecuter::Options] the options used
|
53
60
|
#
|
54
|
-
# @return [
|
61
|
+
# @return [Process::Status] the status of the process
|
55
62
|
#
|
56
63
|
# @api private
|
57
64
|
#
|
58
65
|
private_class_method def self.wait_for_process(pid, options)
|
59
66
|
Timeout.timeout(options.timeout) do
|
60
|
-
|
67
|
+
Process.wait2(pid).last
|
61
68
|
end
|
62
69
|
rescue Timeout::Error
|
63
|
-
|
64
|
-
|
70
|
+
Process.kill('KILL', pid)
|
71
|
+
Process.wait2(pid).last
|
65
72
|
end
|
66
73
|
end
|
data/process_executer.gemspec
CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
# spec.add_dependency "example-gem", "~> 1.0"
|
36
36
|
spec.add_development_dependency 'bump', '~> 0.10'
|
37
37
|
spec.add_development_dependency 'bundler-audit', '~> 0.9'
|
38
|
-
spec.add_development_dependency 'create_github_release', '~> 0
|
38
|
+
spec.add_development_dependency 'create_github_release', '~> 1.0'
|
39
39
|
spec.add_development_dependency 'rake', '~> 13.0'
|
40
40
|
spec.add_development_dependency 'rspec', '~> 3.10'
|
41
41
|
spec.add_development_dependency 'rubocop', '~> 1.36'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: process_executer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Couball
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bump
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0
|
47
|
+
version: '1.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0
|
54
|
+
version: '1.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -229,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
229
229
|
- !ruby/object:Gem::Version
|
230
230
|
version: '0'
|
231
231
|
requirements: []
|
232
|
-
rubygems_version: 3.
|
232
|
+
rubygems_version: 3.4.1
|
233
233
|
signing_key:
|
234
234
|
specification_version: 4
|
235
235
|
summary: An API for executing commands in a subprocess
|