@@ -129,19 +129,28 @@ class Process
129
129
pid
130
130
end
131
131
132
- # The standard `IO` configuration of a process:
133
- #
134
- # * `nil`: use a pipe
135
- # * `false`: no `IO` (`/dev/null`)
136
- # * `true`: inherit from parent
137
- # * `IO`: use the given `IO`
138
- alias Stdio = Nil | Bool | IO
132
+ # How to redirect the standard input, output and error IO of a process.
133
+ enum Redirect
134
+ # Pipe the IO so the parent process can read (or write) to the process IO
135
+ # throught `#input`, `#output` or `#error`.
136
+ Pipe
137
+
138
+ # Discards the IO.
139
+ Close
140
+
141
+ # Use the IO of the parent process.
142
+ Inherit
143
+ end
144
+
145
+ # The standard `IO` configuration of a process.
146
+ alias Stdio = Redirect | IO
139
147
alias Env = Nil | Hash (String , Nil ) | Hash (String , String ?) | Hash (String , String )
140
148
141
149
# Executes a process and waits for it to complete.
142
150
#
143
151
# By default the process is configured without input, output or error.
144
- def self.run (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false , input : Stdio = false , output : Stdio = false , error : Stdio = false , chdir : String ? = nil ) : Process ::Status
152
+ def self.run (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false ,
153
+ input : Stdio = Redirect ::Close , output : Stdio = Redirect ::Close , error : Stdio = Redirect ::Close , chdir : String ? = nil ) : Process ::Status
145
154
status = new(command, args, env, clear_env, shell, input, output, error, chdir).wait
146
155
$? = status
147
156
status
@@ -153,7 +162,8 @@ class Process
153
162
# will be closed automatically at the end of the block.
154
163
#
155
164
# Returns the block's value.
156
- def self.run (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false , input : Stdio = nil , output : Stdio = nil , error : Stdio = nil , chdir : String ? = nil )
165
+ def self.run (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false ,
166
+ input : Stdio = Redirect ::Pipe , output : Stdio = Redirect ::Pipe , error : Stdio = Redirect ::Pipe , chdir : String ? = nil )
157
167
process = new(command, args, env, clear_env, shell, input, output, error, chdir)
158
168
begin
159
169
value = yield process
@@ -171,7 +181,8 @@ class Process
171
181
# * `false`: no `IO` (`/dev/null`)
172
182
# * `true`: inherit from parent
173
183
# * `IO`: use the given `IO`
174
- def self.exec (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false , input : Bool | IO ::FileDescriptor = true , output : Bool | IO ::FileDescriptor = true , error : Bool | IO ::FileDescriptor = true , chdir : String ? = nil )
184
+ def self.exec (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false ,
185
+ input : Stdio = Redirect ::Inherit , output : Stdio = Redirect ::Inherit , error : Stdio = Redirect ::Inherit , chdir : String ? = nil )
175
186
command, argv = prepare_argv(command, args, shell)
176
187
exec_internal(command, argv, env, clear_env, input, output, error, chdir)
177
188
end
@@ -194,14 +205,15 @@ class Process
194
205
# To wait for it to finish, invoke `wait`.
195
206
#
196
207
# By default the process is configured without input, output or error.
197
- def initialize (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false , input : Stdio = false , output : Stdio = false , error : Stdio = false , chdir : String ? = nil )
208
+ def initialize (command : String , args = nil , env : Env = nil , clear_env : Bool = false , shell : Bool = false ,
209
+ input : Stdio = Redirect ::Close , output : Stdio = Redirect ::Close , error : Stdio = Redirect ::Close , chdir : String ? = nil )
198
210
command, argv = Process .prepare_argv(command, args, shell)
199
211
200
212
@wait_count = 0
201
213
202
214
if needs_pipe?(input)
203
215
fork_input, process_input = IO .pipe(read_blocking: true )
204
- if input
216
+ if input.is_a?( IO )
205
217
@wait_count += 1
206
218
spawn { copy_io(input, process_input, channel, close_dst: true ) }
207
219
else
@@ -211,7 +223,7 @@ class Process
211
223
212
224
if needs_pipe?(output)
213
225
process_output, fork_output = IO .pipe(write_blocking: true )
214
- if output
226
+ if output.is_a?( IO )
215
227
@wait_count += 1
216
228
spawn { copy_io(process_output, output, channel, close_src: true ) }
217
229
else
@@ -221,7 +233,7 @@ class Process
221
233
222
234
if needs_pipe?(error)
223
235
process_error, fork_error = IO .pipe(write_blocking: true )
224
- if error
236
+ if error.is_a?( IO )
225
237
@wait_count += 1
226
238
spawn { copy_io(process_error, error, channel, close_src: true ) }
227
239
else
@@ -334,7 +346,7 @@ class Process
334
346
end
335
347
336
348
private def needs_pipe? (io )
337
- io.nil? || (io.is_a?(IO ) && ! io.is_a?(IO ::FileDescriptor ))
349
+ (io == Redirect :: Pipe ) || (io.is_a?(IO ) && ! io.is_a?(IO ::FileDescriptor ))
338
350
end
339
351
340
352
private def copy_io (src , dst , channel , close_src = false , close_dst = false )
@@ -387,10 +399,9 @@ class Process
387
399
when IO ::FileDescriptor
388
400
src_io.blocking = true
389
401
dst_io.reopen(src_io)
390
- when true
391
- # use same io as parent
402
+ when Redirect ::Inherit
392
403
dst_io.blocking = true
393
- when false
404
+ when Redirect :: Close
394
405
File .open(" /dev/null" , mode) do |file |
395
406
dst_io.reopen(file)
396
407
end
431
442
# LICENSE shard.yml Readme.md spec src
432
443
# ```
433
444
def system (command : String , args = nil ) : Bool
434
- status = Process .run(command, args, shell: true , input: true , output: true , error: true )
445
+ status = Process .run(command, args, shell: true , input: Process :: Redirect :: Inherit , output: Process :: Redirect :: Inherit , error: Process :: Redirect :: Inherit )
435
446
$? = status
436
447
status.success?
437
448
end
446
457
# `echo hi` # => "hi\n"
447
458
# ```
448
459
def ` (command ) : String
449
- process = Process .new(command, shell: true , input: true , output: nil , error: true )
460
+ process = Process .new(command, shell: true , input: Process :: Redirect :: Inherit , output: Process :: Redirect :: Pipe , error: Process :: Redirect :: Inherit )
450
461
output = process.output.gets_to_end
451
462
status = process.wait
452
463
$? = status
0 commit comments