Skip to content

Commit b484d49

Browse files
committed
Code cleanup
1 parent a4dee58 commit b484d49

14 files changed

+198
-29
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ vendor/
22
build/
33
composer.phar
44
composer.lock
5+
.idea/

src/Command.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function setCallback(callable $callback, $readlines=false)
5959
* Read no more than this many bytes at a time
6060
*
6161
* @param int $bytes
62-
* @reutrn Command - Fluent
62+
* @return Command - Fluent
6363
*/
6464
public function setReadBuffer($bytes)
6565
{
@@ -172,6 +172,7 @@ public function argument($arg) {
172172
* @param string|resource $stdin The string contents for STDIN or a stream resource to be consumed
173173
* @param bool $throw_exceptions If true (default), an exception will be thrown if the command fails
174174
* @return Command - Fluent interface
175+
* @throws CommandException The command failed
175176
*/
176177
public function run($stdin = null, $throw_exceptions = true)
177178
{
@@ -181,15 +182,15 @@ public function run($stdin = null, $throw_exceptions = true)
181182
$this->stderr = null;
182183
$this->timestart = microtime(true);
183184

184-
$process = new ProcessManager($this->getFullCommand(), $buffers);
185-
186185
// Prepare the buffers structure
187186
$buffers = [
188187
self::STDIN => $stdin,
189188
self::STDOUT => &$this->stdout,
190189
self::STDERR => &$this->stderr,
191190
];
192191

192+
$process = new ProcessManager($this->getFullCommand(), $buffers);
193+
193194
$this->exitcode = $process->exec($this->callback, $this->callbacklines, $this->readbuffer, $this->cwd, $this->env, $this->conf);
194195
$this->timeend = microtime(true);
195196

src/CommandException.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<?php namespace kamermans\Command;
22

3-
class CommandException extends \Exception {
3+
/**
4+
* Class CommandException is thrown when a command fails
5+
* @package kamermans\Command
6+
*/
7+
class CommandException extends Exception {
48

59
protected $cmd;
610

@@ -14,4 +18,4 @@ public function getCommand()
1418
{
1519
return $this->cmd;
1620
}
17-
}
21+
}

src/Exception.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php namespace kamermans\Command;
2+
3+
/**
4+
* Base Exception
5+
* @package kamermans\Command
6+
*/
7+
class Exception extends \Exception {}

src/ProcessManager.php

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
<?php namespace kamermans\Command;
2-
2+
use kamermans\Command\Stream\Handler;
3+
4+
/**
5+
* Class ProcessManager
6+
* Starts and manages a process, handling STDIN, STDOUT and STDERR and exit status.
7+
*
8+
* @package kamermans\Command
9+
*/
310
class ProcessManager {
411

512
protected $cmd;
@@ -10,6 +17,12 @@ class ProcessManager {
1017
protected $io_writes = [];
1118
protected $streams = [];
1219

20+
21+
/**
22+
* ProcessManager constructor.
23+
* @param string $cmd Full command to be run
24+
* @param array $buffers Array of buffers to be used for STDIN, STDOUT, STDERR
25+
*/
1326
public function __construct($cmd, &$buffers)
1427
{
1528
if (!is_array($buffers)) {
@@ -21,15 +34,15 @@ public function __construct($cmd, &$buffers)
2134
}
2235

2336
/**
24-
* Executes a command returning the exitcode and capturing the stdout and stderr
37+
* Executes a command returning the exit code and capturing the stdout and stderr
2538
*
2639
* @param callable $callback A callback function for stdout/stderr data
2740
* @param bool $callbacklines Call callback for each line
2841
* @param int $buffer_size Read this many bytes at a time
2942
* @param string $cwd Set working directory
3043
* @param array $env Environment variables for the process
3144
* @param array $conf Additional options for proc_open()
32-
* @return int
45+
* @return int Process exit code
3346
*/
3447
public function exec($callback, $callbacklines, $buffer_size, $cwd, $env, $conf)
3548
{
@@ -79,13 +92,24 @@ public function exec($callback, $callbacklines, $buffer_size, $cwd, $env, $conf)
7992
return $exit_code;
8093
}
8194

95+
/**
96+
* Checks all ready read/write handles as returned by `stream_select()` and calls the write() or read() methods
97+
* of their corresponding Stream handler
98+
*
99+
* @see Writer::write()
100+
* @see Reader::read()
101+
*
102+
* @param $handles
103+
* @return bool
104+
* @throws Exception
105+
*/
82106
protected function doReadWrite($handles)
83107
{
84108
if ($handles['ready'] === 0) {
85109
// Stream timeout; no streams ready
86110
return false;
87111
} else if ($handles['ready'] === false) {
88-
throw new \Exception("stream_select() failed while waiting for I/O on command");
112+
throw new Exception("stream_select() failed while waiting for I/O on command");
89113
}
90114

91115
// Read from all ready streams
@@ -108,6 +132,14 @@ protected function doReadWrite($handles)
108132
return true;
109133
}
110134

135+
/**
136+
* Opens the process handle via `proc_open()`
137+
*
138+
* @param string $cwd The initial working dir for the command. This must be an absolute directory path or null.
139+
* @param array $env An array with the environment variables for the command that will be run, or null.
140+
* @param array $conf Additional options to pass to `proc_open()` (as the `$other_options` parameter).
141+
* @throws Exception The command failed to start
142+
*/
111143
protected function open($cwd, $env, $conf)
112144
{
113145
// Define the streams to configure for the process
@@ -120,7 +152,7 @@ protected function open($cwd, $env, $conf)
120152
// Start the process
121153
$this->handle = proc_open($this->cmd, $descriptors, $this->io_handles, $cwd, $env, $conf);
122154
if (!is_resource($this->handle)) {
123-
throw new \Exception("Failed to open process handle");
155+
throw new Exception("Failed to open process handle");
124156
}
125157

126158
// Set all IO handles to non-blocking mode
@@ -142,7 +174,14 @@ protected function open($cwd, $env, $conf)
142174
];
143175
}
144176

145-
protected function close($exit_code, $callback)
177+
/**
178+
* Closes the currently running process and returns the exit code.
179+
*
180+
* @param int $exit_code The code that the process exited with or null if unavailable
181+
* @param callable $callback Output data callback function
182+
* @return int Exit code
183+
*/
184+
protected function close($exit_code, callable $callback=null)
146185
{
147186
// Make sure all IO handles are closed
148187
foreach ($this->io_handles as $id => $handle) {
@@ -171,16 +210,29 @@ protected function close($exit_code, $callback)
171210
return $exit_code;
172211
}
173212

213+
/**
214+
* @return bool true if STDIN buffer is available for reading
215+
*/
174216
protected function isStdInAvailable()
175217
{
176218
return $this->isStdInStreaming() || !empty($this->buffers[Command::STDIN]);
177219
}
178220

221+
/**
222+
* @return bool true if STDIN is a stream (false if it is a string)
223+
*/
179224
protected function isStdInStreaming()
180225
{
181226
return is_resource($this->buffers[Command::STDIN]);
182227
}
183228

229+
/**
230+
* Setup the STDIN, STDOUT and STDERR stream handlers
231+
*
232+
* @param callable|null $callback
233+
* @param bool $callbacklines
234+
* @param int $buffer_size
235+
*/
184236
protected function setupStreams($callback, $callbacklines, $buffer_size)
185237
{
186238
// Prepare STDIN
@@ -253,28 +305,33 @@ protected function setupStreams($callback, $callbacklines, $buffer_size)
253305
];
254306
}
255307

256-
308+
/**
309+
* This function will wait until streams are ready for read/write, or a timeout has occurred, then it will
310+
* return an array of those handles that are ready for processing.
311+
*
312+
* @return array
313+
*/
257314
protected function waitForReadyHandles()
258315
{
259316
// Setup streams before each iteration since they are changed by stream_select()
260317
$stream_select_timeout_sec = null;
261318
$stream_select_timeout_usec = 200000;
262319

263-
$handles['read'] = array_filter($this->io_reads, 'is_resource');
320+
$handles = [
321+
'read' => array_filter($this->io_reads, 'is_resource'),
322+
'write' => [],
323+
'except' => [],
324+
];
264325

265326
if ($this->isStdInAvailable() && is_resource($this->io_handles[Command::STDIN])) {
266327
$handles['write'] = $this->io_writes;
267-
} else {
268-
$handles['write'] = [];
269328
}
270329

271-
$except = [];
272-
273330
// This line will block until a stream is ready for input or output
274331
$num_ready = stream_select(
275332
$handles['read'],
276333
$handles['write'],
277-
$except,
334+
$handles['except'],
278335
$stream_select_timeout_sec,
279336
$stream_select_timeout_usec
280337
);
@@ -284,6 +341,12 @@ protected function waitForReadyHandles()
284341
return $handles;
285342
}
286343

344+
/**
345+
* Returns the Stream Handler (Reader/Writer) that is managing a given IO handle
346+
*
347+
* @param resource $handle
348+
* @return Stream\Handler
349+
*/
287350
protected function getStreamFromIoHandle($handle)
288351
{
289352
return $this->streams[array_search($handle, $this->io_handles)];

src/Stream/CallbackLinesReader.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
use kamermans\Command\TerminateException;
44

5+
/**
6+
* Reads a stream into a callback one line at a time
7+
* @package kamermans\Command\Stream
8+
*/
59
class CallbackLinesReader extends CallbackReader {
610

711
public function read()

src/Stream/CallbackReader.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,35 @@
11
<?php namespace kamermans\Command\Stream;
22

3+
use kamermans\Command\Exception;
34
use kamermans\Command\TerminateException;
45

6+
/**
7+
* Reads a stream into a callback in chunks
8+
* @package kamermans\Command\Stream
9+
*/
510
class CallbackReader extends StringReader {
611

712
protected $callback;
813

9-
public function __construct($stream, $stream_id, $callback, $buffer_size=4096)
14+
/**
15+
* CallbackReader constructor.
16+
*
17+
* Note that the $callback function will be called with two arguments:
18+
* int $stream_id The stream_id that the data was read from
19+
* string $data The data that was read
20+
*
21+
* When the stream is finally closed, it will be called one last time with `$data = null`.
22+
*
23+
* @param resource $stream The source stream to be read from
24+
* @param int $stream_id The ID of the stream (0=STDIN, 1=STDOUT, 2=STDERR)
25+
* @param callable $callback The function that will be called for each chunk of data
26+
* @param int $buffer_size The max bytes that can be copied at one time
27+
* @throws Exception The source stream is invalid
28+
*/
29+
public function __construct($stream, $stream_id, callable $callback, $buffer_size=4096)
1030
{
1131
if (!is_resource($stream)) {
12-
throw new \InvalidArguentException("stream is not a valid resource");
32+
throw new Exception("stream is not a valid resource");
1333
}
1434

1535
$this->callback = $callback;

src/Stream/Handler.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php namespace kamermans\Command\Stream;
2+
3+
/**
4+
* Manages an IO handle/resource and is able to provide stats about the bytes affected.
5+
* @package kamermans\Command\Stream
6+
*/
7+
interface Handler {
8+
9+
public function getBytes();
10+
11+
}

src/Stream/Reader.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
<?php namespace kamermans\Command\Stream;
22

3+
/**
4+
* Handles a stream and can read from it
5+
* @package kamermans\Command\Stream
6+
*/
37
interface Reader {
48

9+
/**
10+
* Reads data from a stream. This function should be called until the stream is closed (EOF).
11+
* @return int bytes read
12+
*/
513
public function read();
6-
public function getBytes();
714

815
}

src/Stream/StreamWriter.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
<?php namespace kamermans\Command\Stream;
22

3-
class StreamWriter implements Writer {
3+
use kamermans\Command\Exception;
4+
5+
/**
6+
* Writes a stream into another stream
7+
* @package kamermans\Command\Stream
8+
*/
9+
class StreamWriter implements Handler, Writer {
410

511
protected $id;
612
protected $stream;
@@ -9,14 +15,22 @@ class StreamWriter implements Writer {
915
protected $buffer_size;
1016
protected $bytes = 0;
1117

18+
/**
19+
* StreamWriter constructor.
20+
*
21+
* @param resource $source_stream The source stream that will be read from
22+
* @param resource $dest_stream The destination stream that will be written to
23+
* @param int $buffer_size The max bytes that can be copied at one time
24+
* @throws Exception The source or destination streams are invalid
25+
*/
1226
public function __construct($source_stream, $dest_stream, $buffer_size=4096)
1327
{
1428
if (!is_resource($source_stream)) {
15-
throw new \InvalidArguentException("source_stream is not a valid resource");
29+
throw new Exception("source_stream is not a valid resource");
1630
}
1731

1832
if (!is_resource($dest_stream)) {
19-
throw new \InvalidArgumentException("dest_stream is not a valid resource");
33+
throw new Exception("dest_stream is not a valid resource");
2034
}
2135

2236
$this->id = (string)$source_stream;

0 commit comments

Comments
 (0)