diff --git a/base/exports.jl b/base/exports.jl index 2f87c86d5976a..bcb70cba15886 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1195,6 +1195,7 @@ export readline, readlines, readuntil, + redirect, redirect_stderr, redirect_stdin, redirect_stdout, diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 9f5b2e661087d..bfda1bc066bfd 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -83,7 +83,7 @@ end global _clipboardcmd _clipboardcmd !== nothing && return _clipboardcmd for cmd in (:xclip, :xsel) - success(`which $cmd` |> DevNull) && return _clipboardcmd = cmd + success(`which $cmd` |> redirect(DevNull)) && return _clipboardcmd = cmd end error("no clipboard command found, please install xsel or xclip") end @@ -158,7 +158,7 @@ function versioninfo(io::IO=STDOUT, verbose::Bool=false) println(io, " WORD_SIZE: ", Sys.WORD_SIZE) if verbose lsb = "" - @linux_only try lsb = readchomp(`lsb_release -ds` .> DevNull) end + @linux_only try lsb = readchomp(`lsb_release -ds` |> redirect(stderr=DevNull)) end @windows_only try lsb = strip(readall(`$(ENV["COMSPEC"]) /c ver`)) end if lsb != "" println(io, " ", lsb) @@ -333,7 +333,7 @@ downloadcmd = nothing global downloadcmd if downloadcmd === nothing for checkcmd in (:curl, :wget, :fetch) - if success(`which $checkcmd` |> DevNull) + if success(`which $checkcmd` |> redirect(DevNull)) downloadcmd = checkcmd break end diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 9b79d9a119095..eae8b285192cc 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -53,7 +53,7 @@ function add(pkg::AbstractString, vers::VersionSet) outdated = :yes else try - run(Git.cmd(`fetch -q --all`, dir="METADATA") |>DevNull .>DevNull) + run(Git.cmd(`fetch -q --all`, dir="METADATA") |> redirect(DevNull,stderr=DevNull)) outdated = Git.success(`diff --quiet origin/$branch`, dir="METADATA") ? (:no) : (:yes) end diff --git a/base/pkg/generate.jl b/base/pkg/generate.jl index 1907db42e8cd8..ffbfebb5e9c57 100644 --- a/base/pkg/generate.jl +++ b/base/pkg/generate.jl @@ -9,7 +9,7 @@ github_user() = readchomp(ignorestatus(`git config --global --get github.user`)) function git_contributors(dir::AbstractString, n::Int=typemax(Int)) contrib = Dict() tty = @windows? "CON:" : "/dev/tty" - for line in eachline(tty |> Git.cmd(`shortlog -nes`, dir=dir)) + for line in eachline(tty |> redirect(Git.cmd(`shortlog -nes`, dir=dir))) m = match(r"\s*(\d+)\s+(.+?)\s+\<(.+?)\>\s*$", line) m == nothing && continue commits, name, email = m.captures diff --git a/base/pkg/git.jl b/base/pkg/git.jl index 5ec3555279b67..aac15d44e2163 100644 --- a/base/pkg/git.jl +++ b/base/pkg/git.jl @@ -19,7 +19,7 @@ function git(d) end cmd(args::Cmd; dir="") = `$(git(dir)) $args` -run(args::Cmd; dir="", out=STDOUT) = Base.run(cmd(args,dir=dir) |> out) +run(args::Cmd; dir="", out=STDOUT) = Base.run(cmd(args,dir=dir) |> redirect(out)) readall(args::Cmd; dir="") = Base.readall(cmd(args,dir=dir)) readchomp(args::Cmd; dir="") = Base.readchomp(cmd(args,dir=dir)) diff --git a/base/process.jl b/base/process.jl index 6b9ed3d451858..a9965245c8836 100644 --- a/base/process.jl +++ b/base/process.jl @@ -47,7 +47,7 @@ function show(io::IO, cmd::Cmd) (print_dir || print_env) && print(io, ")") end -function show(io::IO, cmds::OrCmds) +function show(io::IO, cmds::Union(OrCmds,ErrOrCmds)) if isa(cmds.a, AndCmds) || isa(cmds.a, CmdRedirect) print(io, "(") show(io, cmds.a) @@ -55,18 +55,14 @@ function show(io::IO, cmds::OrCmds) else show(io, cmds.a) end - print(io, " |> ") - if isa(cmds.b, AndCmds) || isa(cmds.b, CmdRedirect) - print(io, "(") - show(io, cmds.b) - print(io, ")") - else - show(io, cmds.b) - end + print(io, " |> redirect(") + isa(cmds, ErrOrCmds) && print(io, "stderr=") + show(io, cmds.b) + print(io, ")") end function show(io::IO, cmds::AndCmds) - if isa(cmds.a, OrCmds) || isa(cmds.a, CmdRedirect) + if isa(cmds.a, OrCmds) || isa(cmds.a, ErrOrCmds) || isa(cmds.a, CmdRedirect) print(io, "(") show(io, cmds.a) print(io, ")") @@ -74,7 +70,7 @@ function show(io::IO, cmds::AndCmds) show(io, cmds.a) end print(io, " & ") - if isa(cmds.b, OrCmds) || isa(cmds.b, CmdRedirect) + if isa(cmds.a, OrCmds) || isa(cmds.a, ErrOrCmds) || isa(cmds.a, CmdRedirect) print(io, "(") show(io, cmds.b) print(io, ")") @@ -122,16 +118,19 @@ end function show(io::IO, cr::CmdRedirect) if cr.stream_no == STDOUT_NO show(io, cr.cmd) - print(io, " |> ") + print(io, " |> redirect(") show(io, cr.handle) + print(io, ")") elseif cr.stream_no == STDERR_NO show(io, cr.cmd) - print(io, " .> ") + print(io, " |> redirect(stderr=") show(io, cr.handle) + print(io, ")") elseif cr.stream_no == STDIN_NO show(io, cr.handle) - print(io, " |> ") + print(io, " |> redirect(") show(io, cr.cmd) + print(io, ")") end end @@ -145,21 +144,36 @@ setenv(cmd::Cmd, env::Associative; dir="") = (cmd.env = ByteString[string(k)*"=" setenv(cmd::Cmd; dir="") = (cmd.dir = dir; cmd) (&)(left::AbstractCmd, right::AbstractCmd) = AndCmds(left, right) -(|>)(src::AbstractCmd, dest::AbstractCmd) = OrCmds(src, dest) -(.>)(src::AbstractCmd, dest::AbstractCmd) = ErrOrCmds(src, dest) +redir_out(src::AbstractCmd, dest::AbstractCmd) = OrCmds(src, dest) +redir_err(src::AbstractCmd, dest::AbstractCmd) = ErrOrCmds(src, dest) # Stream Redirects -(|>)(dest::Redirectable, src::AbstractCmd) = CmdRedirect(src, dest, STDIN_NO) -(|>)(src::AbstractCmd, dest::Redirectable) = CmdRedirect(src, dest, STDOUT_NO) -(.>)(src::AbstractCmd, dest::Redirectable) = CmdRedirect(src, dest, STDERR_NO) +redir_out(dest::Redirectable, src::AbstractCmd) = CmdRedirect(src, dest, STDIN_NO) +redir_out(src::AbstractCmd, dest::Redirectable) = CmdRedirect(src, dest, STDOUT_NO) +redir_err(src::AbstractCmd, dest::Redirectable) = CmdRedirect(src, dest, STDERR_NO) # File redirects -(|>)(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, false), STDOUT_NO) -(|>)(src::AbstractString, dest::AbstractCmd) = CmdRedirect(dest, FileRedirect(src, false), STDIN_NO) -(.>)(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, false), STDERR_NO) -(>>)(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, true), STDOUT_NO) -(.>>)(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, true), STDERR_NO) +redir_out(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, false), STDOUT_NO) +redir_out(src::AbstractString, dest::AbstractCmd) = CmdRedirect(dest, FileRedirect(src, false), STDIN_NO) +redir_err(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, false), STDERR_NO) +redir_out_append(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, true), STDOUT_NO) +redir_err_append(src::AbstractCmd, dest::AbstractString) = CmdRedirect(src, FileRedirect(dest, true), STDERR_NO) + +function redirect(stdout; stderr=nothing, append=false) + if stderr !== nothing + if append + cmd->redir_err_append(redir_out_append(cmd, stdout), stderr) + else + cmd->redir_err(redir_out(cmd, stdout), stderr) + end + else + append ? cmd->redir_out_append(cmd, stdout) : cmd->redir_out(cmd, stdout) + end +end +function redirect(; stderr=error("must specify something to redirect to"), append=false) + append ? cmd->redir_err_append(cmd, stderr) : cmd->redir_err(cmd, stderr) +end typealias RawOrBoxedHandle Union(UVHandle,UVStream,Redirectable,IOStream) typealias StdIOSet NTuple{3,RawOrBoxedHandle} diff --git a/base/random.jl b/base/random.jl index eb0e3bddd1003..01017d7177a0d 100644 --- a/base/random.jl +++ b/base/random.jl @@ -124,7 +124,7 @@ function make_seed() seed = reinterpret(UInt64, time()) seed = hash(seed, uint64(getpid())) try - seed = hash(seed, parseint(UInt64, readall(`ifconfig` |> `sha1sum`)[1:40], 16)) + seed = hash(seed, parseint(UInt64, readall(`ifconfig` |> redirect(`sha1sum`))[1:40], 16)) end return make_seed(seed) end diff --git a/test/spawn.jl b/test/spawn.jl index 43a15ec662e58..beafc410abb4e 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -14,23 +14,23 @@ yes = `perl -le 'while (1) {print STDOUT "y"}'` #### Examples used in the manual #### @test readall(`echo hello | sort`) == "hello | sort\n" -@test readall(`echo hello` |> `sort`) == "hello\n" -@test length(spawn(`echo hello` |> `sort`).processes) == 2 +@test readall(`echo hello` |> redirect(`sort`)) == "hello\n" +@test length(spawn(`echo hello` |> redirect(`sort`)).processes) == 2 out = readall(`echo hello` & `echo world`) @test search(out,"world") != (0,0) @test search(out,"hello") != (0,0) -@test readall((`echo hello` & `echo world`) |> `sort`)=="hello\nworld\n" +@test readall((`echo hello` & `echo world`) |> redirect(`sort`))=="hello\nworld\n" @test (run(`printf " \033[34m[stdio passthrough ok]\033[0m\n"`); true) # Test for SIGPIPE being treated as normal termination (throws an error if broken) -@unix_only @test (run(yes|>`head`|>DevNull); true) +@unix_only @test (run(yes|>redirect(`head`)|>redirect(DevNull)); true) begin a = Base.Condition() @schedule begin - p = spawn(yes|>DevNull) + p = spawn(yes|>redirect(DevNull)) Base.notify(a,p) @test !success(p) end @@ -43,29 +43,29 @@ end if false prefixer(prefix, sleep) = `perl -nle '$|=1; print "'$prefix' ", $_; sleep '$sleep';'` @test success(`perl -le '$|=1; for(0..2){ print; sleep 1 }'` |> - prefixer("A",2) & prefixer("B",2)) + redirect(prefixer("A",2) & prefixer("B",2))) @test success(`perl -le '$|=1; for(0..2){ print; sleep 1 }'` |> - prefixer("X",3) & prefixer("Y",3) & prefixer("Z",3) |> - prefixer("A",2) & prefixer("B",2)) + redirect(prefixer("X",3) & prefixer("Y",3) & prefixer("Z",3)) |> + redirect(prefixer("A",2) & prefixer("B",2))) end @test success(`true`) @test !success(`false`) -@test success(`true` |> `true`) +@test success(`true` |> redirect(`true`)) if false @test success(ignorestatus(`false`)) - @test success(ignorestatus(`false`) |> `true`) - @test !success(ignorestatus(`false`) |> `false`) + @test success(ignorestatus(`false`) |> redirect(`true`)) + @test !success(ignorestatus(`false`) |> redirect(`false`)) @test !success(ignorestatus(`false`) & `false`) - @test success(ignorestatus(`false` |> `false`)) + @test success(ignorestatus(`false` |> redirect(`false`))) @test success(ignorestatus(`false` & `false`)) end # STDIN Redirection file = tempname() -run(`echo hello world` |> file) -@test readall(file |> `cat`) == "hello world\n" -@test open(readall, file |> `cat`, "r") == "hello world\n" +run(`echo hello world` |> redirect(file)) +@test readall(file |> redirect(`cat`)) == "hello world\n" +@test open(readall, file |> redirect(`cat`), "r") == "hello world\n" rm(file) # Stream Redirection @@ -75,12 +75,12 @@ rm(file) port, server = listenany(2326) put!(r,port) client = accept(server) - @test readall(client |> `cat`) == "hello world\n" + @test readall(client |> redirect(`cat`)) == "hello world\n" close(server) end @async begin sock = connect(fetch(r)) - run(`echo hello world` |> sock) + run(`echo hello world` |> redirect(sock)) close(sock) end end @@ -102,7 +102,7 @@ str2 = readall(stdout) # This test hangs if the end of run walk across uv streams calls shutdown on a stream that is shutting down. file = tempname() -open(`cat -` |> file, "w") do io +open(`cat -` |> redirect(file), "w") do io write(io, str) end rm(file) @@ -154,13 +154,13 @@ close(sock) # issue #4535 exename=joinpath(JULIA_HOME,(ccall(:jl_is_debugbuild,Cint,())==0?"julia":"julia-debug")) -@test readall(`$exename -f -e 'println(STDERR,"Hello World")'` .> `cat`) == "Hello World\n" +@test readall(`$exename -f -e 'println(STDERR,"Hello World")'` |> redirect(stderr=`cat`)) == "Hello World\n" # issue #6310 -@test readall(`echo "2+2"` |> `$exename -f`) == "4\n" +@test readall(`echo "2+2"` |> redirect(`$exename -f`)) == "4\n" # issue #5904 -@test run(ignorestatus(`false`) |> `true`) === nothing +@test run(ignorestatus(`false`) |> redirect(`true`)) === nothing # issue #6010 diff --git a/test/unicode.jl b/test/unicode.jl index 72658ed349d41..4ab1fe2ed3cdf 100644 --- a/test/unicode.jl +++ b/test/unicode.jl @@ -45,7 +45,7 @@ else for encoding in ["UTF-32LE", "UTF-16BE", "UTF-16LE", "UTF-8"] output_path = joinpath(unicodedir, encoding*".unicode") f = Base.FS.open(output_path,Base.JL_O_WRONLY|Base.JL_O_CREAT,Base.S_IRUSR | Base.S_IWUSR | Base.S_IRGRP | Base.S_IROTH) - run(`iconv -f $primary_encoding -t $encoding $primary_path` |> f) + run(`iconv -f $primary_encoding -t $encoding $primary_path` |> redirect(f)) Base.FS.close(f) end