toys-core 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55fb96e74b22786912b754dbd969e5ead0825afe8ac8182f3a0b06520a46b867
4
- data.tar.gz: e85f258b34362a5ab66f47115805898807432560680bd6bde074b25979caa9cd
3
+ metadata.gz: a85fbb6170bb1609f304cc0b1a62d4743437802b64c796372d569856bdd1e256
4
+ data.tar.gz: 8291edf5cd82f0bbbcafb83878351415a28f8d0a21e058332184534c08e29751
5
5
  SHA512:
6
- metadata.gz: 408586c952bc613bed26f549883e39fecc49cca4c298bdd22b40fe44a365c2fe23bae0016622a54ddfeb69cf7b72357310183fc8bd56e4614e476480de9527a6
7
- data.tar.gz: 0afaf0c2a723277074e0b772b8166db55b5bc2d8f86150bd2a9367f5254ee770f9c82d09ef98d38c444b269ade5a59857b145f086609efb5bdc4176457ccc5c7
6
+ metadata.gz: 701ff10d98b0ae6f2b8c9d758c8dcb1769622a59dc3e86b85fedfae327811403c3ae514b05060eb91b701948cd275d94c86fa20973724864fc9c2b4aae355f90
7
+ data.tar.gz: b042cb80c9fb0f9d0d0132b546384179efc69873e4d060c20b7e2bc1b7c6e36721d27655e4efa4b77960cc899e726bbc47e92cbdbfd5cf2c18289dcde0b8e3cb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Release History
2
2
 
3
+ ### 0.4.3 / 2018-07-13
4
+
5
+ * IMPROVED: Utils::Exec methods can now spawn subprocesses in the background
6
+ * IMPROVED: Utils::Exec capture methods can now yield a controller
7
+
3
8
  ### 0.4.2 / 2018-07-08
4
9
 
5
10
  * FIXED: Raise an error rather than cause unexpected behavior if a mixin is included twice.
@@ -34,5 +34,5 @@ module Toys
34
34
  # Current version of Toys core
35
35
  # @return [String]
36
36
  #
37
- CORE_VERSION = "0.4.2"
37
+ CORE_VERSION = "0.4.3"
38
38
  end
@@ -100,8 +100,8 @@ module Toys
100
100
  # Execute a command. The command may be given as a single string to pass
101
101
  # to a shell, or an array of strings indicating a posix command.
102
102
  #
103
- # If you provide a block, a {Toys::Utils::Exec::Controller} will be
104
- # yielded to it, allowing you to interact with the subprocess streams.
103
+ # If the process is not set to run in the background, and a block is
104
+ # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
105
105
  #
106
106
  # @param [String,Array<String>] cmd The command to execute.
107
107
  # @param [Hash] opts The command options. All options listed in the
@@ -110,8 +110,9 @@ module Toys
110
110
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
111
111
  # the subprocess streams.
112
112
  #
113
- # @return [Toys::Utils::Exec::Result] The subprocess result, including
114
- # the exit code and any captured output.
113
+ # @return [Toys::Utils::Exec::Controller,Toys::Utils::Exec::Result] The
114
+ # subprocess controller or result, depending on whether the process
115
+ # is running in the background or foreground.
115
116
  #
116
117
  def exec(cmd, opts = {}, &block)
117
118
  self[KEY].exec(cmd, Exec._setup_exec_opts(opts, self), &block)
@@ -120,8 +121,8 @@ module Toys
120
121
  ##
121
122
  # Spawn a ruby process and pass the given arguments to it.
122
123
  #
123
- # If you provide a block, a {Toys::Utils::Exec::Controller} will be
124
- # yielded to it, allowing you to interact with the subprocess streams.
124
+ # If the process is not set to run in the background, and a block is
125
+ # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
125
126
  #
126
127
  # @param [String,Array<String>] args The arguments to ruby.
127
128
  # @param [Hash] opts The command options. All options listed in the
@@ -130,8 +131,9 @@ module Toys
130
131
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
131
132
  # for the subprocess streams.
132
133
  #
