@@ -35,36 +35,6 @@ module StandardMixins
3535 # but you can also retrieve the service object itself by calling
3636 # {Toys::Context#get} with the key {Toys::StandardMixins::Exec::KEY}.
3737 #
38- # ### Controlling processes
39- #
40- # A process can be started in the *foreground* or the *background*. If you
41- # start a foreground process, it will "take over" your standard input and
42- # output streams by default, and it will keep control until it completes.
43- # If you start a background process, its streams will be redirected to null
44- # by default, and control will be returned to you immediately.
45- #
46- # While a process is running, you can control it using a
47- # {Toys::Utils::Exec::Controller} object. Use a controller to interact with
48- # the process's input and output streams, send it signals, or wait for it
49- # to complete.
50- #
51- # When running a process in the foreground, the controller will be yielded
52- # to an optional block. For example, the following code starts a process in
53- # the foreground and passes its output stream to a controller.
54- #
55- # exec(["git", "init"], out: :controller) do |controller|
56- # loop do
57- # line = controller.out.gets
58- # break if line.nil?
59- # puts "Got line: #{line}"
60- # end
61- # end
62- #
63- # When running a process in the background, the controller is returned from
64- # the method that starts the process:
65- #
66- # controller = exec(["git", "init"], background: true)
67- #
6838 # ### Stream handling
6939 #
7040 # By default, subprocess streams are connected to the corresponding streams
@@ -84,7 +54,7 @@ module StandardMixins
8454 #
8555 # * **Inherit parent stream:** You can inherit the corresponding stream
8656 # in the parent process by passing `:inherit` as the option value. This
87- # is the default if the subprocess is *not* run in the background .
57+ # is the default if the subprocess is run in the foreground .
8858 #
8959 # * **Redirect to null:** You can redirect to a null stream by passing
9060 # `:null` as the option value. This connects to a stream that is not
@@ -136,7 +106,7 @@ module StandardMixins
136106 # the setting `:controller`. You can then manipulate the stream via the
137107 # controller. If you pass a block to {Toys::StandardMixins::Exec#exec},
138108 # it yields the {Toys::Utils::Exec::Controller}, giving you access to
139- # streams.
109+ # streams. See the section below on controlling processes.
140110 #
141111 # * **Make copies of an output stream:** You can "tee," or duplicate the
142112 # `:out` or `:err` stream and redirect those copies to various
@@ -156,6 +126,68 @@ module StandardMixins
156126 # the tee. Larger buffers may allow higher throughput. The default
157127 # is 65536.
158128 #
129+ # ### Controlling processes
130+ #
131+ # A process can be started in the *foreground* or the *background*. If you
132+ # start a foreground process, it will inherit your standard input and
133+ # output streams by default, and it will keep control until it completes.
134+ # If you start a background process, its streams will be redirected to null
135+ # by default, and control will be returned to you immediately.
136+ #
137+ # While a process is running, you can control it using a
138+ # {Toys::Utils::Exec::Controller} object. Use a controller to interact with
139+ # the process's input and output streams, send it signals, or wait for it
140+ # to complete.
141+ #
142+ # When running a process in the foreground, the controller will be yielded
143+ # to an optional block. For example, the following code starts a process in
144+ # the foreground and passes its output stream to a controller.
145+ #
146+ # exec(["git", "init"], out: :controller) do |controller|
147+ # loop do
148+ # line = controller.out.gets
149+ # break if line.nil?
150+ # puts "Got line: #{line}"
151+ # end
152+ # end
153+ #
154+ # At the end of the block, if the controller is handling the process's
155+ # input stream, that stream will automatically be closed. The following
156+ # example programmatically sends data to the `wc` unix program, and
157+ # captures its output. Because the controller is handling the input stream,
158+ # it automatically closes the stream at the end of the block, which causes
159+ # `wc` to end.
160+ #
161+ # result = exec(["wc"], in: :controller, out: :capture) do |controller|
162+ # controller.in.puts "Hello, world!"
163+ # end
164+ # puts "Results: #{result.captured_out}"
165+ #
166+ # Otherwise, depending on the process's behavior, it may continue to run
167+ # after the end of the block. Control will not be returned to the caller
168+ # until the process actually terminates. Conversely, it is also possible
169+ # the process could terminate by itself while the block is still executing.
170+ # You can call controller methods to obtain the process's actual current
171+ # state.
172+ #
173+ # When running a process in the background, the controller is returned
174+ # immediately from the method that starts the process. In the following
175+ # example, git init is kicked off in the background and the output is
176+ # thrown away to /dev/null.
177+ #
178+ # controller = exec(["git", "init"], background: true)
179+ #
180+ # In this mode, use the returned controller to query the process's state
181+ # and interact with it. Streams directed to the controller are not
182+ # automatically closed, so you will need to do so yourself. Following is an
183+ # example of running `wc` in the background:
184+ #
185+ # controller = exec(["wc"], background: true,
186+ # in: :controller, out: :controller)
187+ # controller.in.puts "Hello, world!"
188+ # controller.in.close # Do this explicitly to cause wc to finish
189+ # puts "Results: #{controller.out.read}" # Read the entire stream
190+ #
159191 # ### Result handling
160192 #
161193 # A subprocess result is represented by a {Toys::Utils::Exec::Result}
@@ -193,6 +225,12 @@ module StandardMixins
193225 # puts "exit code: #{result.exit_code}"
194226 # end
195227 #
228+ # In foreground mode, the callback is executed in the calling thread, after
229+ # the process terminates (and after any controller block has completed) but
230+ # before control is returned to the caller. In background mode, the
231+ # callback is executed asynchronously in a separate thread after the
232+ # process terminates.
233+ #
196234 # Finally, you can force your tool to exit if a subprocess fails, similar
197235 # to setting the `set -e` option in bash, by setting the
198236 # `:exit_on_nonzero_status` option. This is often set as a default
@@ -216,6 +254,10 @@ module StandardMixins
216254 #
217255 # * `:background` (Boolean) Runs the process in the background if `true`.
218256 #
257+ # * `:unbundle` (Boolean) Disables any existing bundle when running the
258+ # subprocess. Has no effect if Bundler isn't active at the call point.
259+ # Cannot be used when executing in a fork, e.g. via {#exec_proc}.
260+ #
219261 # Options related to handling results
220262 #
221263 # * `:result_callback` (Proc,Symbol) A procedure that is called, and
@@ -837,12 +879,7 @@ def self._setup_clean_process(cmd)
837879 context = self
838880 opts = Exec . _setup_exec_opts ( opts , context )
839881 context [ KEY ] = Utils ::Exec . new ( **opts ) do |k |
840- case k
841- when :logger
842- context [ Context ::Key ::LOGGER ]
843- when :cli
844- context [ Context ::Key ::CLI ]
845- end
882+ k == :logger ? context [ Context ::Key ::LOGGER ] : nil
846883 end
847884 end
848885 end
0 commit comments