ruby-sh 2.1.4 → 3.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.
@@ -1,5 +1,3 @@
1
- require "timeout"
2
-
3
1
  module Rubsh
4
2
  class RunningCommand
5
3
  SPECIAL_KWARGS = %i[
@@ -20,15 +18,6 @@ module Rubsh
20
18
  _no_err
21
19
  _long_sep
22
20
  _long_prefix
23
- _pipeline
24
- ]
25
-
26
- SPECIAL_KWARGS_WITHIN_PIPELINE = %i[
27
- _env
28
- _cwd
29
- _long_sep
30
- _long_prefix
31
- _pipeline
32
21
  ]
33
22
 
34
23
  # @!attribute [r] pid
@@ -39,6 +28,14 @@ module Rubsh
39
28
  # @return [Number]
40
29
  attr_reader :exit_code
41
30
 
31
+ # @!attribute [r] started_at
32
+ # @return [Time]
33
+ attr_reader :started_at
34
+
35
+ # @!attribute [r] finished_at
36
+ # @return [Time]
37
+ attr_reader :finished_at
38
+
42
39
  # @!attribute [r] stdout_data
43
40
  # @return [String]
44
41
  attr_reader :stdout_data
@@ -47,8 +44,7 @@ module Rubsh
47
44
  # @return [String]
48
45
  attr_reader :stderr_data
49
46
 
50
- def initialize(sh, prog, progpath, *args, **kwargs)
51
- @sh = sh
47
+ def initialize(prog, progpath, *args, **kwargs)
52
48
  @prog = prog
53
49
  @progpath = progpath
54
50
  @args = []
@@ -57,6 +53,8 @@ module Rubsh
57
53
  @prog_with_args = nil
58
54
  @pid = nil
59
55
  @exit_code = nil
56
+ @started_at = nil
57
+ @finished_at = nil
60
58
  @stdout_data = "".force_encoding(::Encoding.default_external)
61
59
  @stderr_data = "".force_encoding(::Encoding.default_external)
62
60
  @in_rd = nil
@@ -93,9 +91,6 @@ module Rubsh
93
91
  @_long_sep = "="
94
92
  @_long_prefix = "--"
95
93
 
96
- # Special Kwargs - Misc
97
- @_pipeline = nil
98
-
99
94
  opts = []
100
95
  args.each do |arg|
101
96
  if arg.is_a?(::Hash)
@@ -105,92 +100,43 @@ module Rubsh
105
100
  end
106
101
  end
107
102
  kwargs.each { |k, v| opts << Option.build(k, v) }
108
- validate_opts(opts)
109
103
  extract_opts(opts)
110
104
  end
111
105
 
112
- # @return [void]
113
- def wait(timeout: nil)
114
- timeout_occurred = false
115
- _, status = nil, nil
116
-
117
- if timeout
118
- begin
119
- ::Timeout.timeout(timeout) { _, status = ::Process.wait2(@pid) }
120
- rescue ::Timeout::Error
121
- timeout_occurred = true
122
-
123
- ::Process.kill("TERM", @pid) # graceful stop
124
- 30.times do
125
- _, status = ::Process.wait2(@pid, ::Process::WNOHANG | ::Process::WUNTRACED)
126
- break if status
127
- sleep 0.1
128
- end
129
- failure = @pid if status.nil?
130
- failure && ::Process.kill("KILL", failure) # forceful stop
131
- end
132
- else
133
- _, status = ::Process.wait2(@pid)
134
- end
135
-
136
- @exit_code = status&.exitstatus
137
- raise Exceptions::CommandTimeoutError, "execution expired" if timeout_occurred
138
- rescue Errno::ECHILD, Errno::ESRCH
139
- raise Exceptions::CommandTimeoutError, "execution expired" if timeout_occurred
140
- ensure
141
- @out_rd_reader&.wait
142
- @err_rd_reader&.wait
106
+ # @return [Numeric, nil]
107
+ def wall_time
108
+ @finished_at.nil? ? nil : @finished_at - @started_at
143
109
  end
110
+ alias_method :execution_time, :wall_time
144
111
 
145
- # @return [String]
146
- def inspect
147
- format("#<Rubsh::RunningCommand '%s'>", @prog_with_args)
112
+ # @return [Boolean]
113
+ def ok?
114
+ @_ok_code.include?(@exit_code)
148
115
  end
