5 class Proc
implements Able
29 * @param string $command
32 * @throws \RuntimeException
34 function __construct($command, $cwd = null, array $env = null) {
35 $this->command
= $command;
36 $this->proc
= proc_open($command, [["pipe","r"],["pipe","w"],["pipe","w"]], $this->pipes
, $cwd, $env);
38 if (!is_resource($this->proc
) ||
!($status = proc_get_status($this->proc
))) {
39 throw new \
RuntimeException("Could not open proc '$command': " . error_get_last()["message"]);
42 stream_set_blocking($this->pipes
[1], false);
43 stream_set_blocking($this->pipes
[2], false);
47 * Returns the command string
50 function __toString() {
51 return (string) $this->command
;
55 * Cleanup pipes and proc handle
57 function __destruct() {
63 * @implements \aticker\Able
64 * @param \atick\Ticker $ticker
65 * @param callable $verify
67 function with(Ticker
$ticker, callable
$verify = null) {
68 if (is_callable($this->read
)) {
69 $ticker->read($this->pipes
[1], $this->read
, $verify ?
: array($this, "stat"));
70 } elseif (is_resource($this->read
)) {
71 $ticker->read($this->pipes
[1], function($fd) {
72 if (strlen($data = fread($fd, 8192))) {
73 fwrite($this->read
, $data);
75 }, $verify ?
: array($this, "stat"));
77 $ticker->read($this->pipes
[1], function($fd) {
80 }, $verify ?
: array($this, "stat"));
83 if (is_callable($this->error
)) {
84 $ticker->read($this->pipes
[2], $this->error
, $verify ?
: array($this, "stat"));
85 } elseif (is_resource($this->error
)) {
86 $ticker->read($this->pipes
[2], function($fd) {
87 if (strlen($data = fread($fd, 8192))) {
88 fwrite($this->error
, $data);
90 }, $verify ?
: array($this, "stat"));
92 $ticker->read($this->pipes
[2], function($fd) {
95 }, $verify ?
: array($this, "stat"));
101 if ($this->proc
&& proc_get_status($this->proc
)["running"]) {
102 if ((isset($this->pipes
[1]) && is_resource($this->pipes
[1]) && !feof($this->pipes
[1]))
103 && (isset($this->pipes
[2]) && is_resource($this->pipes
[2]) && !feof($this->pipes
[2]))
105 if (isset($this->pipes
[0]) && is_resource($this->pipes
[0]) && !feof($this->pipes
[0])) {
106 return self
::READABLE | self
::WRITABLE
;
108 return self
::READABLE
;
115 function close($what = self
::CLOSED
) {
116 echo "PROC KILL $this $what\n";
118 if (!$what ||
($what & self
::WRITABLE
)) {
119 if (is_resource($this->pipes
[0])) {
120 fclose($this->pipes
[0]);
122 $this->pipes
[0] = null;
125 if (!$what ||
($what & self
::READABLE
)) {
126 if (is_resource($this->pipes
[1])) {
127 fclose($this->pipes
[1]);
129 $this->pipes
[1] = null;
130 if (is_resource($this->read
)) {
133 if (is_resource($this->pipes
[2])) {
134 fclose($this->pipes
[2]);
136 $this->pipes
[2] = null;
137 if (is_resource($this->error
)) {
138 fclose($this->error
);
142 if (!$what && is_resource($this->proc
)) {
143 proc_close($this->proc
);
150 * @implements \aticker\Able
151 * @param string $data
154 function write($data) {
155 return fwrite($this->pipes
[0], $data);
159 * Where to read STDOUT into
160 * @param resource|callable $into
161 * @return \atick\Proc
162 * @throws \InvalidArgumentException
164 function read($into) {
165 if (is_resource($into) ||
is_callable($into)) {
168 throw new \
InvalidArgumentException("Not a valid resource or callback");
174 * Where to pass STDERR into
175 * @param resource|callable $into
176 * @return \atick\Proc
177 * @throws \InvalidArgumentException
179 function error($into) {
180 if (is_resource($into) ||
is_callable($into)) {
181 $this->error
= $into;
183 throw new \
InvalidArgumentException("Not a valid resource or callback");