133
- # @return [Toys::Utils::Exec::Result] The subprocess result, including
134
- # the exit code and any captured output.
134
+ # @return [Toys::Utils::Exec::Controller,Toys::Utils::Exec::Result] The
135
+ # subprocess controller or result, depending on whether the process
136
+ # is running in the background or foreground.
135
137
  #
136
138
  def exec_ruby(args, opts = {}, &block)
137
139
  self[KEY].exec_ruby(args, Exec._setup_exec_opts(opts, self), &block)
@@ -141,8 +143,8 @@ module Toys
141
143
  ##
142
144
  # Execute a proc in a subprocess.
143
145
  #
144
- # If you provide a block, a {Toys::Utils::Exec::Controller} will be
145
- # yielded to it, allowing you to interact with the subprocess streams.
146
+ # If the process is not set to run in the background, and a block is
147
+ # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
146
148
  #
147
149
  # @param [Proc] func The proc to call.
148
150
  # @param [Hash] opts The command options. Most options listed in the
@@ -151,8 +153,9 @@ module Toys
151
153
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
152
154
  # for the subprocess streams.
153
155
  #
154
- # @return [Toys::Utils::Exec::Result] The subprocess result, including
155
- # exit code and any captured output.
156
+ # @return [Toys::Utils::Exec::Controller,Toys::Utils::Exec::Result] The
157
+ # subprocess controller or result, depending on whether the process
158
+ # is running in the background or foreground.
156
159
  #
157
160
  def exec_proc(func, opts = {}, &block)
158
161
  self[KEY].exec_proc(func, Exec._setup_exec_opts(opts, self), &block)
@@ -162,8 +165,8 @@ module Toys
162
165
  # Execute a tool. The command may be given as a single string or an array
163
166
  # of strings, representing the tool to run and the arguments to pass.
164
167
  #
165
- # If you provide a block, a {Toys::Utils::Exec::Controller} will be
166
- # yielded to it, allowing you to interact with the subprocess streams.
168
+ # If the process is not set to run in the background, and a block is
169
+ # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
167
170
  #
168
171
  # @param [String,Array<String>] cmd The tool to execute.
169
172
  # @param [Hash] opts The command options. Most options listed in the
@@ -172,8 +175,9 @@ module Toys
172
175
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
173
176
  # for the subprocess streams.
174
177
  #
175
- # @return [Toys::Utils::Exec::Result] The subprocess result, including
176
- # exit code and any captured output.
178
+ # @return [Toys::Utils::Exec::Controller,Toys::Utils::Exec::Result] The
179
+ # subprocess controller or result, depending on whether the process
180
+ # is running in the background or foreground.
177
181
  #
178
182
  def exec_tool(cmd, opts = {}, &block)
179
183
  func = Exec._make_tool_caller(cmd)
@@ -185,48 +189,66 @@ module Toys
185
189
  # to a shell, or an array of strings indicating a posix command.
186
190
  #
187
191
  # Captures standard out and returns it as a string.
192
+ # Cannot be run in the background.
193
+ #
194
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
195
+ # yielded to it.
188
196
  #
189
197
  # @param [String,Array<String>] cmd The command to execute.
190
198
  # @param [Hash] opts The command options. All options listed in the
191
199
  # {Toys::Utils::Exec} documentation are supported, plus the
192
200
  # `exit_on_nonzero_status` option.
201
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
202
+ # for the subprocess streams.
193
203
  #
194
204
  # @return [String] What was written to standard out.
195
205
  #
196
- def capture(cmd, opts = {})
197
- self[KEY].capture(cmd, Exec._setup_exec_opts(opts, self))
206
+ def capture(cmd, opts = {}, &block)
207
+ self[KEY].capture(cmd, Exec._setup_exec_opts(opts, self), &block)
198
208
  end
199
209
 
200
210
  ##
201
211
  # Spawn a ruby process and pass the given arguments to it.
202
212
  #
203
213
  # Captures standard out and returns it as a string.
214
+ # Cannot be run in the background.
215
+ #
216
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
217
+ # yielded to it.
204
218
  #
205
219
  # @param [String,Array<String>] args The arguments to ruby.
