Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions base/process.jl
Original file line number Diff line number Diff line change
Expand Up @@ -383,19 +383,24 @@ end
"""
open(f::Function, command, args...; kwargs...)

Similar to `open(command, args...; kwargs...)`, but calls `f(stream)` on the resulting process
stream, then closes the input stream and waits for the process to complete.
Returns the value returned by `f`.
Similar to `open(command, args...; kwargs...)`, but calls `f(stream)` on the
resulting process stream, then closes the input stream and waits for the process
to complete. Return the value returned by `f` on success. Throw an error if the
process failed, or if the process attempts to print anything to stdout.
"""
function open(f::Function, cmds::AbstractCmd, args...; kwargs...)
P = open(cmds, args...; kwargs...)
ret = try
f(P)
catch
kill(P)
close(P)
rethrow()
finally
close(P.in)
end
close(P.in)
if !eof(P.out)
close(P.out)
throw(_UVError("open(do)", UV_EPIPE))
end
success(P) || pipeline_error(P)
return ret
Expand Down
6 changes: 3 additions & 3 deletions base/shell.jl
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,11 @@ This function may be useful in concert with the `windows_verbatim` flag to

```julia
wincmd(c::String) =
run(Cmd(Cmd(["cmd.exe", "/s /c \" \$c \""]);
run(Cmd(Cmd(["cmd.exe", "/s /c \\" \$c \\""]);
windows_verbatim=true))
wincmd_echo(s::String) =
wincmd("echo " * Base.shell_escape_wincmd(s))
wincmd_echo("hello \$(ENV["USERNAME"]) & the \"whole\" world! (=^I^=)")
wincmd_echo("hello \$(ENV["USERNAME"]) & the \\"whole\\" world! (=^I^=)")
```

But take note that if the input string `s` contains a `%`, the argument list
Expand All @@ -316,7 +316,7 @@ run(setenv(`cmd /C echo %cmdargs%`, "cmdargs" => cmdargs))
```julia
to_print = "All for 1 & 1 for all!"
to_print_esc = Base.shell_escape_wincmd(Base.shell_escape_wincmd(to_print))
run(Cmd(Cmd(["cmd", "/S /C \" break | echo \$(to_print_esc) \""]), windows_verbatim=true))
run(Cmd(Cmd(["cmd", "/S /C \\" break | echo \$(to_print_esc) \\""]), windows_verbatim=true))
```

With an I/O stream parameter `io`, the result will be written there,
Expand Down
36 changes: 16 additions & 20 deletions test/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,30 +98,27 @@ s = io(text)
close(s)
push!(l, ("PipeEndpoint", io))

#FIXME See https://github.com/JuliaLang/julia/issues/14747
# Reading from open(::Command) seems to deadlock on Linux
#=
if !Sys.iswindows()

# Windows type command not working?
# See "could not spawn `type 'C:\Users\appveyor\AppData\Local\Temp\1\jul3516.tmp\file.txt'`"
#https://ci.appveyor.com/project/StefanKarpinski/julia/build/1.0.12733/job/hpwjs4hmf03vs5ag#L1244

# Pipe
# Pipe (#14747)
io = (text) -> begin
write(filename, text)
open(`$(Sys.iswindows() ? "type" : "cat") $filename`)[1]
# Was open(`echo -n $text`)[1]
# See https://github.com/JuliaLang/julia/issues/14747
# we can skip using shell_escape_wincmd, since ", ^, and % aren't legal in
# a filename, so unconditionally wrapping in " is sufficient (okay, that's
# a lie, since ^ and % actually are legal, but DOS is broken)
if Sys.iswindows()
cmd = Cmd(["cmd.exe", "/c type \"$(replace(filename, '/' => '\\'))\""])
cmd = Cmd(cmd; windows_verbatim=true)
cmd = pipeline(cmd, stderr=devnull)
else
cmd = `cat $filename`
end
open(cmd)
end
s = io(text)
@test isa(s, IO)
@test isa(s, Pipe)
@test isa(s, Base.Process)
close(s)
push!(l, ("Pipe", io))

end
=#
push!(l, ("Process", io))


open_streams = []
Expand All @@ -140,7 +137,6 @@ end
verbose = false

for (name, f) in l
local f
local function io(text=text)
local s = f(text)
push!(open_streams, s)
Expand Down Expand Up @@ -319,9 +315,9 @@ for (name, f) in l
text = old_text
write(filename, text)

if !(typeof(io()) in [Base.PipeEndpoint, Pipe, TCPSocket])
if !isa(io(), Union{Base.PipeEndpoint, Base.AbstractPipe, TCPSocket})
verbose && println("$name position...")
@test (s = io(); read!(s, Vector{UInt8}(undef, 4)); position(s)) == 4
@test (s = io(); read!(s, Vector{UInt8}(undef, 4)); position(s)) == 4

verbose && println("$name seek...")
for n = 0:length(text)-1
Expand Down