149
116
 
150
117
  # @!visibility private
151
118
  def __run
152
- if @_pipeline
153
- @_pipeline.__add_running_command(self)
119
+ if @_bg
120
+ spawn
154
121
  else
155
- @_bg ? run_in_background : run_in_foreground
122
+ spawn
123
+ wait(timeout: @_timeout)
156
124
  end
157
125
  end
158
126
 
159
- # @!visibility private
160
- def __spawn_arguments(env: nil, cwd: nil, redirection_args: nil)
161
- env ||= @_env
162
- cmd_args = compile_cmd_args
163
- redirection_args ||= compile_redirection_args
164
- extra_args = compile_extra_args(cwd: cwd)
165
-
166
- # For logging
167
- @prog_with_args = [@progpath].concat(cmd_args).join(" ")
168
-
169
- # .
170
- _args =
171
- if env
172
- [env, [@progpath, @prog], *cmd_args, **redirection_args, **extra_args, unsetenv_others: true]
173
- else
174
- [[@progpath, @prog], *cmd_args, **redirection_args, **extra_args]
175
- end
127
+ # @return [void]
128
+ def wait(timeout: nil)
129
+ wait2(@pid, timeout)
130
+ handle_return_code
176
131
  end
177
132
 
178
- # @!visibility private
179
- def __prog_with_args
133
+ # @return [String]
134
+ def to_s
180
135
  @prog_with_args
181
136
  end
182
137
 
183
138
  private
184
139
 
185
- def validate_opts(opts)
186
- within_pipeline = opts.any? { |opt| opt.special_kwarg?(:_pipeline) }
187
- within_pipeline && opts.each do |opt|
188
- if opt.special_kwarg? && !SPECIAL_KWARGS_WITHIN_PIPELINE.include?(opt.k.to_sym)
189
- raise ::ArgumentError, format("unsupported special kwargs within _pipeline `%s'", opt.k)
190
- end
191
- end
192
- end
193
-
194
140
  def extract_opts(opts)
195
141
  args_hash = {}
196
142
  opts.each do |opt|
@@ -208,6 +154,8 @@ module Rubsh
208
154
  @args << arg
209
155
  end
210
156
  end
157
+
158
+ raise ::ArgumentError, "kwargs :_bg conflicts with kwargs :_timeout" if @_bg && @_timeout
211
159
  end
212
160
 
213
161
  def extract_special_kwargs_opts(opt)
@@ -246,11 +194,52 @@ module Rubsh
246
194
  @_long_sep = opt.v
247
195
  when :_long_prefix
248
196
  @_long_prefix = opt.v
249
- when :_pipeline
250
- @_pipeline = opt.v
251
197
  end
252
198
  end
253
199
 
200
+ def spawn
201
+ args = spawn_arguments
202
+ @pid = ::Process.spawn(*args)
203
+ @started_at = Time.now
204
+ @in_wr&.write(@_in_data) if @_in_data
205
+ @in_wr&.close
206
+
207
+ if @out_rd
208
+ @out_rd_reader = StreamReader.new(@out_rd, bufsize: @_capture ? @_out_bufsize : nil, &proc { |chunk|
209
+ @stdout_data << chunk unless @_no_out
210
+ @_capture&.call(chunk, nil)
211
+ })
212
+ end
213
+ if @err_rd
214
+ @err_rd_reader = StreamReader.new(@err_rd, bufsize: @_capture ? @_err_bufsize : nil, &proc { |chunk|
215
+ @stderr_data << chunk unless @_no_err
216
+ @_capture&.call(nil, chunk)
217
+ })
218
+ end
219
+ ensure
220
+ @in_rd&.close
221
+ @out_wr&.close
222
+ @err_wr&.close
223
+ end
224
+
225
+ def spawn_arguments
226
+ env = @_env
227
+ cmd_args = compile_cmd_args
228
+ redirection_args = compile_redirection_args
229
+ extra_args = compile_extra_args
230
+
231
+ # For logging
232
+ @prog_with_args = [@progpath].concat(cmd_args).join(" ")
233
+
234
+ # .
235
+ _args =
236
+ if env
237
+ [env, [@progpath, @prog], *cmd_args, **redirection_args, **extra_args, unsetenv_others: true]
238
+ else
239
+ [[@progpath, @prog], *cmd_args, **redirection_args, **extra_args]
240
+ end
241
+ end
242
+
254
243
  def compile_cmd_args