206
220
  # @param [Hash] opts The command options. All options listed in the
207
221
  # {Toys::Utils::Exec} documentation are supported, plus the
208
222
  # `exit_on_nonzero_status` option.
223
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
224
+ # for the subprocess streams.
209
225
  #
210
226
  # @return [String] What was written to standard out.
211
227
  #
212
- def capture_ruby(args, opts = {})
213
- self[KEY].capture_ruby(args, Exec._setup_exec_opts(opts, self))
228
+ def capture_ruby(args, opts = {}, &block)
229
+ self[KEY].capture_ruby(args, Exec._setup_exec_opts(opts, self), &block)
214
230
  end
215
231
 
216
232
  ##
217
233
  # Execute a proc in a subprocess.
218
234
  #
219
235
  # Captures standard out and returns it as a string.
236
+ # Cannot be run in the background.
237
+ #
238
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
239
+ # yielded to it.
220
240
  #
221
241
  # @param [Proc] func The proc to call.
222
242
  # @param [Hash] opts The command options. Most options listed in the
223
243
  # {Toys::Utils::Exec} documentation are supported, plus the
224
244
  # `exit_on_nonzero_status` option.
245
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
246
+ # for the subprocess streams.
225
247
  #
226
248
  # @return [String] What was written to standard out.
227
249
  #
228
- def capture_proc(func, opts = {})
229
- self[KEY].capture_proc(func, Exec._setup_exec_opts(opts, self))
250
+ def capture_proc(func, opts = {}, &block)
251
+ self[KEY].capture_proc(func, Exec._setup_exec_opts(opts, self), &block)
230
252
  end
231
253
 
232
254
  ##
@@ -234,31 +256,43 @@ module Toys
234
256
  # of strings, representing the tool to run and the arguments to pass.
235
257
  #
236
258
  # Captures standard out and returns it as a string.
259
+ # Cannot be run in the background.
260
+ #
261
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
262
+ # yielded to it.
237
263
  #
238
264
  # @param [String,Array<String>] cmd The tool to execute.
239
265
  # @param [Hash] opts The command options. Most options listed in the
240
266
  # {Toys::Utils::Exec} documentation are supported, plus the
241
267
  # `exit_on_nonzero_status` option.
268
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
269
+ # for the subprocess streams.
242
270
  #
243
271
  # @return [String] What was written to standard out.
244
272
  #
245
- def capture_tool(cmd, opts = {})
273
+ def capture_tool(cmd, opts = {}, &block)
246
274
  func = Exec._make_tool_caller(cmd)
247
- self[KEY].capture_proc(func, Exec._setup_exec_opts(opts, self))
275
+ self[KEY].capture_proc(func, Exec._setup_exec_opts(opts, self), &block)
248
276
  end
249
277
 
250
278
  ##
251
279
  # Execute the given string in a shell. Returns the exit code.
280
+ # Cannot be run in the background.
281
+ #
282
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
283
+ # yielded to it.
252
284
  #
253
285
  # @param [String] cmd The shell command to execute.
254
286
  # @param [Hash] opts The command options. All options listed in the
255
287
  # {Toys::Utils::Exec} documentation are supported, plus the
256
288
  # `exit_on_nonzero_status` option.
289
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
290
+ # for the subprocess streams.
257
291
  #
258
292
  # @return [Integer] The exit code
259
293
  #
260
- def sh(cmd, opts = {})
261
- self[KEY].sh(cmd, Exec._setup_exec_opts(opts, self))
294
+ def sh(cmd, opts = {}, &block)
295
+ self[KEY].sh(cmd, Exec._setup_exec_opts(opts, self), &block)
262
296
  end
263
297
 
264
298
  ##
@@ -82,6 +82,7 @@ module Toys
82
82
  def puts(str = "", *styles)
83
83
  terminal.puts(str, *styles)
84
84
  end
85
+ alias say puts
85
86
 
86
87
  ##
87
88
  # @see Toys::Utils::Terminal#write
@@ -50,6 +50,8 @@ module Toys
50
50
  # If not present, the command is not logged.
