@@ -310,6 +310,7 @@ mutable struct Process <: AbstractPipe
310310 termsignal:: Int32
311311 exitnotify:: Condition
312312 closenotify:: Condition
313+ openstream:: Symbol # for open(cmd) deprecation
313314 function Process (cmd:: Cmd , handle:: Ptr{Void} ,
314315 in:: Union{Redirectable, Ptr{Void}} ,
315316 out:: Union{Redirectable, Ptr{Void}} ,
@@ -339,7 +340,9 @@ struct ProcessChain <: AbstractPipe
339340 in:: Redirectable
340341 out:: Redirectable
341342 err:: Redirectable
343+ openstream:: Symbol # for open(cmd) deprecation
342344 ProcessChain (stdios:: StdIOSet ) = new (Process[], stdios[1 ], stdios[2 ], stdios[3 ])
345+ ProcessChain (chain:: ProcessChain , openstream:: Symbol ) = new (chain. processes, chain. in, chain. out, chain. err, openstream) # for open(cmd) deprecation
343346end
344347pipe_reader (p:: ProcessChain ) = p. out
345348pipe_writer (p:: ProcessChain ) = p. in
@@ -572,38 +575,55 @@ the process's standard input and `stdio` optionally specifies the process's stan
572575stream.
573576"""
574577function open (cmds:: AbstractCmd , mode:: AbstractString = " r" , other:: Redirectable = DevNull)
575- if mode == " r"
578+ if mode == " r+" || mode == " w+"
579+ other === DevNull || throw (ArgumentError (" no other stream for mode rw+" ))
580+ in = Pipe ()
581+ out = Pipe ()
582+ processes = spawn (cmds, (in,out,STDERR))
583+ close (in. out)
584+ close (out. in)
585+ elseif mode == " r"
576586 in = other
577- out = io = Pipe ()
587+ out = Pipe ()
578588 processes = spawn (cmds, (in,out,STDERR))
579589 close (out. in)
590+ if isa (processes, ProcessChain) # for open(cmd) deprecation
591+ processes = ProcessChain (processes, :out )
592+ else
593+ processes. openstream = :out
594+ end
580595 elseif mode == " w"
581- in = io = Pipe ()
596+ in = Pipe ()
582597 out = other
583598 processes = spawn (cmds, (in,out,STDERR))
584599 close (in. out)
600+ if isa (processes, ProcessChain) # for open(cmd) deprecation
601+ processes = ProcessChain (processes, :in )
602+ else
603+ processes. openstream = :in
604+ end
585605 else
586606 throw (ArgumentError (" mode must be \" r\" or \" w\" , not \" $mode \" " ))
587607 end
588- return (io, processes)
608+ return processes
589609end
590610
591611"""
592612 open(f::Function, command, mode::AbstractString="r", stdio=DevNull)
593613
594- Similar to `open(command, mode, stdio)`, but calls `f(stream)` on the resulting read or
595- write stream, then closes the stream and waits for the process to complete. Returns the
596- value returned by `f`.
614+ Similar to `open(command, mode, stdio)`, but calls `f(stream)` on the resulting process
615+ stream, then closes the input stream and waits for the process to complete.
616+ Returns the value returned by `f`.
597617"""
598618function open (f:: Function , cmds:: AbstractCmd , args... )
599- io, P = open (cmds, args... )
619+ P = open (cmds, args... )
600620 ret = try
601- f (io )
602- catch
621+ f (P )
622+ catch e
603623 kill (P)
604- rethrow ()
624+ rethrow (e )
605625 finally
606- close (io )
626+ close (P . in )
607627 end
608628 success (P) || pipeline_error (P)
609629 return ret
@@ -618,15 +638,14 @@ Starts running a command asynchronously, and returns a tuple (stdout,stdin,proce
618638output stream and input stream of the process, and the process object itself.
619639"""
620640function readandwrite (cmds:: AbstractCmd )
621- in = Pipe ()
622- out, processes = open (cmds, " r" , in)
623- (out, in, processes)
641+ processes = open (cmds, " r+" )
642+ return (processes. out, processes. in, processes)
624643end
625644
626645function read (cmd:: AbstractCmd , stdin :: Redirectable = DevNull)
627- out, procs = open (cmd, " r" , stdin )
628- bytes = read (out)
629- ! success (procs) && pipeline_error (procs)
646+ procs = open (cmd, " r" , stdin )
647+ bytes = read (procs . out)
648+ success (procs) || pipeline_error (procs)
630649 return bytes
631650end
632651
@@ -651,9 +670,17 @@ function run(cmds::AbstractCmd, args...)
651670 success (ps) ? nothing : pipeline_error (ps)
652671end
653672
654- const SIGPIPE = 13
673+ # some common signal numbers that are usually available on all platforms
674+ # and might be useful as arguments to `kill` or testing against `Process.termsignal`
675+ const SIGHUP = 1
676+ const SIGINT = 2
677+ const SIGQUIT = 3 # !windows
678+ const SIGKILL = 9
679+ const SIGPIPE = 13 # !windows
680+ const SIGTERM = 15
681+
655682function test_success (proc:: Process )
656- assert ( process_exited (proc) )
683+ @ assert process_exited (proc)
657684 if proc. exitcode < 0
658685 # TODO : this codepath is not currently tested
659686 throw (UVError (" could not start process $(string (proc. cmd)) " , proc. exitcode))
663690
664691function success (x:: Process )
665692 wait (x)
666- kill (x)
667- test_success (x)
693+ return test_success (x)
668694end
669695success (procs:: Vector{Process} ) = mapreduce (success, & , procs)
670696success (procs:: ProcessChain ) = success (procs. processes)
@@ -700,8 +726,6 @@ function pipeline_error(procs::ProcessChain)
700726 error (msg)
701727end
702728
703- _jl_kill (p:: Process , signum:: Integer ) = ccall (:uv_process_kill , Int32, (Ptr{Void},Int32), p. handle, signum)
704-
705729"""
706730 kill(p::Process, signum=SIGTERM)
707731
@@ -710,14 +734,14 @@ Send a signal to a process. The default is to terminate the process.
710734function kill (p:: Process , signum:: Integer )
711735 if process_running (p)
712736 @assert p. handle != C_NULL
713- _jl_kill (p , signum)
737+ ccall ( :uv_process_kill , Int32, (Ptr{Void}, Int32), p . handle , signum)
714738 else
715739 Int32 (- 1 )
716740 end
717741end
718742kill (ps:: Vector{Process} ) = map (kill, ps)
719743kill (ps:: ProcessChain ) = map (kill, ps. processes)
720- kill (p:: Process ) = kill (p, 15 ) # SIGTERM
744+ kill (p:: Process ) = kill (p, SIGTERM)
721745
722746function _contains_newline (bufptr:: Ptr{Void} , len:: Int32 )
723747 return (ccall (:memchr , Ptr{Void}, (Ptr{Void},Int32,Csize_t), bufptr, ' \n ' , len) != C_NULL )
0 commit comments