255
244
  @args.map { |arg| arg.compile(long_sep: @_long_sep, long_prefix: @_long_prefix) }.compact.flatten
256
245
  end
@@ -285,53 +274,47 @@ module Rubsh
285
274
  args
286
275
  end
287
276
 
288
- def compile_extra_args(cwd: nil)
289
- chdir = cwd || @_cwd
290
-
277
+ def compile_extra_args
291
278
  args = {}
292
- args[:chdir] = chdir if chdir
279
+ args[:chdir] = @_cwd if @_cwd
293
280
  args
294
281
  end
295
282
 
296
- def spawn
297
- args = __spawn_arguments
298
- @pid = ::Process.spawn(*args)
299
- @in_wr&.write(@_in_data) if @_in_data
300
- @in_wr&.close
283
+ def wait2(pid, timeout)
284
+ timeout_occurred = false
285
+ _, status = nil, nil
301
286
 
302
- if @out_rd
303
- @out_rd_reader = StreamReader.new(@out_rd, bufsize: @_capture ? @_out_bufsize : nil, &proc { |chunk|
304
- @stdout_data << chunk unless @_no_out
305
- @_capture&.call(chunk, nil)
306
- })
307
- end
308
- if @err_rd
309
- @err_rd_reader = StreamReader.new(@err_rd, bufsize: @_capture ? @_err_bufsize : nil, &proc { |chunk|
310
- @stderr_data << chunk unless @_no_err
311
- @_capture&.call(nil, chunk)
312
- })
287
+ if timeout
288
+ begin
289
+ ::Timeout.timeout(timeout) { _, status = ::Process.wait2(pid) }
290
+ rescue ::Timeout::Error
291
+ timeout_occurred = true
292
+
293
+ ::Process.kill("TERM", pid) # graceful stop
294
+ 30.times do
295
+ _, status = ::Process.wait2(pid, ::Process::WNOHANG | ::Process::WUNTRACED)
296
+ break if status
297
+ sleep 0.1
298
+ end
299
+ failure = pid if status.nil?
300
+ failure && ::Process.kill("KILL", failure) # forceful stop
301
+ end
302
+ else
303
+ _, status = ::Process.wait2(pid)
313
304
  end
305
+
306
+ @exit_code = status&.exitstatus || -1
307
+ @finished_at = Time.now
308
+ raise Exceptions::CommandTimeoutError, "execution expired" if timeout_occurred
314
309
  ensure
315
- @in_rd&.close
316
- @out_wr&.close
317
- @err_wr&.close
310
+ @out_rd_reader&.wait
311
+ @err_rd_reader&.wait
318
312
  end
319
313
 
320
314
  def handle_return_code
321
- return if @_ok_code.include?(@exit_code)
322
- message = format("\n\n RAN: %s\n\n STDOUT:\n%s\n STDERR:\n%s\n", @prog_with_args, @stdout_data, @stderr_data)
315
+ return if ok?
316
+ message = format("\n\n $?: %s\n\n RAN: %s\n\n STDOUT:\n%s\n\n STDERR:\n%s\n", @exit_code, @prog_with_args, @stdout_data, @stderr_data)
323
317
  raise Exceptions::CommandReturnFailureError.new(@exit_code, message)
324
318
  end
325
-
326
- def run_in_background
327
- spawn
328
- Process.detach(@pid)
329
- end
330
-
331
- def run_in_foreground
332
- spawn
333
- wait(timeout: @_timeout)
334
- handle_return_code
335
- end
336
319
  end
337
320
  end
data/lib/rubsh/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubsh
4
- VERSION = "2.1.4"
4
+ VERSION = "3.0.0"
5
5
  end
data/lib/rubsh.rb CHANGED
@@ -1,12 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "timeout"
4
+
3
5
  require_relative "rubsh/argument"
4
6
  require_relative "rubsh/command"
5
7
  require_relative "rubsh/exceptions"
6
8
  require_relative "rubsh/option"
