toys-core 0.10.0 → 0.10.1

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