51
51
  # * **:log_level** (Integer) Log level for logging the actual command.
52
52
  # Defaults to Logger::INFO if not present.
53
+ # * **:background** (Boolean) Runs the process in the background,
54
+ # returning a controller object instead of a result object.
53
55
  # * **:in** Connects the input stream of the subprocess. See the section
54
56
  # on stream handling.
55
57
  # * **:out** Connects the standard output stream of the subprocess. See
@@ -95,7 +97,11 @@ module Toys
95
97
  # `Process#spawn`.
96
98
  # * **Redirect to null:** You may redirect to a null stream by passing
97
99
  # `:null` as the option value. This connects to a stream that is not
98
- # closed but contains no data, i.e. `/dev/null` on unix systems.
100
+ # closed but contains no data, i.e. `/dev/null` on unix systems. This is
101
+ # the default if the subprocess is run in the background.
102
+ # * **Inherit parent stream:** You may inherit the corresponding stream in
103
+ # the parent process by passing `:inherit` as the option value. This is
104
+ # the default if the subprocess is *not* run in the background.
99
105
  # * **Redirect to a file:** You may redirect to a file. This reads from an
100
106
  # existing file when connected to `:in`, and creates or appends to a
101
107
  # file when connected to `:out` or `:err`. To specify a file, use the
@@ -147,8 +153,8 @@ module Toys
147
153
  # Execute a command. The command may be given as a single string to pass
148
154
  # to a shell, or an array of strings indicating a posix command.
149
155
  #
150
- # If you provide a block, a {Toys::Utils::Exec::Controller} will be
151
- # yielded to it, allowing you to interact with the subprocess streams.
156
+ # If the process is not set to run in the background, and a block is
157
+ # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
152
158
  #
153
159
  # @param [String,Array<String>] cmd The command to execute.
154
160
  # @param [Hash] opts The command options. See the section on
@@ -156,8 +162,9 @@ module Toys
156
162
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
157
163
  # for the subprocess streams.
158
164
  #
159
- # @return [Toys::Utils::Exec::Result] The subprocess result, including
160
- # exit code and any captured output.
165
+ # @return [Toys::Utils::Exec::Controller,Toys::Utils::Exec::Result] The
166
+ # subprocess controller or result, depending on whether the process
167
+ # is running in the background or foreground.
161
168
  #
162
169
  def exec(cmd, opts = {}, &block)
163
170
  exec_opts = Opts.new(@default_opts).add(opts)
@@ -171,15 +178,15 @@ module Toys
171
178
  else
172
179
  [cmd]
173
180
  end
174
- executor = Executor.new(exec_opts, spawn_cmd)
175
- executor.execute(&block)
181
+ executor = Executor.new(exec_opts, spawn_cmd, block)
182
+ executor.execute
176
183
  end
177
184
 
178
185
  ##
179
186
  # Spawn a ruby process and pass the given arguments to it.
180
187
  #
181
- # If you provide a block, a {Toys::Utils::Exec::Controller} will be
182
- # yielded to it, allowing you to interact with the subprocess streams.
188
+ # If the process is not set to run in the background, and a block is
189
+ # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
183
190
  #
184
191
  # @param [String,Array<String>] args The arguments to ruby.
185
192
  # @param [Hash] opts The command options. See the section on
@@ -187,8 +194,9 @@ module Toys
187
194
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
188
195
  # for the subprocess streams.
189
196
  #
190
- # @return [Toys::Utils::Exec::Result] The subprocess result, including
191
- # exit code and any captured output.
197
+ # @return [Toys::Utils::Exec::Controller,Toys::Utils::Exec::Result] The
198
+ # subprocess controller or result, depending on whether the process
199
+ # is running in the background or foreground.
192
200
  #
193
201
  def exec_ruby(args, opts = {}, &block)
194
202
  cmd = args.is_a?(::Array) ? [::RbConfig.ruby] + args : "#{::RbConfig.ruby} #{args}"
@@ -200,8 +208,8 @@ module Toys
200
208
  ##
201
209
  # Execute a proc in a fork.
202
210
  #