7
9
  require_relative "rubsh/running_command"
8
- require_relative "rubsh/running_pipeline"
9
- require_relative "rubsh/shell/env"
10
- require_relative "rubsh/shell"
11
10
  require_relative "rubsh/stream_reader"
12
11
  require_relative "rubsh/version"
12
+
13
+ module Rubsh
14
+ def self.cmd(prog)
15
+ Command.new(prog)
16
+ end
17
+ end
data/rubsh.gemspec CHANGED
@@ -10,13 +10,13 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = "Rubsh (a.k.a. ruby-sh) - Inspired by python-sh, allows you to call any program as if it were a function."
12
12
  spec.description = "Rubsh (a.k.a. ruby-sh) - Inspired by python-sh, allows you to call any program as if it were a function."
13
- spec.homepage = "https://github.com/souk4711/rubsh"
13
+ spec.homepage = "https://github.com/souk4711/ruby-sh"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 2.7.0"
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://github.com/souk4711/rubsh"
19
- spec.metadata["changelog_uri"] = "https://github.com/souk4711/rubsh"
18
+ spec.metadata["source_code_uri"] = "https://github.com/souk4711/ruby-sh"
19
+ spec.metadata["changelog_uri"] = "https://github.com/souk4711/ruby-sh"
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-sh
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.4
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Doe
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2022-06-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: Rubsh (a.k.a. ruby-sh) - Inspired by python-sh, allows you to call any
14
13
  program as if it were a function.
@@ -18,10 +17,10 @@ executables: []
18
17
  extensions: []
19
18
  extra_rdoc_files: []
20
19
  files:
21
- - ".overcommit.yml"
20
+ - ".editorconfig"
22
21
  - ".rspec"
23
- - ".rubocop"
24
22
  - ".rubocop.yml"
23
+ - ".ruby-version"
25
24
  - ".yardopts"
26
25
  - CODE_OF_CONDUCT.md
27
26
  - Gemfile
@@ -35,22 +34,17 @@ files:
35
34
  - lib/rubsh/exceptions.rb
36
35
  - lib/rubsh/option.rb
37
36
  - lib/rubsh/running_command.rb
38
- - lib/rubsh/running_pipeline.rb
39
- - lib/rubsh/shell.rb
40
- - lib/rubsh/shell/env.rb
41
37
  - lib/rubsh/stream_reader.rb
42
38
  - lib/rubsh/version.rb
43
39
  - rubsh.gemspec
44
- - sig/rubsh.rbs
45
- homepage: https://github.com/souk4711/rubsh
40
+ homepage: https://github.com/souk4711/ruby-sh
46
41
  licenses:
47
42
  - MIT
48
43
  metadata:
49
- homepage_uri: https://github.com/souk4711/rubsh
50
- source_code_uri: https://github.com/souk4711/rubsh
51
- changelog_uri: https://github.com/souk4711/rubsh
44
+ homepage_uri: https://github.com/souk4711/ruby-sh
45
+ source_code_uri: https://github.com/souk4711/ruby-sh
46
+ changelog_uri: https://github.com/souk4711/ruby-sh
52
47
  rubygems_mfa_required: 'true'
53
- post_install_message:
54
48
  rdoc_options: []
55
49
  require_paths:
56
50
  - lib
@@ -65,8 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
59
  - !ruby/object:Gem::Version
66
60
  version: '0'
67
61
  requirements: []
68
- rubygems_version: 3.3.7
69
- signing_key:
62
+ rubygems_version: 3.6.9
70
63
  specification_version: 4
71
64
  summary: Rubsh (a.k.a. ruby-sh) - Inspired by python-sh, allows you to call any program
72
65
  as if it were a function.
