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 +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/toys/core.rb +1 -1
- data/lib/toys/standard_mixins/exec.rb +371 -110
- data/lib/toys/utils/exec.rb +141 -50
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b63889a0ce44a42d805bba363f2051c1b1f82c6c50e70138b35cab077441dcdd
|
4
|
+
data.tar.gz: 0403e5af7269879d468baae34bbae1664c1f83dfef4ec91c1545079502db5c86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 401d695bc0375db501df082733813925f229def58bea2b65f947c453b5b0f2989712b27c0a7d8f4d0f19c7e5f90293210a8c8755985a1584efae54bc35e90d2b
|
7
|
+
data.tar.gz: 258f2466dab53c45d1541f4608af756d9cddf3a7af555d1c11e329ad7de3cb9ce5e52831347cb417e97bb4628a6563220d2fc486669597c38df0f0184bd6aa89
|
data/CHANGELOG.md
CHANGED
data/lib/toys/core.rb
CHANGED
@@ -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
|
-
#
|
22
|
-
#
|
23
|
-
# by
|
24
|
-
#
|
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
|
-
#
|
27
|
-
#
|
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
|
-
#
|
190
|
+
# Options related to logging and reporting:
|
31
191
|
#
|
32
|
-
#
|
192
|
+
# * `:logger` (Logger) Logger to use for logging the actual command. If
|
193
|
+
# not present, the command is not logged.
|
33
194
|
#
|
34
|
-
# *
|
35
|
-
#
|
36
|
-
#
|
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
|
-
#
|
43
|
-
#
|
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
|
-
#
|
51
|
-
#
|
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
|
-
#
|
55
|
-
#
|
56
|
-
#
|
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
|
-
#
|
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
|
-
#
|
211
|
+
# * `:close_others` (Boolean) Whether to close non-redirected
|
212
|
+
# non-standard file descriptors.
|
63
213
|
#
|
64
|
-
#
|
214
|
+
# * `:new_pgroup` (Boolean) Create new process group (Windows only).
|
65
215
|
#
|
66
|
-
#
|
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
|
249
|
+
# Set default configuration options.
|
93
250
|
#
|
94
|
-
#
|
95
|
-
#
|
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.
|
115
|
-
# {Toys::
|
116
|
-
#
|
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
|
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.
|
138
|
-
# {Toys::
|
139
|
-
#
|
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
|
-
#
|
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.
|
165
|
-
# {Toys::
|
166
|
-
#
|
167
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
168
|
-
#
|
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.
|
194
|
-
# {Toys::
|
195
|
-
#
|
196
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
197
|
-
#
|
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.
|
234
|
-
# {Toys::
|
235
|
-
#
|
236
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
237
|
-
#
|
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.
|
262
|
-
# {Toys::
|
263
|
-
#
|
264
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
265
|
-
#
|
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.
|
285
|
-
# {Toys::
|
286
|
-
#
|
287
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
288
|
-
#
|
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.
|
311
|
-
# {Toys::
|
312
|
-
#
|
313
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
314
|
-
#
|
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.
|
340
|
-
# {Toys::
|
341
|
-
#
|
342
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
343
|
-
#
|
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.
|
380
|
-
# {Toys::
|
381
|
-
#
|
382
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
383
|
-
#
|
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.
|
402
|
-
# {Toys::
|
403
|
-
#
|
404
|
-
# @yieldparam controller [Toys::Utils::Exec::Controller] A controller
|
405
|
-
#
|
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
|
-
|
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
|
439
|
-
|
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.
|
446
|
-
|
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.
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
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
|
data/lib/toys/utils/exec.rb
CHANGED
@@ -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
|
-
# ##
|
19
|
+
# ## Features
|
20
20
|
#
|
21
|
-
#
|
21
|
+
# ### Controlling processes
|
22
22
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
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
|
-
#
|
45
|
-
#
|
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
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
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
|
-
#
|
46
|
+
# When running a process in the background, the controller is returned from
|
47
|
+
# the method that starts the process:
|
55
48
|
#
|
56
|
-
#
|
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
|
-
#
|
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
|
-
# * **
|
78
|
-
# the
|
79
|
-
#
|
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
|
-
# * **
|
85
|
-
#
|
86
|
-
#
|
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}
|
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}
|
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}
|
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}
|
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}
|
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}
|
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}
|
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.
|
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-
|
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.
|
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:
|