203
- # If you provide a block, a {Toys::Utils::Exec::Controller} will be
204
- # yielded to it, allowing you to interact with the subprocess streams.
211
+ # If the process is not set to run in the background, and a block is
212
+ # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
205
213
  #
206
214
  # @param [Proc] func The proc to call.
207
215
  # @param [Hash] opts The command options. See the section on
@@ -209,13 +217,14 @@ module Toys
209
217
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
210
218
  # for the subprocess streams.
211
219
  #
212
- # @return [Toys::Utils::Exec::Result] The subprocess result, including
213
- # exit code and any captured output.
220
+ # @return [Toys::Utils::Exec::Controller,Toys::Utils::Exec::Result] The
221
+ # subprocess controller or result, depending on whether the process
222
+ # is running in the background or foreground.
214
223
  #
215
224
  def exec_proc(func, opts = {}, &block)
216
225
  exec_opts = Opts.new(@default_opts).add(opts)
217
- executor = Executor.new(exec_opts, func)
218
- executor.execute(&block)
226
+ executor = Executor.new(exec_opts, func, block)
227
+ executor.execute
219
228
  end
220
229
 
221
230
  ##
@@ -223,58 +232,79 @@ module Toys
223
232
  # to a shell, or an array of strings indicating a posix command.
224
233
  #
225
234
  # Captures standard out and returns it as a string.
235
+ # Cannot be run in the background.
236
+ #
237
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
238
+ # yielded to it.
226
239
  #
227
240
  # @param [String,Array<String>] cmd The command to execute.
228
241
  # @param [Hash] opts The command options. See the section on
229
242
  # configuration options in the {Toys::Utils::Exec} module docs.
243
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
244
+ # for the subprocess streams.
230
245
  #
231
246
  # @return [String] What was written to standard out.
232
247
  #
233
- def capture(cmd, opts = {})
234
- exec(cmd, opts.merge(out: :capture)).captured_out
248
+ def capture(cmd, opts = {}, &block)
249
+ exec(cmd, opts.merge(out: :capture, background: false), &block).captured_out
235
250
  end
236
251
 
237
252
  ##
238
253
  # Spawn a ruby process and pass the given arguments to it.
239
254
  #
240
255
  # Captures standard out and returns it as a string.
256
+ # Cannot be run in the background.
257
+ #
258
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
259
+ # yielded to it.
241
260
  #
242
261
  # @param [String,Array<String>] args The arguments to ruby.
243
262
  # @param [Hash] opts The command options. See the section on
244
263
  # configuration options in the {Toys::Utils::Exec} module docs.
264
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
265
+ # for the subprocess streams.
245
266
  #
246
267
  # @return [String] What was written to standard out.
247
268
  #
248
- def capture_ruby(args, opts = {})
249
- ruby(args, opts.merge(out: :capture)).captured_out
269
+ def capture_ruby(args, opts = {}, &block)
270
+ ruby(args, opts.merge(out: :capture, background: false), &block).captured_out
250
271
  end
251
272
 
252
273
  ##
253
274
  # Execute a proc in a fork.
254
275
  #
255
276
  # Captures standard out and returns it as a string.
277
+ # Cannot be run in the background.
278
+ #
279
+ # If a block is provided, a {Toys::Utils::Exec::Controller} will be
280
+ # yielded to it.
256
281
  #
257
282
  # @param [Proc] func The proc to call.
258
283
  # @param [Hash] opts The command options. See the section on
259
284
  # configuration options in the {Toys::Utils::Exec} module docs.
285
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
286
+ # for the subprocess streams.
260
287
  #
261
288
  # @return [String] What was written to standard out.
262
289
  #
263
- def capture_proc(func, opts = {})
264
- exec_proc(func, opts.merge(out: :capture)).captured_out
290
+ def capture_proc(func, opts = {}, &block)
291
+ exec_proc(func, opts.merge(out: :capture, background: false), &block).captured_out
265
292
  end
266
293
 
267
294
  ##
268
295
  # Execute the given string in a shell. Returns the exit code.
296
+ # Cannot be run in the background.
269
297
  #