data/.overcommit.yml DELETED
@@ -1,26 +0,0 @@
1
- # Use this file to configure the Overcommit hooks you wish to use. This will
2
- # extend the default configuration defined in:
3
- # https://github.com/sds/overcommit/blob/master/config/default.yml
4
- #
5
- # At the topmost level of this YAML file is a key representing type of hook
6
- # being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
7
- # customize each hook, such as whether to only run it on certain files (via
8
- # `include`), whether to only display output if it fails (via `quiet`), etc.
9
- #
10
- # For a complete list of hooks, see:
11
- # https://github.com/sds/overcommit/tree/master/lib/overcommit/hook
12
- #
13
- # For a complete list of options that you can use to customize hooks, see:
14
- # https://github.com/sds/overcommit#configuration
15
- #
16
- # Uncomment the following lines to make the configuration take effect.
17
-
18
- PreCommit:
19
- RuboCop:
20
- enabled: true
21
- command: 'bin/rubocop'
22
-
23
- PrePush:
24
- RSpec:
25
- enabled: true
26
- command: 'bin/rspec'
data/.rubocop DELETED
File without changes
@@ -1,243 +0,0 @@
1
- require "open3"
2
-
3
- module Rubsh
4
- class RunningPipeline
5
- SPECIAL_KWARGS = %i[
6
- _in_data
7
- _in
8
- _out
9
- _err
10
- _err_to_out
11
- _capture
12
- _bg
13
- _env
14
- _timeout
15
- _cwd
16
- _ok_code
17
- _out_bufsize
18
- _err_bufsize
19
- _no_out
20
- _no_err
21
- ]
22
-
23
- # @!attribute [r] exit_code
24
- # @return [Number]
25
- attr_reader :exit_code
26
-
27
- # @!attribute [r] stdout_data
28
- # @return [String]
29
- attr_reader :stdout_data
30
-
31
- # @!attribute [r] stderr_data
32
- # @return [String]
33
- attr_reader :stderr_data
34
-
35
- def initialize(sh)
36
- @sh = sh
37
- @rcmds = []
38
-
39
- # Runtime
40
- @prog_with_args = nil
41
- @exit_code = nil
42
- @stdout_data = "".force_encoding(::Encoding.default_external)
43
- @stderr_data = "".force_encoding(::Encoding.default_external)
44
- @in_rd = nil
45
- @in_wr = nil
46
- @out_rd = nil
47
- @out_wr = nil
48
- @err_rd = nil
49
- @err_wr = nil
50
- @out_rd_reader = nil
51
- @err_rd_reader = nil
52
- @waiters = []
53
-
54
- # Special Kwargs - Controlling Input/Output
55
- @_in_data = nil
56
- @_in = nil
57
- @_out = nil
58
- @_err = nil
59
- @_err_to_out = false
60
- @_capture = nil
61
-
62
- # Special Kwargs - Execution
63
- @_bg = false
64
- @_env = nil
65
- @_timeout = nil
66
- @_cwd = nil
67
- @_ok_code = [0]
68
-
69
- # Special Kwargs - Performance & Optimization
70
- @_out_bufsize = 0
71
- @_err_bufsize = 0
72
- @_no_out = false
73
- @_no_err = false
74
- end
75
-
76
- # @return [void]
77
- def wait(timeout: nil)
78
- timeout_occurred = false
79
- last_status = nil
80
-
81
- if timeout
82
- begin
83
- ::Timeout.timeout(timeout) { last_status = @waiters.map(&:value)[-1] }
84
- rescue ::Timeout::Error
85
- timeout_occurred = true
86
-
87
- failures = []
88
- @waiters.each { |w| ::Process.kill("TERM", w.pid) } # graceful stop
89
- @waiters.each { |w|
90
- _, status = nil, nil
91
- 30.times do
92
- _, status = ::Process.wait2(w.pid, ::Process::WNOHANG | ::Process::WUNTRACED)
93
- break if status
94
- sleep 0.1
95
- rescue ::Errno::ECHILD, ::Errno::ESRCH
96
- status = true
97
- end
98
- failures << w.pid if status.nil?
99
- }
100
- failures.each { |pid| ::Process.kill("KILL", pid) } # forceful stop
101
- end
102
- else
103
- last_status = @waiters.map(&:value)[-1]
104
- end
105
-
106
- @exit_code = last_status&.exitstatus
107
- raise Exceptions::CommandTimeoutError, "execution expired" if timeout_occurred
108
- rescue ::Errno::ECHILD, ::Errno::ESRCH
109
- raise Exceptions::CommandTimeoutError, "execution expired" if timeout_occurred
110
- ensure
111
- @out_rd_reader&.wait
112
- @err_rd_reader&.wait
113
- end
114
-
115
- # @return [String]
116
- def inspect
117
- format("#<Rubsh::RunningPipeline '%s'>", @prog_with_args)
118
- end
119
-
120
- # @!visibility private
121
- def __add_running_command(cmd)
122
- @rcmds << cmd
123
- end
124
-
125
- # @!visibility private
126
- def __run(**kwargs)
127
- raise Exceptions::CommandNotFoundError, format("no commands") if @rcmds.length == 0
128
- extract_opts(**kwargs)
129
- @_bg ? run_in_background : run_in_foreground
130
- end
131
-
132
- private
133
-
134
- def extract_opts(**kwargs)
135
- kwargs.each do |k, v|
136
- raise ::ArgumentError, format("unsupported special kwarg `%s'", k) unless SPECIAL_KWARGS.include?(k.to_sym)
137
- case k.to_sym
138
- when :_in_data
139
- @_in_data = v
140
- when :_in
141
- @_in = v
142
- when :_out
143
- @_out = v
144
- when :_err
145
- @_err = v
146
- when :_err_to_out
147
- @_err_to_out = v
148
- when :_capture
149
- @_capture = v
150
- when :_bg
151
- @_bg = v
152
- when :_env
153
- @_env = v.transform_keys(&:to_s).transform_values(&:to_s)
154
- when :_timeout
155
- @_timeout = v
156
- when :_cwd
157
- @_cwd = v
158
- when :_ok_code
159
- @_ok_code = [*v]
160
- when :_out_bufsize
161
- @_out_bufsize = v
162
- when :_err_bufsize
163
- @_err_bufsize = v
164
- when :_no_out
165
- @_no_out = v
166
- when :_no_err
167
- @_no_err = v
168
- end
169
- end
170
- end
171
-
172
- def compile_redirection_args
173
- args = {}
174
-
175
- if @_in
176
- args[:in] = @_in
177
- else
178
- @in_rd, @in_wr = ::IO.pipe
179
- @in_wr.sync = true
180
- args[:in] = @in_rd.fileno
181
- end
182
-
183
- if @_out
184
- args[:out] = @_out
185
- else
186
- @out_rd, @out_wr = ::IO.pipe
187
- args[:out] = @out_wr.fileno
188
- end
189
-
190
- if @_err_to_out
191
- args[:err] = [:child, :out]
192
- elsif @_err
193
- args[:err] = @_err
194
- else
195
- @err_rd, @err_wr = ::IO.pipe
196
- args[:err] = @err_wr.fileno
197
- end
198
-
199
- args
200
- end
201
-
202
- def spawn
203
- cmds = @rcmds.map { |r| r.__spawn_arguments(env: @_env, cwd: @_cwd, redirection_args: {}) }
204
- @prog_with_args = @rcmds.map(&:__prog_with_args).join(" | ")
205
- @waiters = ::Open3.pipeline_start(*cmds, compile_redirection_args)
206
- @in_wr&.write(@_in_data) if @_in_data
207
- @in_wr&.close
208
-
209
- if @out_rd
210
- @out_rd_reader = StreamReader.new(@out_rd, bufsize: @_capture ? @_out_bufsize : nil, &proc { |chunk|
211
- @stdout_data << chunk unless @_no_out
212
- @_capture&.call(chunk, nil)
213
- })
214
- end
215
- if @err_rd
216
- @err_rd_reader = StreamReader.new(@err_rd, bufsize: @_capture ? @_err_bufsize : nil, &proc { |chunk|
217
- @stderr_data << chunk unless @_no_err
218
- @_capture&.call(nil, chunk)
219
- })
220
- end
221
- ensure
222
- @in_rd&.close
223
- @out_wr&.close
224
- @err_wr&.close
225
- end
226
-
227
- def handle_return_code
228
- return if @_ok_code.include?(@exit_code)
229
- message = format("\n\n RAN: %s\n\n STDOUT:\n%s\n STDERR:\n%s\n", @prog_with_args, @stdout_data, @stderr_data)
230
- raise Exceptions::CommandReturnFailureError.new(@exit_code, message)
231
- end
232
-
233
- def run_in_background
234
- spawn
235
- end
236
-
237
- def run_in_foreground
238
- spawn
239
- wait(timeout: @_timeout)
240
- handle_return_code
241
- end
242
- end
243
- end