process_executer 3.2.4 → 4.0.0
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 +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +41 -0
- data/README.md +177 -134
- data/lib/process_executer/commands/run.rb +124 -0
- data/lib/process_executer/commands/run_with_capture.rb +148 -0
- data/lib/process_executer/commands/spawn_with_timeout.rb +163 -0
- data/lib/process_executer/commands.rb +11 -0
- data/lib/process_executer/destinations/child_redirection.rb +5 -4
- data/lib/process_executer/destinations/close.rb +5 -4
- data/lib/process_executer/destinations/destination_base.rb +73 -0
- data/lib/process_executer/destinations/file_descriptor.rb +10 -6
- data/lib/process_executer/destinations/file_path.rb +12 -6
- data/lib/process_executer/destinations/file_path_mode.rb +10 -6
- data/lib/process_executer/destinations/file_path_mode_perms.rb +12 -5
- data/lib/process_executer/destinations/io.rb +10 -5
- data/lib/process_executer/destinations/monitored_pipe.rb +10 -5
- data/lib/process_executer/destinations/stderr.rb +8 -4
- data/lib/process_executer/destinations/stdout.rb +8 -4
- data/lib/process_executer/destinations/tee.rb +24 -17
- data/lib/process_executer/destinations/writer.rb +12 -7
- data/lib/process_executer/destinations.rb +32 -17
- data/lib/process_executer/errors.rb +50 -26
- data/lib/process_executer/monitored_pipe.rb +128 -59
- data/lib/process_executer/options/base.rb +118 -82
- data/lib/process_executer/options/option_definition.rb +5 -1
- data/lib/process_executer/options/run_options.rb +13 -12
- data/lib/process_executer/options/run_with_capture_options.rb +156 -0
- data/lib/process_executer/options/spawn_options.rb +31 -30
- data/lib/process_executer/options/{spawn_and_wait_options.rb → spawn_with_timeout_options.rb} +11 -7
- data/lib/process_executer/options.rb +3 -1
- data/lib/process_executer/result.rb +35 -77
- data/lib/process_executer/result_with_capture.rb +62 -0
- data/lib/process_executer/version.rb +2 -1
- data/lib/process_executer.rb +384 -346
- data/process_executer.gemspec +11 -2
- metadata +18 -8
- data/lib/process_executer/destination_base.rb +0 -83
- data/lib/process_executer/runner.rb +0 -144
@@ -1,20 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'destination_base'
|
4
|
+
|
3
5
|
module ProcessExecuter
|
4
6
|
module Destinations
|
5
7
|
# Handles monitored pipes
|
6
8
|
#
|
7
9
|
# @api private
|
8
|
-
class MonitoredPipe <
|
10
|
+
class MonitoredPipe < DestinationBase
|
9
11
|
# Writes data to the monitored pipe
|
10
12
|
#
|
11
|
-
# @param data [String] the data to write
|
12
|
-
# @return [Object] the return value of the pipe's write method
|
13
|
-
#
|
14
13
|
# @example
|
15
|
-
#
|
14
|
+
# stringio_dest = StringIO.new
|
15
|
+
# pipe = ProcessExecuter::MonitoredPipe.new(stringio_dest)
|
16
16
|
# pipe_handler = ProcessExecuter::Destinations::MonitoredPipe.new(pipe)
|
17
17
|
# pipe_handler.write("Data to pipe")
|
18
|
+
#
|
19
|
+
# @param data [String] the data to write
|
20
|
+
#
|
21
|
+
# @return [Integer] the number of bytes written
|
22
|
+
#
|
18
23
|
def write(data)
|
19
24
|
super
|
20
25
|
destination.write data
|
@@ -1,19 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'destination_base'
|
4
|
+
|
3
5
|
module ProcessExecuter
|
4
6
|
module Destinations
|
5
7
|
# Handles standard error redirection
|
6
8
|
#
|
7
9
|
# @api private
|
8
|
-
class Stderr <
|
10
|
+
class Stderr < DestinationBase
|
9
11
|
# Writes data to standard error
|
10
12
|
#
|
11
|
-
# @param data [String] the data to write
|
12
|
-
# @return [Integer] the number of bytes written
|
13
|
-
#
|
14
13
|
# @example
|
15
14
|
# stderr_handler = ProcessExecuter::Destinations::Stderr.new(:err)
|
16
15
|
# stderr_handler.write("Error message")
|
16
|
+
#
|
17
|
+
# @param data [String] the data to write
|
18
|
+
#
|
19
|
+
# @return [Integer] the number of bytes written
|
20
|
+
#
|
17
21
|
def write(data)
|
18
22
|
super
|
19
23
|
$stderr.write data
|
@@ -1,19 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'destination_base'
|
4
|
+
|
3
5
|
module ProcessExecuter
|
4
6
|
module Destinations
|
5
7
|
# Handles standard output redirection
|
6
8
|
#
|
7
9
|
# @api private
|
8
|
-
class Stdout <
|
10
|
+
class Stdout < DestinationBase
|
9
11
|
# Writes data to standard output
|
10
12
|
#
|
11
|
-
# @param data [String] the data to write
|
12
|
-
# @return [Integer] the number of bytes written
|
13
|
-
#
|
14
13
|
# @example
|
15
14
|
# stdout_handler = ProcessExecuter::Destinations::Stdout.new(:out)
|
16
15
|
# stdout_handler.write("Hello world")
|
16
|
+
#
|
17
|
+
# @param data [String] the data to write
|
18
|
+
#
|
19
|
+
# @return [Integer] the number of bytes written
|
20
|
+
#
|
17
21
|
def write(data)
|
18
22
|
super
|
19
23
|
$stdout.write data
|
@@ -1,47 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'destination_base'
|
4
|
+
|
3
5
|
module ProcessExecuter
|
4
6
|
module Destinations
|
5
|
-
# Handles destination for writing to multiple destinations
|
7
|
+
# Handles a destination for writing to multiple destinations
|
6
8
|
#
|
7
9
|
# The destination is an array with the first element being :tee and the rest
|
8
10
|
# being the destinations.
|
9
11
|
#
|
10
12
|
# @api private
|
11
|
-
class Tee <
|
12
|
-
# Initializes a
|
13
|
+
class Tee < DestinationBase
|
14
|
+
# Initializes a destination handler for writing to multiple output destinations
|
15
|
+
#
|
16
|
+
# @param destination [Array<Symbol, Object...>] array in the form [:tee, destination...]
|
13
17
|
#
|
14
|
-
#
|
18
|
+
# @raise [ArgumentError] if a child destination is invalid or incompatible
|
15
19
|
#
|
16
|
-
# @param destination [Array<String, String, Integer>] array with file path, mode, and permissions
|
17
|
-
# @return [FilePathModePerms] a new handler instance
|
18
|
-
# @raise [Errno::ENOENT] if the file path is invalid
|
19
|
-
# @raise [ArgumentError] if the mode is invalid
|
20
20
|
def initialize(destination)
|
21
21
|
super
|
22
22
|
@child_destinations = destination[1..].map { |dest| ProcessExecuter::Destinations.factory(dest) }
|
23
23
|
end
|
24
24
|
|
25
|
-
#
|
25
|
+
# An array of child destinations
|
26
|
+
#
|
27
|
+
# @return [Array<ProcessExecuter::Destinations::DestinationBase>]
|
28
|
+
# An array of the child destination handlers
|
26
29
|
#
|
27
|
-
# @return [File] the opened file
|
28
30
|
attr_reader :child_destinations
|
29
31
|
|
30
|
-
# Writes data
|
32
|
+
# Writes data each of the {child_destinations}
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# tee = ProcessExecuter::Destinations::Tee.new([:tee, "output1.log", "output2.log"])
|
36
|
+
# tee.write("Log entry with specific permissions")
|
37
|
+
# tee.close # Important to close the tee to ensure all data is flushed
|
31
38
|
#
|
32
39
|
# @param data [String] the data to write
|
33
|
-
#
|
40
|
+
#
|
41
|
+
# @return [Integer] the number of bytes in the input data (which is written to each destination)
|
42
|
+
#
|
34
43
|
# @raise [IOError] if the file is closed
|
35
44
|
#
|
36
|
-
# @example
|
37
|
-
# perms_handler = ProcessExecuter::Destinations::FilePathModePerms.new(["output.log", "w", 0644])
|
38
|
-
# perms_handler.write("Log entry with specific permissions")
|
39
45
|
def write(data)
|
40
46
|
super
|
41
47
|
child_destinations.each { |dest| dest.write(data) }
|
48
|
+
data.bytesize
|
42
49
|
end
|
43
50
|
|
44
|
-
# Closes the
|
51
|
+
# Closes the child_destinations
|
45
52
|
#
|
46
53
|
# @return [void]
|
47
54
|
def close
|
@@ -51,7 +58,7 @@ module ProcessExecuter
|
|
51
58
|
# Determines if this class can handle the given destination
|
52
59
|
#
|
53
60
|
# @param destination [Object] the destination to check
|
54
|
-
# @return [Boolean] true if destination is an Array
|
61
|
+
# @return [Boolean] true if destination is an Array in the form [:tee, destination...]
|
55
62
|
def self.handles?(destination)
|
56
63
|
destination.is_a?(Array) && destination.size > 1 && destination[0] == :tee
|
57
64
|
end
|
@@ -1,21 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'destination_base'
|
4
|
+
|
3
5
|
module ProcessExecuter
|
4
6
|
module Destinations
|
5
|
-
# Handles generic objects that respond to write
|
7
|
+
# Handles generic objects that respond to `#write`
|
6
8
|
#
|
7
9
|
# @api private
|
8
|
-
class Writer <
|
10
|
+
class Writer < DestinationBase
|
9
11
|
# Writes data to the destination object
|
10
12
|
#
|
11
|
-
# @param data [String] the data to write
|
12
|
-
# @return [Object] the return value of the destination's write method
|
13
|
-
# @raise [NoMethodError] if the destination doesn't respond to write
|
14
|
-
#
|
15
13
|
# @example
|
16
14
|
# buffer = StringIO.new
|
17
15
|
# writer_handler = ProcessExecuter::Destinations::Writer.new(buffer)
|
18
16
|
# writer_handler.write("Hello world")
|
17
|
+
#
|
18
|
+
# @param data [String] the data to write
|
19
|
+
#
|
20
|
+
# @return [Integer] the number of bytes written
|
21
|
+
#
|
19
22
|
def write(data)
|
20
23
|
super
|
21
24
|
destination.write data
|
@@ -24,7 +27,9 @@ module ProcessExecuter
|
|
24
27
|
# Determines if this class can handle the given destination
|
25
28
|
#
|
26
29
|
# @param destination [Object] the destination to check
|
27
|
-
#
|
30
|
+
#
|
31
|
+
# @return [Boolean] true if destination responds to #write and is not an IO object with a #fileno
|
32
|
+
#
|
28
33
|
def self.handles?(destination)
|
29
34
|
destination.respond_to?(:write) && (!destination.respond_to?(:fileno) || destination.fileno.nil?)
|
30
35
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'destinations/child_redirection'
|
4
|
+
require_relative 'destinations/destination_base'
|
4
5
|
require_relative 'destinations/file_descriptor'
|
5
6
|
require_relative 'destinations/file_path'
|
6
7
|
require_relative 'destinations/file_path_mode'
|
@@ -15,54 +16,68 @@ require_relative 'destinations/writer'
|
|
15
16
|
module ProcessExecuter
|
16
17
|
# Collection of destination handler implementations
|
17
18
|
#
|
18
|
-
# @api
|
19
|
+
# @api private
|
19
20
|
module Destinations
|
20
21
|
# Creates appropriate destination objects based on the given destination
|
21
22
|
#
|
22
23
|
# This factory method dynamically finds and instantiates the appropriate
|
23
24
|
# destination class for handling the provided destination.
|
24
25
|
#
|
26
|
+
# @example
|
27
|
+
# ProcessExecuter::Destinations.factory(1) #=> Returns a Stdout instance
|
28
|
+
# ProcessExecuter::Destinations.factory("output.log") #=> Returns a FilePath instance
|
29
|
+
#
|
25
30
|
# @param destination [Object] the destination to create a handler for
|
26
|
-
# @return [DestinationBase] an instance of the appropriate destination handler
|
27
|
-
# @raise [ArgumentError] if no matching destination class is found
|
28
31
|
#
|
29
|
-
# @
|
30
|
-
#
|
31
|
-
#
|
32
|
+
# @return [ProcessExecuter::Destinations::DestinationBase] an instance of the
|
33
|
+
# appropriate destination handler
|
34
|
+
#
|
35
|
+
# @raise [ProcessExecuter::ArgumentError] if no matching destination class is found
|
36
|
+
#
|
32
37
|
def self.factory(destination)
|
33
38
|
matching_class = matching_destination_class(destination)
|
34
39
|
return matching_class.new(destination) if matching_class
|
35
40
|
|
36
|
-
raise ArgumentError,
|
41
|
+
raise ProcessExecuter::ArgumentError, "Destination #{destination.inspect} is not compatible with MonitoredPipe"
|
37
42
|
end
|
38
43
|
|
39
|
-
# Determines if the given destination
|
44
|
+
# Determines if the given destination type can be managed by a {MonitoredPipe}
|
45
|
+
#
|
46
|
+
# Returns true if {MonitoredPipe} can forward data to this destination type.
|
40
47
|
#
|
41
|
-
#
|
48
|
+
# Returns false otherwise (e.g., for destinations like :close or [:child, fd]
|
49
|
+
# which have special meaning to Process.spawn and are not simply data sinks for
|
50
|
+
# {MonitoredPipe}).
|
42
51
|
#
|
43
52
|
# @example
|
44
|
-
# ProcessExecuter::Destinations.compatible_with_monitored_pipe?(1)
|
45
|
-
#
|
46
|
-
# ProcessExecuter::Destinations.compatible_with_monitored_pipe?([:
|
53
|
+
# ProcessExecuter::Destinations.compatible_with_monitored_pipe?(1)
|
54
|
+
# #=> true
|
55
|
+
# ProcessExecuter::Destinations.compatible_with_monitored_pipe?([:child, 6])
|
56
|
+
# #=> false
|
57
|
+
# ProcessExecuter::Destinations.compatible_with_monitored_pipe?(:close)
|
58
|
+
# #=> false
|
47
59
|
#
|
48
60
|
# @param destination [Object] the destination to check
|
49
|
-
#
|
50
|
-
# @
|
51
|
-
#
|
61
|
+
#
|
62
|
+
# @return [Boolean] true if {MonitoredPipe} can forward data to this destination type
|
63
|
+
#
|
52
64
|
def self.compatible_with_monitored_pipe?(destination)
|
53
65
|
matching_class = matching_destination_class(destination)
|
54
66
|
matching_class&.compatible_with_monitored_pipe?
|
55
67
|
end
|
56
68
|
|
57
69
|
# Determines the destination class that can handle the given destination
|
70
|
+
#
|
58
71
|
# @param destination [Object] the destination to check
|
59
|
-
#
|
60
|
-
# @
|
72
|
+
#
|
73
|
+
# @return [Class, nil] the handler class for the given destination or `nil` if no match
|
74
|
+
#
|
61
75
|
def self.matching_destination_class(destination)
|
62
76
|
destination_classes =
|
63
77
|
ProcessExecuter::Destinations.constants
|
64
78
|
.map { |const| ProcessExecuter::Destinations.const_get(const) }
|
65
79
|
.select { |const| const.is_a?(Class) }
|
80
|
+
.reject { |klass| klass == ProcessExecuter::Destinations::DestinationBase }
|
66
81
|
|
67
82
|
destination_classes.find { |klass| klass.handles?(destination) }
|
68
83
|
end
|
@@ -1,18 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable Layout/LineLength
|
4
|
-
|
5
3
|
module ProcessExecuter
|
6
|
-
#
|
4
|
+
# rubocop:disable Layout/LineLength
|
5
|
+
|
6
|
+
# Base class for all {ProcessExecuter} errors
|
7
7
|
#
|
8
|
-
# It is recommended to rescue
|
9
|
-
#
|
8
|
+
# It is recommended to rescue {ProcessExecuter::Error} to catch any runtime error
|
9
|
+
# raised by this gem unless you need more specific error handling.
|
10
10
|
#
|
11
11
|
# Custom errors are arranged in the following class hierarchy:
|
12
12
|
#
|
13
13
|
# ```text
|
14
14
|
# ::StandardError
|
15
15
|
# └─> Error
|
16
|
+
# ├─> ArgumentError
|
16
17
|
# ├─> CommandError
|
17
18
|
# │ ├─> FailedError
|
18
19
|
# │ └─> SignaledError
|
@@ -24,16 +25,17 @@ module ProcessExecuter
|
|
24
25
|
# | Error Class | Description |
|
25
26
|
# | --- | --- |
|
26
27
|
# | `Error` | This catch-all error serves as the base class for other custom errors. |
|
28
|
+
# | `ArgumentError` | Raised when an invalid argument is passed to a method. |
|
27
29
|
# | `CommandError` | A subclass of this error is raised when there is a problem executing a command. |
|
28
|
-
# | `FailedError` | Raised when the command exits with a non-zero status
|
30
|
+
# | `FailedError` | Raised when the command exits with a non-zero exit status. |
|
29
31
|
# | `SignaledError` | Raised when the command is terminated as a result of receiving a signal. This could happen if the process is forcibly terminated or if there is a serious system error. |
|
30
|
-
# | `TimeoutError` | This is a specific type of `SignaledError` that is raised when the command times out and is killed via the SIGKILL signal.
|
32
|
+
# | `TimeoutError` | This is a specific type of `SignaledError` that is raised when the command times out and is killed via the SIGKILL signal. |
|
31
33
|
# | `ProcessIOError` | Raised when an error was encountered reading or writing to the command's subprocess. |
|
32
|
-
# | `SpawnError` | Raised when the process could not execute. Check the |
|
34
|
+
# | `SpawnError` | Raised when the process could not execute. Check the `#cause` for the original exception from `Process.spawn`. |
|
33
35
|
#
|
34
36
|
# @example Rescuing any error
|
35
37
|
# begin
|
36
|
-
# ProcessExecuter.
|
38
|
+
# ProcessExecuter.run('git', 'status')
|
37
39
|
# rescue ProcessExecuter::Error => e
|
38
40
|
# puts "An error occurred: #{e.message}"
|
39
41
|
# end
|
@@ -41,23 +43,37 @@ module ProcessExecuter
|
|
41
43
|
# @example Rescuing a timeout error
|
42
44
|
# begin
|
43
45
|
# timeout_after = 0.1 # seconds
|
44
|
-
# ProcessExecuter.
|
46
|
+
# ProcessExecuter.run('sleep', '1', timeout_after:)
|
45
47
|
# rescue ProcessExecuter::TimeoutError => e # Catch the more specific error first!
|
46
48
|
# puts "Command took too long and timed out: #{e}"
|
47
49
|
# rescue ProcessExecuter::Error => e
|
48
|
-
# puts "Some other error
|
50
|
+
# puts "Some other error occurred: #{e}"
|
49
51
|
# end
|
50
52
|
#
|
51
53
|
# @api public
|
52
54
|
#
|
53
55
|
class Error < ::StandardError; end
|
54
56
|
|
57
|
+
# rubocop:enable Layout/LineLength
|
58
|
+
|
59
|
+
# Raised when an invalid argument is passed to a method
|
60
|
+
#
|
61
|
+
# @example Raising ProcessExecuter::ArgumentError due to invalid option value
|
62
|
+
# begin
|
63
|
+
# ProcessExecuter.run('echo Hello', timeout_after: 'not_a_number')
|
64
|
+
# rescue ProcessExecuter::ArgumentError => e
|
65
|
+
# e.message #=> 'timeout_after must be nil or a non-negative real number but was "not_a_number"'
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
#
|
70
|
+
class ArgumentError < ProcessExecuter::Error; end
|
71
|
+
|
55
72
|
# Raised when a command fails or exits because of an uncaught signal
|
56
73
|
#
|
57
|
-
# The command executed
|
58
|
-
# object.
|
74
|
+
# The command executed and its result are available from this object.
|
59
75
|
#
|
60
|
-
#
|
76
|
+
# This gem will raise a more specific error for each type of failure:
|
61
77
|
#
|
62
78
|
# * {FailedError}: when the command exits with a non-zero status
|
63
79
|
# * {SignaledError}: when the command exits because of an uncaught signal
|
@@ -70,12 +86,18 @@ module ProcessExecuter
|
|
70
86
|
#
|
71
87
|
# @example
|
72
88
|
# `exit 1` # set $? appropriately for this example
|
73
|
-
#
|
89
|
+
# result_data = {
|
90
|
+
# command: ['exit 1'],
|
91
|
+
# options: ProcessExecuter::Options::RunOptions.new,
|
92
|
+
# timed_out: false,
|
93
|
+
# elapsed_time: 0.01
|
94
|
+
# }
|
95
|
+
# result = ProcessExecuter::Result.new($?, **result_data)
|
74
96
|
# error = ProcessExecuter::CommandError.new(result)
|
75
|
-
# error.to_s #=> '["
|
97
|
+
# error.to_s #=> '["exit 1"], status: pid 29686 exit 1'
|
76
98
|
#
|
77
|
-
# @param result [Result] The result of the command including the
|
78
|
-
#
|
99
|
+
# @param result [ProcessExecuter::Result] The result of the command including the
|
100
|
+
# command and exit status
|
79
101
|
#
|
80
102
|
def initialize(result)
|
81
103
|
@result = result
|
@@ -85,12 +107,12 @@ module ProcessExecuter
|
|
85
107
|
# The human readable representation of this error
|
86
108
|
#
|
87
109
|
# @example
|
88
|
-
# error.error_message #=> '["git", "status"], status: pid 89784 exit 1
|
110
|
+
# error.error_message #=> '["git", "status"], status: pid 89784 exit 1'
|
89
111
|
#
|
90
112
|
# @return [String]
|
91
113
|
#
|
92
114
|
def error_message
|
93
|
-
"#{result.command}, status: #{result}
|
115
|
+
"#{result.command}, status: #{result}"
|
94
116
|
end
|
95
117
|
|
96
118
|
# @attribute [r] result
|
@@ -100,12 +122,12 @@ module ProcessExecuter
|
|
100
122
|
# @example
|
101
123
|
# error.result #=> #<ProcessExecuter::Result:0x00007f9b1b8b3d20>
|
102
124
|
#
|
103
|
-
# @return [Result]
|
125
|
+
# @return [ProcessExecuter::Result]
|
104
126
|
#
|
105
127
|
attr_reader :result
|
106
128
|
end
|
107
129
|
|
108
|
-
# Raised when the command returns a non-zero
|
130
|
+
# Raised when the command returns a non-zero exit status
|
109
131
|
#
|
110
132
|
# @api public
|
111
133
|
#
|
@@ -120,13 +142,17 @@ module ProcessExecuter
|
|
120
142
|
# Raised when the command takes longer than the configured timeout_after
|
121
143
|
#
|
122
144
|
# @example
|
123
|
-
#
|
145
|
+
# begin
|
146
|
+
# ProcessExecuter.spawn_with_timeout('sleep 1', timeout_after: 0.1)
|
147
|
+
# rescue ProcessExecuter::TimeoutError => e
|
148
|
+
# puts "Command timed out: #{e.result.command}"
|
149
|
+
# end
|
124
150
|
#
|
125
151
|
# @api public
|
126
152
|
#
|
127
153
|
class TimeoutError < ProcessExecuter::SignaledError; end
|
128
154
|
|
129
|
-
# Raised
|
155
|
+
# Raised if an exception occurred while processing subprocess output
|
130
156
|
#
|
131
157
|
# @api public
|
132
158
|
#
|
@@ -140,5 +166,3 @@ module ProcessExecuter
|
|
140
166
|
#
|
141
167
|
class SpawnError < ProcessExecuter::Error; end
|
142
168
|
end
|
143
|
-
|
144
|
-
# rubocop:enable Layout/LineLength
|