Skip to content

Commit 4bec310

Browse files
ysbaddadenRX14
authored andcommittedAug 19, 2017
Use an Enum for Process stdio redirections (#4445)
1 parent 7f38887 commit 4bec310

File tree

6 files changed

+40
-29
lines changed

6 files changed

+40
-29
lines changed
 

Diff for: ‎spec/std/process_spec.cr

+5-5
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe Process do
3737

3838
it "redirects output to /dev/null" do
3939
# This doesn't test anything but no output should be seen while running tests
40-
Process.run("/bin/ls", output: false).exit_code.should eq(0)
40+
Process.run("/bin/ls", output: Process::Redirect::Close).exit_code.should eq(0)
4141
end
4242

4343
it "gets output" do
@@ -83,7 +83,7 @@ describe Process do
8383

8484
it "sets working directory" do
8585
parent = File.dirname(Dir.current)
86-
value = Process.run("pwd", shell: true, chdir: parent, output: nil) do |proc|
86+
value = Process.run("pwd", shell: true, chdir: parent, output: Process::Redirect::Pipe) do |proc|
8787
proc.output.gets_to_end
8888
end
8989
value.should eq "#{parent}\n"
@@ -96,19 +96,19 @@ describe Process do
9696
end
9797

9898
it "looks up programs in the $PATH with a shell" do
99-
proc = Process.run("uname", {"-a"}, shell: true, output: false)
99+
proc = Process.run("uname", {"-a"}, shell: true, output: Process::Redirect::Close)
100100
proc.exit_code.should eq(0)
101101
end
102102

103103
it "allows passing huge argument lists to a shell" do
104-
proc = Process.new(%(echo "${@}"), {"a", "b"}, shell: true, output: nil)
104+
proc = Process.new(%(echo "${@}"), {"a", "b"}, shell: true, output: Process::Redirect::Pipe)
105105
output = proc.output.gets_to_end
106106
proc.wait
107107
output.should eq "a b\n"
108108
end
109109

110110
it "does not run shell code in the argument list" do
111-
proc = Process.new("echo", {"`echo hi`"}, shell: true, output: nil)
111+
proc = Process.new("echo", {"`echo hi`"}, shell: true, output: Process::Redirect::Pipe)
112112
output = proc.output.gets_to_end
113113
proc.wait
114114
output.should eq "`echo hi`\n"

Diff for: ‎src/compiler/crystal/codegen/link.cr

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ module Crystal
111111

112112
if libname = attr.lib
113113
if has_pkg_config.nil?
114-
has_pkg_config = Process.run("which", {"pkg-config"}, output: false).success?
114+
has_pkg_config = Process.run("which", {"pkg-config"}, output: Process::Redirect::Close).success?
115115
end
116116

117117
if has_pkg_config && (libflags = pkg_config_flags(libname, attr.static?, library_path))

Diff for: ‎src/compiler/crystal/command.cr

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ class Crystal::Command
216216
status, elapsed_time = @progress_tracker.stage("Execute") do
217217
begin
218218
start_time = Time.now
219-
Process.run(output_filename, args: run_args, input: true, output: true, error: true) do |process|
219+
Process.run(output_filename, args: run_args, input: Process::Redirect::Inherit, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit) do |process|
220220
# Ignore the signal so we don't exit the running process
221221
# (the running process can still handle this signal)
222222
Signal::INT.ignore # do

Diff for: ‎src/compiler/crystal/command/deps.cr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class Crystal::Command
88
error "`shards` executable is missing. Please install shards: https://github.com/crystal-lang/shards"
99
end
1010

11-
status = Process.run(path_to_shards, args: options, output: true, error: true)
11+
status = Process.run(path_to_shards, args: options, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit)
1212
exit status.exit_code unless status.success?
1313
end
1414
end

Diff for: ‎src/compiler/crystal/tools/playground/server.cr

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ module Crystal::Playground
150150
stop_process
151151

152152
@logger.info "Code execution started (session=#{@session_key}, tag=#{tag}, filename=#{output_filename})."
153-
process = @process = Process.new(output_filename, args: [] of String, input: nil, output: nil, error: nil)
153+
process = @process = Process.new(output_filename, args: [] of String, input: Process::Redirect::Pipe, output: Process::Redirect::Pipe, error: Process::Redirect::Pipe)
154154
@running_process_filename = output_filename
155155

156156
spawn do

Diff for: ‎src/process.cr

+31-20
Original file line numberDiff line numberDiff line change
@@ -129,19 +129,28 @@ class Process
129129
pid
130130
end
131131

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
139147
alias Env = Nil | Hash(String, Nil) | Hash(String, String?) | Hash(String, String)
140148

141149
# Executes a process and waits for it to complete.
142150
#
143151
# 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
145154
status = new(command, args, env, clear_env, shell, input, output, error, chdir).wait
146155
$? = status
147156
status
@@ -153,7 +162,8 @@ class Process
153162
# will be closed automatically at the end of the block.
154163
#
155164
# 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)
157167
process = new(command, args, env, clear_env, shell, input, output, error, chdir)
158168
begin
159169
value = yield process
@@ -171,7 +181,8 @@ class Process
171181
# * `false`: no `IO` (`/dev/null`)
172182
# * `true`: inherit from parent
173183
# * `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)
175186
command, argv = prepare_argv(command, args, shell)
176187
exec_internal(command, argv, env, clear_env, input, output, error, chdir)
177188
end
@@ -194,14 +205,15 @@ class Process
194205
# To wait for it to finish, invoke `wait`.
195206
#
196207
# 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)
198210
command, argv = Process.prepare_argv(command, args, shell)
199211

200212
@wait_count = 0
201213

202214
if needs_pipe?(input)
203215
fork_input, process_input = IO.pipe(read_blocking: true)
204-
if input
216+
if input.is_a?(IO)
205217
@wait_count += 1
206218
spawn { copy_io(input, process_input, channel, close_dst: true) }
207219
else
@@ -211,7 +223,7 @@ class Process
211223

212224
if needs_pipe?(output)
213225
process_output, fork_output = IO.pipe(write_blocking: true)
214-
if output
226+
if output.is_a?(IO)
215227
@wait_count += 1
216228
spawn { copy_io(process_output, output, channel, close_src: true) }
217229
else
@@ -221,7 +233,7 @@ class Process
221233

222234
if needs_pipe?(error)
223235
process_error, fork_error = IO.pipe(write_blocking: true)
224-
if error
236+
if error.is_a?(IO)
225237
@wait_count += 1
226238
spawn { copy_io(process_error, error, channel, close_src: true) }
227239
else
@@ -334,7 +346,7 @@ class Process
334346
end
335347

336348
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))
338350
end
339351

340352
private def copy_io(src, dst, channel, close_src = false, close_dst = false)
@@ -387,10 +399,9 @@ class Process
387399
when IO::FileDescriptor
388400
src_io.blocking = true
389401
dst_io.reopen(src_io)
390-
when true
391-
# use same io as parent
402+
when Redirect::Inherit
392403
dst_io.blocking = true
393-
when false
404+
when Redirect::Close
394405
File.open("/dev/null", mode) do |file|
395406
dst_io.reopen(file)
396407
end
@@ -431,7 +442,7 @@ end
431442
# LICENSE shard.yml Readme.md spec src
432443
# ```
433444
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)
435446
$? = status
436447
status.success?
437448
end
@@ -446,7 +457,7 @@ end
446457
# `echo hi` # => "hi\n"
447458
# ```
448459
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)
450461
output = process.output.gets_to_end
451462
status = process.wait
452463
$? = status

0 commit comments

Comments
 (0)
Please sign in to comment.