270
298
  # @param [String] cmd The shell command to execute.
271
299
  # @param [Hash] opts The command options. See the section on
272
300
  # configuration options in the {Toys::Utils::Exec} module docs.
301
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
302
+ # for the subprocess streams.
273
303
  #
274
304
  # @return [Integer] The exit code
275
305
  #
276
- def sh(cmd, opts = {})
277
- exec(cmd, opts).exit_code
306
+ def sh(cmd, opts = {}, &block)
307
+ exec(cmd, opts.merge(background: false), &block).exit_code
278
308
  end
279
309
 
280
310
  ##
@@ -288,6 +318,7 @@ module Toys
288
318
  #
289
319
  CONFIG_KEYS = %i[
290
320
  argv0
321
+ background
291
322
  cli
292
323
  env
293
324
  err
@@ -356,17 +387,24 @@ module Toys
356
387
  end
357
388
 
358
389
  ##
359
- # An object of this type is passed to a subcommand control block.
390
+ # An object that controls a subprocess. This object is returned from an
391
+ # execution running in the background, or is yielded to a control block
392
+ # for an execution running in the foreground.
360
393
  # You may use this object to interact with the subcommand's streams,
361
- # and/or send signals to the process.
394
+ # send signals to the process, and get its result.
362
395
  #
363
396
  class Controller
364
397
  ## @private
365
- def initialize(ins, out, err, pid)
366
- @in = ins
367
- @out = out
368
- @err = err
398
+ def initialize(controller_streams, captures, pid, join_threads, nonzero_status_handler)
399
+ @in = controller_streams[:in]
400
+ @out = controller_streams[:out]
401
+ @err = controller_streams[:err]
402
+ @captures = captures
369
403
  @pid = pid
404
+ @join_threads = join_threads
405
+ @nonzero_status_handler = nonzero_status_handler
406
+ @wait_thread = ::Process.detach(pid)
407
+ @result = nil
370
408
  end
371
409
 
372
410
  ##
@@ -408,6 +446,47 @@ module Toys
408
446
  def kill(signal)
409
447
  ::Process.kill(signal, pid)
410
448
  end
449
+
450
+ ##
451
+ # Determine whether the subcommand is still executing
452
+ #
453
+ # @return [Boolean]
454
+ #
455
+ def executing?
456
+ @wait_thread.status ? true : false
457
+ end
458
+
459
+ ##
460
+ # Wait for the subcommand to complete, and return a result object.
461
+ #
462
+ # @param [Numeric,nil] timeout The timeout in seconds, or `nil` to
463
+ # wait indefinitely.
464
+ # @return [Toys::Utils::Exec::Result,nil] The result object, or `nil`
465
+ # if a timeout occurred.
466
+ #
467
+ def result(timeout: nil)
468
+ return nil unless @wait_thread.join(timeout)
469
+ @result ||= begin
470
+ close_streams
471
+ @join_threads.each(&:join)
472
+ status = @wait_thread.value
473
+ if @nonzero_status_handler && status.exitstatus != 0
474
+ @nonzero_status_handler.call(status)
475
+ end
476
+ Result.new(@captures[:out], @captures[:err], status)
477
+ end
478
+ end
479
+
480
+ ##
481
+ # Close all the controller's streams.
482
+ # @private
483
+ #
484
+ def close_streams
485
+ @in.close if @in && !@in.closed?
486
+ @out.close if @out && !@out.closed?
487
+ @err.close if @err && !@err.closed?
488
+ self
489
+ end
411
490
  end
412
491
 
413
492
  ##
@@ -471,7 +550,7 @@ module Toys
471
550
  # @private
472
551
  #
473
552
  class Executor
474
- def initialize(exec_opts, spawn_cmd)
553
+ def initialize(exec_opts, spawn_cmd, block)
475
554
  @fork_func = spawn_cmd.respond_to?(:call) ? spawn_cmd : nil
476
555
  @spawn_cmd = spawn_cmd.respond_to?(:call) ? nil : spawn_cmd
477
556
  @config_opts = exec_opts.config_opts
@@ -481,18 +560,26 @@ module Toys
481
560
  @join_threads = []
482
561
  @child_streams = []
483
562
  @parent_streams = []
563
+ @block = block
564
+ @default_stream = @config_opts[:background] ? :null : :inherit
484
565
  end
485
566
 
486
- def execute(&block)
567
+ def execute
487
568
  setup_in_stream
488
- setup_out_stream(:out, $stdout, 1)
489
- setup_out_stream(:err, $stderr, 2)
569
+ setup_out_stream(:out)
570
+ setup_out_stream(:err)
490
571
  log_command
491
572
  pid = @fork_func ? start_fork : start_process
492
573
  @child_streams.each(&:close)
493
- wait_thread = ::Process.detach(pid)
494
- status = control_process(wait_thread, &block)
495
- create_result(status)
574
+ controller = Controller.new(@controller_streams, @captures, pid, @join_threads,
575
+ @config_opts[:nonzero_status_handler])
576
+ return controller if @config_opts[:background]
577
+ begin
578
+ @block&.call(controller)
579
+ ensure
580
+ controller.close_streams
581
+ end
582
+ controller.result
496
583
  end
497
584
 
498
585
  private
@@ -613,34 +700,8 @@ module Toys
613
700
  end
614
701
  end
615
702
 
616
- def control_process(wait_thread)
617
- begin
618
- if block_given?
619
- controller = Controller.new(
620
- @controller_streams[:in], @controller_streams[:out], @controller_streams[:err],
621
- wait_thread.pid
622
- )
623
- yield controller
624
- end
625
- ensure
626
- @controller_streams.each_value(&:close)
627
- end
628
- @join_threads.each(&:join)
629
- wait_thread.value
630
- end
631
-
632
- def create_result(status)
633
- nonzero_status_handler = @config_opts[:nonzero_status_handler]
634
- nonzero_status_handler.call(status) if nonzero_status_handler && status.exitstatus != 0
635
- Result.new(@captures[:out], @captures[:err], status)
636
- end
637
-
638
703
  def setup_in_stream
639
- setting = @config_opts[:in]
640
- if setting.nil?
641
- return if $stdin.respond_to?(:fileno) && $stdin.fileno.zero?
642
- setting = $stdin
643
- end
704
+ setting = @config_opts[:in] || @default_stream
644
705
  return unless setting
645
706
  case setting
646
707
  when ::Symbol
@@ -683,6 +744,8 @@ module Toys
683
744
  @controller_streams[:in] = make_in_pipe
684
745
  when :null
685
746
  make_null_stream(:in, "r")
747
+ when :inherit
748
+ @spawn_opts[:in] = :in
686
749
  when :close
687
750
  @spawn_opts[:in] = type
688
751
  when :parent
@@ -705,12 +768,8 @@ module Toys
705
768
  @spawn_opts[:in] = args + [::File::RDONLY]
706
769
  end
707
770
 
708
- def setup_out_stream(key, stdstream, stdfileno)
709
- setting = @config_opts[key]
710
- if setting.nil?
711
- return if setting.respond_to?(:fileno) && setting.fileno == stdfileno
712
- setting = stdstream
713
- end
771
+ def setup_out_stream(key)
772
+ setting = @config_opts[key] || @default_stream
714
773
  case setting
715
774
  when ::Symbol
716
775
  setup_out_stream_of_type(key, setting, [])
@@ -752,6 +811,8 @@ module Toys
752
811
  @controller_streams[key] = make_out_pipe(key)
753
812
  when :null
754
813
  make_null_stream(key, "w")
814
+ when :inherit
815
+ @spawn_opts[key] = key
755
816
  when :close, :out, :err
756
817
  @spawn_opts[key] = type
757
818
  when :parent
@@ -192,6 +192,7 @@ module Toys
192
192
  str = "#{str}\n" unless str.end_with?("\n")
193
193
  write(str, *styles)
194
194
  end
195
+ alias say puts
195
196
 
196
197
  ##
197
198
  # Write a line, appending a newline if one is not already present.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toys-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-09 00:00:00.000000000 Z
11
+ date: 2018-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline