toys-core 0.10.0 → 0.10.1

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: 3a9f077375706e67827afa561f71081c121d0eb00c30be6586501e6c76ab47c5
4
- data.tar.gz: 305e31b023d22f687a2406efdd0cea377a1c9725626c8320cebbf013b10f145b
3
+ metadata.gz: b63889a0ce44a42d805bba363f2051c1b1f82c6c50e70138b35cab077441dcdd
4
+ data.tar.gz: 0403e5af7269879d468baae34bbae1664c1f83dfef4ec91c1545079502db5c86
5
5
  SHA512:
6
- metadata.gz: 661b472175296ea3224e3dee08902ca8b2bf04e78f949109a91f4fa471c0b7904a454e0b18e845cf46d8cf04458872c84f55fd3f43bcbb2f3ecd40478783b8a5
7
- data.tar.gz: f9761ab43fffd295af8629906ae3fdee621c42d5df49a92b3539cc68a9588546338a4fdd3a70459639c3127c261de443c5f2359778807d281b451b4c2655316a
6
+ metadata.gz: 401d695bc0375db501df082733813925f229def58bea2b65f947c453b5b0f2989712b27c0a7d8f4d0f19c7e5f90293210a8c8755985a1584efae54bc35e90d2b
7
+ data.tar.gz: 258f2466dab53c45d1541f4608af756d9cddf3a7af555d1c11e329ad7de3cb9ce5e52831347cb417e97bb4628a6563220d2fc486669597c38df0f0184bd6aa89
@@ -1,5 +1,9 @@
1
1
  # Release History
2
2
 
3
+ ### 0.10.1 / 2020-03-07
4
+
5
+ * FIXED: Setting `:exit_on_nonzero_status` explicitly to false now works as expected.
6
+
3
7
  ### 0.10.0 / 2020-02-24
4
8
 
5
9
  Functional changes:
@@ -9,7 +9,7 @@ module Toys
9
9
  # Current version of Toys core.
10
10
  # @return [String]
11
11
  #
12
- VERSION = "0.10.0"
12
+ VERSION = "0.10.1"
13
13
  end
14
14
 
15
15
  ## @private deprecated
@@ -16,54 +16,211 @@ module Toys
16
16
  # This is a frontend for {Toys::Utils::Exec}. More information is
17
17
  # available in that class's documentation.
18
18
  #
19
+ # ## Features
20
+ #
21
+ # ### Controlling processes
22
+ #
23
+ # A process can be started in the *foreground* or the *background*. If you
24
+ # start a foreground process, it will "take over" your standard input and
25
+ # output streams by default, and it will keep control until it completes.
26
+ # If you start a background process, its streams will be redirected to null
27
+ # by default, and control will be returned to you immediately.
28
+ #
29
+ # When a process is running, you can control it using a
30
+ # {Toys::Utils::Exec::Controller} object. Use a controller to interact with
31
+ # the process's input and output streams, send it signals, or wait for it
32
+ # to complete.
33
+ #
34
+ # When running a process in the foreground, the controller will be yielded
35
+ # to an optional block. For example, the following code starts a process in
36
+ # the foreground and passes its output stream to a controller.
37
+ #
38
+ # exec(["git", "init"], out: :controller) do |controller|
39
+ # loop do
40
+ # line = controller.out.gets
41
+ # break if line.nil?
42
+ # puts "Got line: #{line}"
43
+ # end
44
+ # end
45
+ #
46
+ # When running a process in the background, the controller is returned from
47
+ # the method that starts the process:
48
+ #
49
+ # controller = exec_service.exec(["git", "init"], background: true)
50
+ #
51
+ # ### Stream handling
52
+ #
53
+ # By default, subprocess streams are connected to the corresponding streams
54
+ # in the parent process. You can change this behavior, redirecting streams
55
+ # or providing ways to control them, using the `:in`, `:out`, and `:err`
56
+ # options.
57
+ #
58
+ # Three general strategies are available for custom stream handling. First,
59
+ # you may redirect to other streams such as files, IO objects, or Ruby
60
+ # strings. Some of these options map directly to options provided by the
61
+ # `Process#spawn` method. Second, you may use a controller to manipulate
62
+ # the streams programmatically. Third, you may capture output stream data
63
+ # and make it available in the result.
64
+ #
65
+ # Following is a full list of the stream handling options, along with how
66
+ # to specify them using the `:in`, `:out`, and `:err` options.
67
+ #
68
+ # * **Inherit parent stream:** You may inherit the corresponding stream
69
+ # in the parent process by passing `:inherit` as the option value. This
70
+ # is the default if the subprocess is *not* run in the background.
71
+ # * **Redirect to null:** You may redirect to a null stream by passing
72
+ # `:null` as the option value. This connects to a stream that is not
73
+ # closed but contains no data, i.e. `/dev/null` on unix systems. This
74
+ # is the default if the subprocess is run in the background.
75
+ # * **Close the stream:** You may close the stream by passing `:close` as
76
+ # the option value. This is the same as passing `:close` to
77
+ # `Process#spawn`.
78
+ # * **Redirect to a file:** You may redirect to a file. This reads from
79
+ # an existing file when connected to `:in`, and creates or appends to a
80
+ # file when connected to `:out` or `:err`. To specify a file, use the
81
+ # setting `[:file, "/path/to/file"]`. You may also, when writing a
82
+ # file, append an optional mode and permission code to the array. For
83
+ # example, `[:file, "/path/to/file", "a", 0644]`.
84
+ # * **Redirect to an IO object:** You may redirect to an IO object in the
85
+ # parent process, by passing the IO object as the option value. You may
86
+ # use any IO object. For example, you could connect the child's output
87
+ # to the parent's error using `out: $stderr`, or you could connect to
88
+ # an existing File stream. Unlike `Process#spawn`, this works for IO
89
+ # objects that do not have a corresponding file descriptor (such as
90
+ # StringIO objects). In such a case, a thread will be spawned to pipe
91
+ # the IO data through to the child process.
92
+ # * **Combine with another child stream:** You may redirect one child
93
+ # output stream to another, to combine them. To merge the child's error
94
+ # stream into its output stream, use `err: [:child, :out]`.
95
+ # * **Read from a string:** You may pass a string to the input stream by
96
+ # setting `[:string, "the string"]`. This works only for `:in`.
97
+ # * **Capture output stream:** You may capture a stream and make it
98
+ # available on the {Toys::Utils::Exec::Result} object, using the
99
+ # setting `:capture`. This works only for the `:out` and `:err`
100
+ # streams.
101
+ # * **Use the controller:** You may hook a stream to the controller using
102
+ # the setting `:controller`. You can then manipulate the stream via the
103
+ # controller. If you pass a block to {Toys::StandardMixins::Exec#exec},
104
+ # it yields the {Toys::Utils::Exec::Controller}, giving you access to
105
+ # streams.
106
+ #
107
+ # ### Result handling
108
+ #
109
+ # A subprocess result is represented by a {Toys::Utils::Exec::Result}
110
+ # object, which includes the exit code, the content of any captured output
111
+ # streams, and any exeption raised when attempting to run the process.
112
+ # When you run a process in the foreground, the method will return a result
113
+ # object. When you run a process in the background, you can obtain the
114
+ # result from the controller once the process completes.
115
+ #
116
+ # The following example demonstrates running a process in the foreground
117
+ # and getting the exit code:
118
+ #
119
+ # result = exec(["git", "init"])
120
+ # puts "exit code: #{result.exit_code}"
121
+ #
122
+ # The following example demonstrates starting a process in the background,
123
+ # waiting for it to complete, and getting its exit code:
124
+ #
125
+ # controller = exec(["git", "init"], background: true)
126
+ # result = controller.result(timeout: 1.0)
127
+ # if result
128
+ # puts "exit code: #{result.exit_code}"
129
+ # else
130
+ # puts "timed out"
131
+ # end
132
+ #
133
+ # You can also provide a callback that is executed once a process
134
+ # completes. This callback can be specified as a method name or a `Proc`
135
+ # object, and will be passed the result object. For example:
136
+ #
137
+ # def run
138
+ # exec(["git", "init"], result_callback: :handle_result)
139
+ # end
140
+ # def handle_result(result)
141
+ # puts "exit code: #{result.exit_code}"
142
+ # end
143
+ #
144
+ # Finally, you can force your tool to exit if a subprocess fails, similar
145
+ # to setting the `set -e` option in bash, by setting the
146
+ # `:exit_on_nonzero_status` option. This is often set as a default
147
+ # configuration for all subprocesses run in a tool, by passing it as an
148
+ # argument to the `include` directive:
149
+ #
150
+ # include :exec, exit_on_nonzero_status: true
151
+ #
19
152
  # ## Configuration Options
20
153
  #
21
- # Subprocesses may be configured using the options in the
22
- # {Toys::Utils::Exec} class. These include a variety of options supported
23
- # by `Process#spawn`, and some options supported by {Toys::Utils::Exec}
24
- # itself.
154
+ # A variety of options can be used to control subprocesses. These can be
155
+ # provided to any method that starts a subprocess. You can also set
156
+ # defaults by passing them as keyword arguments when you `include` the
157
+ # mixin.
158
+ #
159
+ # Options that affect the behavior of subprocesses:
160
+ #
161
+ # * `:env` (Hash) Environment variables to pass to the subprocess.
162
+ # Keys represent variable names and should be strings. Values should be
163
+ # either strings or `nil`, which unsets the variable.
164
+ #
165
+ # * `:background` (Boolean) Runs the process in the background if `true`.
166
+ #
167
+ # Options related to handling results
168
+ #
169
+ # * `:result_callback` (Proc,Symbol) A procedure that is called, and
170
+ # passed the result object, when the subprocess exits. You can provide
171
+ # a `Proc` object, or the name of a method as a `Symbol`.
172
+ #
173
+ # * `:exit_on_nonzero_status` (Boolean) If set to true, a nonzero exit
174
+ # code will cause the tool to exit immediately with that same code.
175
+ #
176
+ # * `:e` (Boolean) A short name for `:exit_on_nonzero_status`.
177
+ #
178
+ # Options for connecting input and output streams. See the section above on
179
+ # stream handling for info on the values that can be passed.
180
+ #
181
+ # * `:in` Connects the input stream of the subprocess. See the section on
182
+ # stream handling.
183
+ #
184
+ # * `:out` Connects the standard output stream of the subprocess. See the
185
+ # section on stream handling.
25
186
  #
26
- # You can set default configuration by passing options to the `include`
27
- # directive. For example, to log commands at the debug level for all
28
- # subprocesses spawned by this tool:
187
+ # * `:err` Connects the standard error stream of the subprocess. See the
188
+ # section on stream handling.
29
189
  #
30
- # include :exec, log_level: Logger::DEBUG
190
+ # Options related to logging and reporting:
31
191
  #
32
- # Two special options are also recognized by the mixin.
192
+ # * `:logger` (Logger) Logger to use for logging the actual command. If
193
+ # not present, the command is not logged.
33
194
  #
34
- # * A **:result_callback** proc may take a second argument. If it does,
35
- # the context object is passed as the second argument. This is useful
36
- # if a `:result_callback` is applied to the entire tool by passing it
37
- # to the `include` directive. In that case, `self` is not set to the
38
- # context object as it normally would be in a tool's `run` method, so
39
- # you cannot access it otherwise. For example, here is how to log the
40
- # exit code for every subcommand:
195
+ # * `:log_level` (Integer,false) Level for logging the actual command.
196
+ # Defaults to Logger::INFO if not present. You may also pass `false` to
197
+ # disable logging of the command.
41
198
  #
42
- # tool "mytool" do
43
- # callback = proc do |result, context|
44
- # context.logger.info "Exit code: #{result.exit_code}"
45
- # end
46
- # include :exec, result_callback: callback
47
- # # ...
48
- # end
199
+ # * `:log_cmd` (String) The string logged for the actual command.
200
+ # Defaults to the `inspect` representation of the command.
49
201
  #
50
- # You may also pass a symbol as the `:result_callback`. The method with
51
- # that name is then called as the callback. The method must take one
52
- # argument, the result object.
202
+ # * `:name` (Object) An optional object that can be used to identify this
203
+ # subprocess. It is available in the controller and result objects.
53
204
  #
54
- # * If **:exit_on_nonzero_status** is set to true, a nonzero exit code
55
- # returned by the subprocess will also cause the tool to exit
56
- # immediately with that same code.
205
+ # In addition, the following options recognized by
206
+ # [`Process#spawn`](https://ruby-doc.org/core/Process.html#method-c-spawn)
207
+ # are supported.
57
208
  #
58
- # This is particularly useful as an option to the `include` directive,
59
- # where it causes any subprocess failure to abort the tool, similar to
60
- # setting `set -e` in a bash script.
209
+ # * `:chdir` (String) Set the working directory for the command.
61
210
  #
62
- # include :exec, exit_on_nonzero_status: true
211
+ # * `:close_others` (Boolean) Whether to close non-redirected
212
+ # non-standard file descriptors.
63
213
  #
64
- # **:e** can be used as a shortcut for **:exit_on_nonzero_status**
214
+ # * `:new_pgroup` (Boolean) Create new process group (Windows only).
65
215
  #
66
- # include :exec, e: true
216
+ # * `:pgroup` (Integer,true,nil) The process group setting.
217
+ #
218
+ # * `:umask` (Integer) Umask setting for the new process.
219
+ #
220
+ # * `:unsetenv_others` (Boolean) Clear environment variables except those
221
+ # explicitly set.
222
+ #
223
+ # Any other option key will result in an `ArgumentError`.
67
224
  #
68
225
  module Exec
69
226
  include Mixin
@@ -89,10 +246,10 @@ module Toys
89
246
  end
90
247
 
91
248
  ##
92
- # Set default configuration keys.
249
+ # Set default configuration options.
93
250
  #
94
- # All options listed in the {Toys::Utils::Exec} documentation are
95
- # supported, plus the `exit_on_nonzero_status` option.
251
+ # See the {Toys::StandardMixins::Exec} module documentation for a
252
+ # description of the options.
96
253
  #
97
254
  # @param opts [keywords] The default options.
98
255
  # @return [self]
@@ -110,12 +267,25 @@ module Toys
110
267
  # If the process is not set to run in the background, and a block is
111
268
  # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
112
269
  #
270
+ # ## Examples
271
+ #
272
+ # Run a command without a shell, and print the exit code (0 for success):
273
+ #
274
+ # result = exec(["git", "init"])
275
+ # puts "exit code: #{result.exit_code}"
276
+ #
277
+ # Run a shell command:
278
+ #
279
+ # result = exec("cd mydir && git init")
280
+ # puts "exit code: #{result.exit_code}"
281
+ #
113
282
  # @param cmd [String,Array<String>] The command to execute.
114
- # @param opts [keywords] The command options. All options listed in the
115
- # {Toys::Utils::Exec} documentation are supported, plus the
116
- # `exit_on_nonzero_status` option.
283
+ # @param opts [keywords] The command options. See the section on
284
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
285
+ # documentation.
117
286
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
118
- # the subprocess streams.
287
+ # the subprocess. See the section on Controlling Processes in the
288
+ # {Toys::StandardMixins::Exec} module documentation.
119
289
  #
120
290
  # @return [Toys::Utils::Exec::Controller] The subprocess controller, if
121
291
  # the process is running in the background.
@@ -133,12 +303,19 @@ module Toys
133
303
  # If the process is not set to run in the background, and a block is
134
304
  # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
135
305
  #
306
+ # ## Example
307
+ #
308
+ # Execute a small script with warnings
309
+ #
310
+ # exec_ruby("-w", "-e", "(1..10).each { |i| puts i }")
311
+ #
136
312
  # @param args [String,Array<String>] The arguments to ruby.
137
- # @param opts [keywords] The command options. All options listed in the
138
- # {Toys::Utils::Exec} documentation are supported, plus the
139
- # `exit_on_nonzero_status` option.
313
+ # @param opts [keywords] The command options. See the section on
314
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
315
+ # documentation.
140
316
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
141
- # for the subprocess streams.
317
+ # the subprocess. See the section on Controlling Processes in the
318
+ # {Toys::StandardMixins::Exec} module documentation.
142
319
  #
143
320
  # @return [Toys::Utils::Exec::Controller] The subprocess controller, if
144
321
  # the process is running in the background.
@@ -160,12 +337,23 @@ module Toys
160
337
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
161
338
  # do not support this method because they do not support fork.
162
339
  #
340
+ # ## Example
341
+ #
342
+ # Run a proc in a forked process.
343
+ #
344
+ # code = proc do
345
+ # puts "Spawned process ID is #{Process.pid}"
346
+ # end
347
+ # puts "Main process ID is #{Process.pid}"
348
+ # exec_proc(code)
349
+ #
163
350
  # @param func [Proc] The proc to call.
164
- # @param opts [keywords] The command options. Most options listed in the
165
- # {Toys::Utils::Exec} documentation are supported, plus the
166
- # `exit_on_nonzero_status` option.
167
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
168
- # for the subprocess streams.
351
+ # @param opts [keywords] The command options. See the section on
352
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
353
+ # documentation.
354
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
355
+ # the subprocess. See the section on Controlling Processes in the
356
+ # {Toys::StandardMixins::Exec} module documentation.
169
357
  #
170
358
  # @return [Toys::Utils::Exec::Controller] The subprocess controller, if
171
359
  # the process is running in the background.
@@ -189,12 +377,19 @@ module Toys
189
377
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
190
378
  # do not support this method because they do not support fork.
191
379
  #
380
+ # ## Example
381
+ #
382
+ # Run the "system update" tool and pass it an argument.
383
+ #
384
+ # exec_tool(["system", "update", "--verbose"])
385
+ #
192
386
  # @param cmd [String,Array<String>] The tool to execute.
193
- # @param opts [keywords] The command options. Most options listed in the
194
- # {Toys::Utils::Exec} documentation are supported, plus the
195
- # `exit_on_nonzero_status` option.
196
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
197
- # for the subprocess streams.
387
+ # @param opts [keywords] The command options. See the section on
388
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
389
+ # documentation.
390
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
391
+ # the subprocess. See the section on Controlling Processes in the
392
+ # {Toys::StandardMixins::Exec} module documentation.
198
393
  #
199
394
  # @return [Toys::Utils::Exec::Controller] The subprocess controller, if
200
395
  # the process is running in the background.
@@ -229,12 +424,19 @@ module Toys
229
424
  # run a tool that uses a different bundle. It may also be necessary on
230
425
  # environments without "fork" (such as JRuby or Ruby on Windows).
231
426
  #
427
+ # ## Example
428
+ #
429
+ # Run the "system update" tool and pass it an argument.
430
+ #
431
+ # exec_separate_tool(["system", "update", "--verbose"])
432
+ #
232
433
  # @param cmd [String,Array<String>] The tool to execute.
233
- # @param opts [keywords] The command options. Most options listed in the
234
- # {Toys::Utils::Exec} documentation are supported, plus the
235
- # `exit_on_nonzero_status` option.
236
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
237
- # for the subprocess streams.
434
+ # @param opts [keywords] The command options. See the section on
435
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
436
+ # documentation.
437
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
438
+ # the subprocess. See the section on Controlling Processes in the
439
+ # {Toys::StandardMixins::Exec} module documentation.
238
440
  #
239
441
  # @return [Toys::Utils::Exec::Controller] The subprocess controller, if
240
442
  # the process is running in the background.
@@ -257,12 +459,20 @@ module Toys
257
459
  # If a block is provided, a {Toys::Utils::Exec::Controller} will be
258
460
  # yielded to it.
259
461
  #
462
+ # ## Example
463
+ #
464
+ # Capture the output of an echo command
465
+ #
466
+ # str = capture(["echo", "hello"])
467
+ # assert_equal("hello\n", str)
468
+ #
260
469
  # @param cmd [String,Array<String>] The command to execute.
261
- # @param opts [keywords] The command options. All options listed in the
262
- # {Toys::Utils::Exec} documentation are supported, plus the
263
- # `exit_on_nonzero_status` option.
264
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
265
- # for the subprocess streams.
470
+ # @param opts [keywords] The command options. See the section on
471
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
472
+ # documentation.
473
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
474
+ # the subprocess. See the section on Controlling Processes in the
475
+ # {Toys::StandardMixins::Exec} module documentation.
266
476
  #
267
477
  # @return [String] What was written to standard out.
268
478
  #
@@ -280,12 +490,20 @@ module Toys
280
490
  # If a block is provided, a {Toys::Utils::Exec::Controller} will be
281
491
  # yielded to it.
282
492
  #
493
+ # ## Example
494
+ #
495
+ # Capture the output of a ruby script.
496
+ #
497
+ # str = capture_ruby("-e", "(1..3).each { |i| puts i }")
498
+ # assert_equal "1\n2\n3\n", str
499
+ #
283
500
  # @param args [String,Array<String>] The arguments to ruby.
284
- # @param opts [keywords] The command options. All options listed in the
285
- # {Toys::Utils::Exec} documentation are supported, plus the
286
- # `exit_on_nonzero_status` option.
287
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
288
- # for the subprocess streams.
501
+ # @param opts [keywords] The command options. See the section on
502
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
503
+ # documentation.
504
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
505
+ # the subprocess. See the section on Controlling Processes in the
506
+ # {Toys::StandardMixins::Exec} module documentation.
289
507
  #
290
508
  # @return [String] What was written to standard out.
291
509
  #
@@ -306,12 +524,23 @@ module Toys
306
524
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
307
525
  # do not support this method because they do not support fork.
308
526
  #
527
+ # ## Example
528
+ #
529
+ # Run a proc in a forked process and capture its output:
530
+ #
531
+ # code = proc do
532
+ # puts Process.pid
533
+ # end
534
+ # forked_pid = capture_proc(code).chomp
535
+ # puts "I forked PID #{forked_pid}"
536
+ #
309
537
  # @param func [Proc] The proc to call.
310
- # @param opts [keywords] The command options. Most options listed in the
311
- # {Toys::Utils::Exec} documentation are supported, plus the
312
- # `exit_on_nonzero_status` option.
313
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
314
- # for the subprocess streams.
538
+ # @param opts [keywords] The command options. See the section on
539
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
540
+ # documentation.
541
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
542
+ # the subprocess. See the section on Controlling Processes in the
543
+ # {Toys::StandardMixins::Exec} module documentation.
315
544
  #
316
545
  # @return [String] What was written to standard out.
317
546
  #
@@ -335,12 +564,20 @@ module Toys
335
564
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
336
565
  # do not support this method because they do not support fork.
337
566
  #
567
+ # ## Example
568
+ #
569
+ # Run the "system version" tool and capture its output.
570
+ #
571
+ # str = capture_tool(["system", "version"]).chomp
572
+ # puts "Version was #{str}"
573
+ #
338
574
  # @param cmd [String,Array<String>] The tool to execute.
339
- # @param opts [keywords] The command options. Most options listed in the
340
- # {Toys::Utils::Exec} documentation are supported, plus the
341
- # `exit_on_nonzero_status` option.
342
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
343
- # for the subprocess streams.
575
+ # @param opts [keywords] The command options. See the section on
576
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
577
+ # documentation.
578
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
579
+ # the subprocess. See the section on Controlling Processes in the
580
+ # {Toys::StandardMixins::Exec} module documentation.
344
581
  #
345
582
  # @return [String] What was written to standard out.
346
583
  #
@@ -375,12 +612,20 @@ module Toys
375
612
  # run a tool that uses a different bundle. It may also be necessary on
376
613
  # environments without "fork" (such as JRuby or Ruby on Windows).
377
614
  #
615
+ # ## Example
616
+ #
617
+ # Run the "system version" tool and capture its output.
618
+ #
619
+ # str = capture_separate_tool(["system", "version"]).chomp
620
+ # puts "Version was #{str}"
621
+ #
378
622
  # @param cmd [String,Array<String>] The tool to execute.
379
- # @param opts [keywords] The command options. Most options listed in the
380
- # {Toys::Utils::Exec} documentation are supported, plus the
381
- # `exit_on_nonzero_status` option.
382
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
383
- # for the subprocess streams.
623
+ # @param opts [keywords] The command options. See the section on
624
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
625
+ # documentation.
626
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
627
+ # the subprocess. See the section on Controlling Processes in the
628
+ # {Toys::StandardMixins::Exec} module documentation.
384
629
  #
385
630
  # @return [String] What was written to standard out.
386
631
  #
@@ -397,12 +642,20 @@ module Toys
397
642
  # If a block is provided, a {Toys::Utils::Exec::Controller} will be
398
643
  # yielded to it.
399
644
  #
645
+ # ## Example
646
+ #
647
+ # Run a shell script
648
+ #
649
+ # exit_code = sh("cd mydir && git init")
650
+ # puts exit_code == 0 ? "Success!" : "Failed!"
651
+ #
400
652
  # @param cmd [String] The shell command to execute.
401
- # @param opts [keywords] The command options. All options listed in the
402
- # {Toys::Utils::Exec} documentation are supported, plus the
403
- # `exit_on_nonzero_status` option.
404
- # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
405
- # for the subprocess streams.
653
+ # @param opts [keywords] The command options. See the section on
654
+ # Configuration Options in the {Toys::StandardMixins::Exec} module
655
+ # documentation.
656
+ # @yieldparam controller [Toys::Utils::Exec::Controller] A controller for
657
+ # the subprocess. See the section on Controlling Processes in the
658
+ # {Toys::StandardMixins::Exec} module documentation.
406
659
  #
407
660
  # @return [Integer] The exit code
408
661
  #
@@ -432,35 +685,43 @@ module Toys
432
685
 
433
686
  ## @private
434
687
  def self._setup_exec_opts(opts, context)
688
+ count = 0
689
+ result_callback = nil
435
690
  if opts.key?(:result_callback)
436
- opts = _setup_result_callback_option(opts, context)
691
+ result_callback = _interpret_result_callback(opts[:result_callback], context)
692
+ count += 1
693
+ end
694
+ [:exit_on_nonzero_status, :e].each do |sym|
695
+ if opts.key?(sym)
696
+ result_callback = _interpret_e(opts[sym], context)
697
+ count += 1
698
+ opts = opts.reject { |k, _v| k == sym }
699
+ end
437
700
  end
438
- if opts.key?(:exit_on_nonzero_status) || opts.key?(:e)
439
- opts = _setup_e_option(opts, context)
701
+ if count > 1
702
+ raise ::ArgumentError,
703
+ "You can provide at most one of: result_callback, exit_on_nonzero_status, e"
440
704
  end
705
+ opts = opts.merge(result_callback: result_callback) if count == 1
441
706
  opts
442
707
  end
443
708
 
444
709
  ## @private
445
- def self._setup_e_option(opts, context)
446
- e_options = [:exit_on_nonzero_status, :e]
447
- if e_options.any? { |k| opts[k] }
448
- result_callback = proc { |r| context.exit(r.exit_code) if r.error? }
449
- opts = opts.merge(result_callback: result_callback)
450
- end
451
- opts.reject { |k, _v| e_options.include?(k) }
710
+ def self._interpret_e(value, context)
711
+ value ? proc { |r| context.exit(r.exit_code) if r.error? } : nil
452
712
  end
453
713
 
454
714
  ## @private
455
- def self._setup_result_callback_option(opts, context)
456
- orig_callback = opts[:result_callback]
457
- result_callback =
458
- if orig_callback.is_a?(::Symbol)
459
- context.method(orig_callback)
460
- elsif orig_callback.respond_to?(:call)
461
- proc { |r| orig_callback.call(r, context) }
462
- end
463
- opts.merge(result_callback: result_callback)
715
+ def self._interpret_result_callback(value, context)
716
+ if value.is_a?(::Symbol)
717
+ context.method(value)
718
+ elsif value.respond_to?(:call)
719
+ proc { |r| context.instance_eval { value.call(r, context) } }
720
+ elsif value.nil?
721
+ nil
722
+ else
723
+ raise ::ArgumentError, "Bad value for result_callback"
724
+ end
464
725
  end
465
726
 
466
727
  ## @private
@@ -16,48 +16,39 @@ module Toys
16
16
  # This class is not loaded by default. Before using it directly, you should
17
17
  # `require "toys/utils/exec"`
18
18
  #
19
- # ## Configuration options
19
+ # ## Features
20
20
  #
21
- # A variety of options can be used to control subprocesses. These include:
21
+ # ### Controlling processes
22
22
  #
23
- # * `:name` (Object) An optional object that can be used to identify this
24
- # subprocess. It is available in the controller and result objects.
25
- # * `:env` (Hash) Environment variables to pass to the subprocess
26
- # * `:logger` (Logger) Logger to use for logging the actual command. If
27
- # not present, the command is not logged.
28
- # * `:log_level` (Integer,false) Level for logging the actual command.
29
- # Defaults to Logger::INFO if not present. You may also pass `false` to
30
- # disable logging of the command.
31
- # * `:log_cmd` (String) The string logged for the actual command.
32
- # Defaults to the `inspect` representation of the command.
33
- # * `:background` (Boolean) Runs the process in the background, returning
34
- # a controller object instead of a result object.
35
- # * `:result_callback` (Proc) Called and passed the result object when a
36
- # subprocess exits.
37
- # * `:in` Connects the input stream of the subprocess. See the section on
38
- # stream handling.
39
- # * `:out` Connects the standard output stream of the subprocess. See the
40
- # section on stream handling.
41
- # * `:err` Connects the standard error stream of the subprocess. See the
42
- # section on stream handling.
23
+ # A process can be started in the *foreground* or the *background*. If you
24
+ # start a foreground process, it will "take over" your standard input and
25
+ # output streams by default, and it will keep control until it completes.
26
+ # If you start a background process, its streams will be redirected to null
27
+ # by default, and control will be returned to you immediately.
28
+ #
29
+ # When a process is running, you can control it using a
30
+ # {Toys::Utils::Exec::Controller} object. Use a controller to interact with
31
+ # the process's input and output streams, send it signals, or wait for it
32
+ # to complete.
43
33
  #
44
- # In addition, the following options recognized by `Process#spawn` are
45
- # supported.
34
+ # When running a process in the foreground, the controller will be yielded
35
+ # to an optional block. For example, the following code starts a process in
36
+ # the foreground and passes its output stream to a controller.
46
37
  #
47
- # * `:chdir`
48
- # * `:close_others`
49
- # * `:new_pgroup`
50
- # * `:pgroup`
51
- # * `:umask`
52
- # * `:unsetenv_others`
38
+ # exec_service.exec(["git", "init"], out: :controller) do |controller|
39
+ # loop do
40
+ # line = controller.out.gets
41
+ # break if line.nil?
42
+ # puts "Got line: #{line}"
43
+ # end
44
+ # end
53
45
  #
54
- # Any other options are ignored.
46
+ # When running a process in the background, the controller is returned from
47
+ # the method that starts the process:
55
48
  #
56
- # Configuration options may be provided to any method that starts a
57
- # subprocess. You may also modify default values by calling
58
- # {Toys::Utils::Exec#configure_defaults}.
49
+ # controller = exec_service.exec(["git", "init"], background: true)
59
50
  #
60
- # ## Stream handling
51
+ # ### Stream handling
61
52
  #
62
53
  # By default, subprocess streams are connected to the corresponding streams
63
54
  # in the parent process. You can change this behavior, redirecting streams
@@ -74,16 +65,16 @@ module Toys
74
65
  # Following is a full list of the stream handling options, along with how
75
66
  # to specify them using the `:in`, `:out`, and `:err` options.
76
67
  #
77
- # * **Close the stream:** You may close the stream by passing `:close` as
78
- # the option value. This is the same as passing `:close` to
79
- # `Process#spawn`.
68
+ # * **Inherit parent stream:** You may inherit the corresponding stream
69
+ # in the parent process by passing `:inherit` as the option value. This
70
+ # is the default if the subprocess is *not* run in the background.
80
71
  # * **Redirect to null:** You may redirect to a null stream by passing
81
72
  # `:null` as the option value. This connects to a stream that is not
82
73
  # closed but contains no data, i.e. `/dev/null` on unix systems. This
83
74
  # is the default if the subprocess is run in the background.
84
- # * **Inherit parent stream:** You may inherit the corresponding stream
85
- # in the parent process by passing `:inherit` as the option value. This
86
- # is the default if the subprocess is *not* run in the background.
75
+ # * **Close the stream:** You may close the stream by passing `:close` as
76
+ # the option value. This is the same as passing `:close` to
77
+ # `Process#spawn`.
87
78
  # * **Redirect to a file:** You may redirect to a file. This reads from
88
79
  # an existing file when connected to `:in`, and creates or appends to a
89
80
  # file when connected to `:out` or `:err`. To specify a file, use the
@@ -113,6 +104,104 @@ module Toys
113
104
  # yields the {Toys::Utils::Exec::Controller}, giving you access to
114
105
  # streams.
115
106
  #
107
+ # ### Result handling
108
+ #
109
+ # A subprocess result is represented by a {Toys::Utils::Exec::Result}
110
+ # object, which includes the exit code, the content of any captured output
111
+ # streams, and any exeption raised when attempting to run the process.
112
+ # When you run a process in the foreground, the method will return a result
113
+ # object. When you run a process in the background, you can obtain the
114
+ # result from the controller once the process completes.
115
+ #
116
+ # The following example demonstrates running a process in the foreground
117
+ # and getting the exit code:
118
+ #
119
+ # result = exec_service.exec(["git", "init"])
120
+ # puts "exit code: #{result.exit_code}"
121
+ #
122
+ # The following example demonstrates starting a process in the background,
123
+ # waiting for it to complete, and getting its exit code:
124
+ #
125
+ # controller = exec_service.exec(["git", "init"], background: true)
126
+ # result = controller.result(timeout: 1.0)
127
+ # if result
128
+ # puts "exit code: #{result.exit_code}"
129
+ # else
130
+ # puts "timed out"
131
+ # end
132
+ #
133
+ # You can also provide a callback that is executed once a process
134
+ # completes. For example:
135
+ #
136
+ # my_callback = proc do |result|
137
+ # puts "exit code: #{result.exit_code}"
138
+ # end
139
+ # exec_service.exec(["git", "init"], result_callback: my_callback)
140
+ #
141
+ # ## Configuration options
142
+ #
143
+ # A variety of options can be used to control subprocesses. These can be
144
+ # provided to any method that starts a subprocess. Youc an also set
145
+ # defaults by calling {Toys::Utils::Exec#configure_defaults}.
146
+ #
147
+ # Options that affect the behavior of subprocesses:
148
+ #
149
+ # * `:env` (Hash) Environment variables to pass to the subprocess.
150
+ # Keys represent variable names and should be strings. Values should be
151
+ # either strings or `nil`, which unsets the variable.
152
+ #
153
+ # * `:background` (Boolean) Runs the process in the background if `true`.
154
+ #
155
+ # * `:result_callback` (Proc) Called and passed the result object when
156
+ # the subprocess exits.
157
+ #
158
+ # Options for connecting input and output streams. See the section above on
159
+ # stream handling for info on the values that can be passed.
160
+ #
161
+ # * `:in` Connects the input stream of the subprocess. See the section on
162
+ # stream handling.
163
+ #
164
+ # * `:out` Connects the standard output stream of the subprocess. See the
165
+ # section on stream handling.
166
+ #
167
+ # * `:err` Connects the standard error stream of the subprocess. See the
168
+ # section on stream handling.
169
+ #
170
+ # Options related to logging and reporting:
171
+ #
172
+ # * `:logger` (Logger) Logger to use for logging the actual command. If
173
+ # not present, the command is not logged.
174
+ #
175
+ # * `:log_level` (Integer,false) Level for logging the actual command.
176
+ # Defaults to Logger::INFO if not present. You may also pass `false` to
177
+ # disable logging of the command.
178
+ #
179
+ # * `:log_cmd` (String) The string logged for the actual command.
180
+ # Defaults to the `inspect` representation of the command.
181
+ #
182
+ # * `:name` (Object) An optional object that can be used to identify this
183
+ # subprocess. It is available in the controller and result objects.
184
+ #
185
+ # In addition, the following options recognized by
186
+ # [`Process#spawn`](https://ruby-doc.org/core/Process.html#method-c-spawn)
187
+ # are supported.
188
+ #
189
+ # * `:chdir` (String) Set the working directory for the command.
190
+ #
191
+ # * `:close_others` (Boolean) Whether to close non-redirected
192
+ # non-standard file descriptors.
193
+ #
194
+ # * `:new_pgroup` (Boolean) Create new process group (Windows only).
195
+ #
196
+ # * `:pgroup` (Integer,true,nil) The process group setting.
197
+ #
198
+ # * `:umask` (Integer) Umask setting for the new process.
199
+ #
200
+ # * `:unsetenv_others` (Boolean) Clear environment variables except those
201
+ # explicitly set.
202
+ #
203
+ # Any other option key will result in an `ArgumentError`.
204
+ #
116
205
  class Exec
117
206
  ##
118
207
  # Create an exec service.
@@ -120,14 +209,16 @@ module Toys
120
209
  # @param block [Proc] A block that is called if a key is not found. It is
121
210
  # passed the unknown key, and expected to return a default value
122
211
  # (which can be nil).
123
- # @param opts [keywords] Initial default options.
212
+ # @param opts [keywords] Initial default options. See {Toys::Utils::Exec}
213
+ # for a description of the options.
124
214
  #
125
215
  def initialize(**opts, &block)
126
216
  @default_opts = Opts.new(&block).add(opts)
127
217
  end
128
218
 
129
219
  ##
130
- # Set default options
220
+ # Set default options. See {Toys::Utils::Exec} for a description of the
221
+ # options.
131
222
  #
132
223
  # @param opts [keywords] New default options to set
133
224
  # @return [self]
@@ -146,7 +237,7 @@ module Toys
146
237
  #
147
238
  # @param cmd [String,Array<String>] The command to execute.
148
239
  # @param opts [keywords] The command options. See the section on
149
- # configuration options in the {Toys::Utils::Exec} module docs.
240
+ # configuration options in the {Toys::Utils::Exec} class docs.
150
241
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
151
242
  # for the subprocess streams.
152
243
  #
@@ -179,7 +270,7 @@ module Toys
179
270
  #
180
271
  # @param args [String,Array<String>] The arguments to ruby.
181
272
  # @param opts [keywords] The command options. See the section on
182
- # configuration options in the {Toys::Utils::Exec} module docs.
273
+ # configuration options in the {Toys::Utils::Exec} class docs.
183
274
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
184
275
  # for the subprocess streams.
185
276
  #
@@ -204,7 +295,7 @@ module Toys
204
295
  #
205
296
  # @param func [Proc] The proc to call.
206
297
  # @param opts [keywords] The command options. See the section on
207
- # configuration options in the {Toys::Utils::Exec} module docs.
298
+ # configuration options in the {Toys::Utils::Exec} class docs.
208
299
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
209
300
  # for the subprocess streams.
210
301
  #
@@ -231,7 +322,7 @@ module Toys
231
322
  #
232
323
  # @param cmd [String,Array<String>] The command to execute.
233
324
  # @param opts [keywords] The command options. See the section on
234
- # configuration options in the {Toys::Utils::Exec} module docs.
325
+ # configuration options in the {Toys::Utils::Exec} class docs.
235
326
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
236
327
  # for the subprocess streams.
237
328
  #
@@ -253,7 +344,7 @@ module Toys
253
344
  #
254
345
  # @param args [String,Array<String>] The arguments to ruby.
255
346
  # @param opts [keywords] The command options. See the section on
256
- # configuration options in the {Toys::Utils::Exec} module docs.
347
+ # configuration options in the {Toys::Utils::Exec} class docs.
257
348
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
258
349
  # for the subprocess streams.
259
350
  #
@@ -275,7 +366,7 @@ module Toys
275
366
  #
276
367
  # @param func [Proc] The proc to call.
277
368
  # @param opts [keywords] The command options. See the section on
278
- # configuration options in the {Toys::Utils::Exec} module docs.
369
+ # configuration options in the {Toys::Utils::Exec} class docs.
279
370
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
280
371
  # for the subprocess streams.
281
372
  #
@@ -295,7 +386,7 @@ module Toys
295
386
  #
296
387
  # @param cmd [String] The shell command to execute.
297
388
  # @param opts [keywords] The command options. See the section on
298
- # configuration options in the {Toys::Utils::Exec} module docs.
389
+ # configuration options in the {Toys::Utils::Exec} class docs.
299
390
  # @yieldparam controller [Toys::Utils::Exec::Controller] A controller
300
391
  # for the subprocess streams.
301
392
  #
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.10.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-24 00:00:00.000000000 Z
11
+ date: 2020-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: did_you_mean
@@ -198,7 +198,7 @@ metadata:
198
198
  changelog_uri: https://github.com/dazuma/toys/blob/master/toys-core/CHANGELOG.md
199
199
  source_code_uri: https://github.com/dazuma/toys
200
200
  bug_tracker_uri: https://github.com/dazuma/toys/issues
201
- documentation_uri: https://dazuma.github.io/toys/gems/toys-core/v0.10.0
201
+ documentation_uri: https://dazuma.github.io/toys/gems/toys-core/v0.10.1
202
202
  post_install_message:
203
203
  rdoc_options: []
204
204
  require_paths: