open Core.Std
open Async.Std
type t = { pid : pid
; stdin : Writer.t
; stdout : Reader.t
; stderr : Reader.t
}
type cmd_exit
= [ `Exited
of int | `Signal
of int | `Unknown
]
let read_all r =
in
let rec read_all' () =
in
Reader.read r str >>= (function
| `Ok n -> begin
Buffer.add_substring b str
0 n
; read_all' ()
end
| `Eof -> begin
let _ = Reader.close r in
Deferred
.return
(Buffer.contents b
) end)
in
read_all' ()
let wait pi =
In_thread.run
(fun () ->
match OUnix.waitpid [] pi.pid with
| (_, OUnix.WEXITED exit_code) ->
`Exited exit_code
| (_, OUnix.WSIGNALED signal) ->
`Signal signal
| _ ->
`Unknown)
let run ~prog ~args =
let (c_stdin, m_stdin) = OUnix.pipe ()
and (m_stdout, c_stdout) = OUnix.pipe ()
and (m_stderr, c_stderr) = OUnix.pipe ()
in
let pid =
OUnix.create_process
prog
(Array.of_list
(prog
::args
)) c_stdin
c_stdout
c_stderr
in
OUnix.close c_stdin;
OUnix.close c_stdout;
OUnix.close c_stderr;
let module K = Async.Std.Fd.Kind
in
Deferred.return
{ pid = pid
; stdin = Writer.create (Fd.create K.File m_stdin ~name:"stdin")
; stdout = Reader.create (Fd.create K.File m_stdout ~name:"stdout")
; stderr = Reader.create (Fd.create K.File m_stderr ~name:"stderr")
}
let background d =
let ret = Ivar.create () in
whenever (d >>| fun r -> Ivar.fill ret r);
ret
let get_output ~text ~prog ~args =
run ~prog:prog ~args:args >>= fun pi ->
Writer.write pi.stdin text;
Writer.close pi.stdin >>= fun () ->
let stdout = background (read_all pi.stdout) in
let stderr = background (read_all pi.stderr) in
wait pi >>= function
| `Exited 0 ->
Deferred.both (Ivar.read stdout) (Ivar.read stderr) >>= fun (stdout, stderr) ->
Deferred.return (Result.Ok (stdout, stderr))
| err ->
Deferred.both (Ivar.read stdout) (Ivar.read stderr) >>= fun (stdout, stderr) ->
Deferred.return (Result.Error (err, (stdout, stderr)))
bW9kdWxlIE9Vbml4ID0gVW5peApvcGVuIENvcmUuU3RkCm9wZW4gQXN5bmMuU3RkCgp0eXBlIHBpZCA9IGludAoKdHlwZSB0ID0geyBwaWQgICAgOiBwaWQKCSA7IHN0ZGluICA6IFdyaXRlci50CgkgOyBzdGRvdXQgOiBSZWFkZXIudAoJIDsgc3RkZXJyIDogUmVhZGVyLnQKCSB9Cgp0eXBlIGNtZF9leGl0ID0gWyBgRXhpdGVkIG9mIGludCB8IGBTaWduYWwgb2YgaW50IHwgYFVua25vd24gXQoKbGV0IHJlYWRfYWxsIHIgPQogIGxldCBiID0gQnVmZmVyLmNyZWF0ZSAxMDI0CiAgaW4KICBsZXQgcmVjIHJlYWRfYWxsJyAoKSA9CiAgICBsZXQgc3RyID0gU3RyaW5nLmNyZWF0ZSA0MDk2CiAgICBpbgogICAgUmVhZGVyLnJlYWQgciBzdHIgPj49IChmdW5jdGlvbgogICAgICB8IGBPayBuIC0+IGJlZ2luCglCdWZmZXIuYWRkX3N1YnN0cmluZyBiIHN0ciAwIG47CglyZWFkX2FsbCcgKCkKICAgICAgZW5kCiAgICAgIHwgYEVvZiAgLT4gYmVnaW4KCWxldCBfID0gUmVhZGVyLmNsb3NlIHIgaW4KCURlZmVycmVkLnJldHVybiAoQnVmZmVyLmNvbnRlbnRzIGIpCiAgICAgIGVuZCkKICBpbgogIHJlYWRfYWxsJyAoKQoKbGV0IHdhaXQgcGkgPQogIEluX3RocmVhZC5ydW4KICAgIChmdW4gKCkgLT4KICAgICAgbWF0Y2ggT1VuaXgud2FpdHBpZCBbXSBwaS5waWQgd2l0aAoJfCAoXywgT1VuaXguV0VYSVRFRCBleGl0X2NvZGUpIC0+CgkgIGBFeGl0ZWQgZXhpdF9jb2RlCgl8IChfLCBPVW5peC5XU0lHTkFMRUQgc2lnbmFsKSAtPgoJICBgU2lnbmFsIHNpZ25hbAoJfCBfIC0+CgkgIGBVbmtub3duKQoKbGV0IHJ1biB+cHJvZyB+YXJncyA9CiAgbGV0IChjX3N0ZGluLCBtX3N0ZGluKSAgID0gT1VuaXgucGlwZSAoKQogIGFuZCAobV9zdGRvdXQsIGNfc3Rkb3V0KSA9IE9Vbml4LnBpcGUgKCkKICBhbmQgKG1fc3RkZXJyLCBjX3N0ZGVycikgPSBPVW5peC5waXBlICgpCiAgaW4KICBsZXQgcGlkID0KICAgIE9Vbml4LmNyZWF0ZV9wcm9jZXNzCiAgICAgIHByb2cKICAgICAgKEFycmF5Lm9mX2xpc3QgKHByb2c6OmFyZ3MpKQogICAgICBjX3N0ZGluCiAgICAgIGNfc3Rkb3V0CiAgICAgIGNfc3RkZXJyCiAgaW4KICBPVW5peC5jbG9zZSBjX3N0ZGluOwogIE9Vbml4LmNsb3NlIGNfc3Rkb3V0OwogIE9Vbml4LmNsb3NlIGNfc3RkZXJyOwogIGxldCBtb2R1bGUgSyA9IEFzeW5jLlN0ZC5GZC5LaW5kCiAgaW4KICBEZWZlcnJlZC5yZXR1cm4KICAgIHsgcGlkID0gcGlkCiAgICA7IHN0ZGluICA9IFdyaXRlci5jcmVhdGUgKEZkLmNyZWF0ZSBLLkZpbGUgbV9zdGRpbiB+bmFtZToic3RkaW4iKQogICAgOyBzdGRvdXQgPSBSZWFkZXIuY3JlYXRlIChGZC5jcmVhdGUgSy5GaWxlIG1fc3Rkb3V0IH5uYW1lOiJzdGRvdXQiKQogICAgOyBzdGRlcnIgPSBSZWFkZXIuY3JlYXRlIChGZC5jcmVhdGUgSy5GaWxlIG1fc3RkZXJyIH5uYW1lOiJzdGRlcnIiKQogICAgfQoKbGV0IGJhY2tncm91bmQgZCA9CiAgbGV0IHJldCA9IEl2YXIuY3JlYXRlICgpIGluCiAgd2hlbmV2ZXIgKGQgPj58IGZ1biByIC0+IEl2YXIuZmlsbCByZXQgcik7CiAgcmV0CgpsZXQgZ2V0X291dHB1dCB+dGV4dCB+cHJvZyB+YXJncyA9CiAgcnVuIH5wcm9nOnByb2cgfmFyZ3M6YXJncyA+Pj0gZnVuIHBpIC0+CiAgV3JpdGVyLndyaXRlIHBpLnN0ZGluIHRleHQ7CiAgV3JpdGVyLmNsb3NlIHBpLnN0ZGluID4+PSBmdW4gKCkgLT4KICBsZXQgc3Rkb3V0ID0gYmFja2dyb3VuZCAocmVhZF9hbGwgcGkuc3Rkb3V0KSBpbgogIGxldCBzdGRlcnIgPSBiYWNrZ3JvdW5kIChyZWFkX2FsbCBwaS5zdGRlcnIpIGluCiAgd2FpdCBwaSA+Pj0gZnVuY3Rpb24KICAgIHwgYEV4aXRlZCAwIC0+CiAgICAgIERlZmVycmVkLmJvdGggKEl2YXIucmVhZCBzdGRvdXQpIChJdmFyLnJlYWQgc3RkZXJyKSA+Pj0gZnVuIChzdGRvdXQsIHN0ZGVycikgLT4KICAgICAgRGVmZXJyZWQucmV0dXJuIChSZXN1bHQuT2sgKHN0ZG91dCwgc3RkZXJyKSkKICAgIHwgZXJyIC0+CiAgICAgIERlZmVycmVkLmJvdGggKEl2YXIucmVhZCBzdGRvdXQpIChJdmFyLnJlYWQgc3RkZXJyKSA+Pj0gZnVuIChzdGRvdXQsIHN0ZGVycikgLT4KICAgICAgRGVmZXJyZWQucmV0dXJuIChSZXN1bHQuRXJyb3IgKGVyciwgKHN0ZG91dCwgc3RkZXJyKSkpCg==