toys-core 0.4.2 → 0.4.3

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 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