1
0
mirror of https://github.com/danog/process.git synced 2024-11-29 20:29:16 +01:00

Use shared CS config; update styles

This commit is contained in:
Aaron Piotrowski 2018-10-14 23:16:09 -05:00
parent c2c529d72d
commit 9460633c7d
No known key found for this signature in database
GPG Key ID: ADD1EF783EDE9EEB
24 changed files with 242 additions and 157 deletions

46
.php_cs
View File

@ -1,40 +1,10 @@
<?php
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
"@PSR1" => true,
"@PSR2" => true,
"braces" => [
"allow_single_line_closure" => true,
"position_after_functions_and_oop_constructs" => "same",
],
"array_syntax" => ["syntax" => "short"],
"cast_spaces" => true,
"combine_consecutive_unsets" => true,
"function_to_constant" => true,
"no_multiline_whitespace_before_semicolons" => true,
"no_unused_imports" => true,
"no_useless_else" => true,
"no_useless_return" => true,
"no_whitespace_before_comma_in_array" => true,
"no_whitespace_in_blank_line" => true,
"non_printable_character" => true,
"normalize_index_brace" => true,
"ordered_imports" => true,
"php_unit_construct" => true,
"php_unit_dedicate_assert" => true,
"php_unit_fqcn_annotation" => true,
"phpdoc_summary" => true,
"phpdoc_types" => true,
"psr4" => true,
"return_type_declaration" => ["space_before" => "none"],
"short_scalar_cast" => true,
"single_blank_line_before_namespace" => true,
])
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__ . "/examples")
->in(__DIR__ . "/lib")
->in(__DIR__ . "/test")
);
$config = new Amp\CodeStyle\Config();
$config->getFinder()->in(__DIR__);
$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__;
$config->setCacheFile($cacheDir . '/.php_cs.cache');
return $config;

View File

@ -5,12 +5,12 @@
"require": {
"php": ">=7",
"amphp/amp": "^2",
"amphp/byte-stream": "^1"
"amphp/byte-stream": "^1.2"
},
"require-dev": {
"phpunit/phpunit": "^6",
"amphp/phpunit-util": "^1",
"friendsofphp/php-cs-fixer": "^2.3"
"amphp/php-cs-fixer-config": "dev-master"
},
"license": "MIT",
"authors": [
@ -42,5 +42,14 @@
"platform": {
"php": "7.0.0"
}
},
"scripts": {
"check": [
"@cs",
"@test"
],
"cs": "php-cs-fixer fix -v --diff --dry-run",
"cs-fix": "php-cs-fixer fix -v --diff",
"test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text"
}
}

View File

@ -1,6 +1,6 @@
<?php
include dirname(__DIR__) . "/vendor/autoload.php";
include \dirname(__DIR__) . "/vendor/autoload.php";
use Amp\ByteStream\Message;
use Amp\Process\Process;

View File

@ -1,11 +1,12 @@
<?php
include dirname(__DIR__) . "/vendor/autoload.php";
include \dirname(__DIR__) . "/vendor/autoload.php";
use Amp\Process\Process;
use function Amp\Promise\all;
function show_process_output(Process $process): \Generator {
function show_process_output(Process $process): \Generator
{
$stream = $process->getStdout();
while (null !== $chunk = yield $stream->read()) {

View File

@ -1,6 +1,6 @@
<?php
include dirname(__DIR__) . "/vendor/autoload.php";
include \dirname(__DIR__) . "/vendor/autoload.php";
use Amp\Process\Process;

View File

@ -1,6 +1,6 @@
<?php
include dirname(__DIR__) . "/vendor/autoload.php";
include \dirname(__DIR__) . "/vendor/autoload.php";
use Amp\ByteStream\Message;
use Amp\Process\Process;

View File

@ -6,8 +6,10 @@ use Amp\Deferred;
use Amp\Process\Internal\ProcessHandle;
/** @internal */
final class Handle extends ProcessHandle {
public function __construct() {
final class Handle extends ProcessHandle
{
public function __construct()
{
$this->pidDeferred = new Deferred;
$this->joinDeferred = new Deferred;
$this->originalParentPid = \getmypid();

View File

@ -15,7 +15,8 @@ use Amp\Process\ProcessOutputStream;
use Amp\Promise;
/** @internal */
final class Runner implements ProcessRunner {
final class Runner implements ProcessRunner
{
const FD_SPEC = [
["pipe", "r"], // stdin
["pipe", "w"], // stdout
@ -23,7 +24,8 @@ final class Runner implements ProcessRunner {
["pipe", "w"], // exit code pipe
];
public static function onProcessEndExtraDataPipeReadable($watcher, $stream, Handle $handle) {
public static function onProcessEndExtraDataPipeReadable($watcher, $stream, Handle $handle)
{
Loop::cancel($watcher);
$handle->extraDataPipeWatcher = null;
@ -36,7 +38,8 @@ final class Runner implements ProcessRunner {
}
}
public static function onProcessStartExtraDataPipeReadable($watcher, $stream, $data) {
public static function onProcessStartExtraDataPipeReadable($watcher, $stream, $data)
{
Loop::cancel($watcher);
$pid = \rtrim(@\fgets($stream));
@ -70,7 +73,8 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle {
public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle
{
$command = \sprintf(
'{ (%s) <&3 3<&- 3>/dev/null & } 3<&0;' .
'pid=$!; echo $pid >&3; wait $pid; RC=$?; echo $RC >&3; exit $RC',
@ -124,7 +128,8 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function join(ProcessHandle $handle): Promise {
public function join(ProcessHandle $handle): Promise
{
/** @var Handle $handle */
if ($handle->extraDataPipeWatcher !== null) {
Loop::reference($handle->extraDataPipeWatcher);
@ -134,7 +139,8 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function kill(ProcessHandle $handle) {
public function kill(ProcessHandle $handle)
{
/** @var Handle $handle */
if ($handle->extraDataPipeWatcher !== null) {
Loop::cancel($handle->extraDataPipeWatcher);
@ -160,7 +166,8 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function signal(ProcessHandle $handle, int $signo) {
public function signal(ProcessHandle $handle, int $signo)
{
/** @var Handle $handle */
if (!\proc_terminate($handle->proc, $signo)) {
throw new ProcessException("Sending signal to process failed");
@ -168,7 +175,8 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function destroy(ProcessHandle $handle) {
public function destroy(ProcessHandle $handle)
{
/** @var Handle $handle */
if ($handle->status < ProcessStatus::ENDED && \getmypid() === $handle->originalParentPid) {
try {
@ -182,7 +190,8 @@ final class Runner implements ProcessRunner {
$this->free($handle);
}
private function free(Handle $handle) {
private function free(Handle $handle)
{
/** @var Handle $handle */
if ($handle->extraDataPipeWatcher !== null) {
Loop::cancel($handle->extraDataPipeWatcher);

View File

@ -7,7 +7,8 @@ use Amp\Process\ProcessInputStream;
use Amp\Process\ProcessOutputStream;
use Amp\Struct;
abstract class ProcessHandle {
abstract class ProcessHandle
{
use Struct;
/** @var ProcessOutputStream */

View File

@ -5,7 +5,8 @@ namespace Amp\Process\Internal;
use Amp\Process\ProcessException;
use Amp\Promise;
interface ProcessRunner {
interface ProcessRunner
{
/**
* Start a process using the supplied parameters.
*

View File

@ -2,12 +2,14 @@
namespace Amp\Process\Internal;
final class ProcessStatus {
final class ProcessStatus
{
const STARTING = 0;
const RUNNING = 1;
const ENDED = 2;
private function __construct() {
private function __construct()
{
// empty to prevent instances of this class
}
}

View File

@ -9,8 +9,10 @@ use Amp\Process\Internal\ProcessHandle;
* @internal
* @codeCoverageIgnore Windows only.
*/
final class Handle extends ProcessHandle {
public function __construct() {
final class Handle extends ProcessHandle
{
public function __construct()
{
$this->joinDeferred = new Deferred;
$this->pidDeferred = new Deferred;
}

View File

@ -6,7 +6,8 @@ namespace Amp\Process\Internal\Windows;
* @internal
* @codeCoverageIgnore Windows only.
*/
final class HandshakeStatus {
final class HandshakeStatus
{
const SUCCESS = 0;
const SIGNAL_UNEXPECTED = 0x01;
const INVALID_STREAM_ID = 0x02;
@ -14,7 +15,8 @@ final class HandshakeStatus {
const DUPLICATE_STREAM_ID = 0x04;
const INVALID_CLIENT_TOKEN = 0x05;
private function __construct() {
private function __construct()
{
// empty to prevent instances of this class
}
}

View File

@ -8,7 +8,8 @@ use Amp\Struct;
* @internal
* @codeCoverageIgnore Windows only.
*/
final class PendingSocketClient {
final class PendingSocketClient
{
use Struct;
public $readWatcher;

View File

@ -17,7 +17,8 @@ use const Amp\Process\BIN_DIR;
* @internal
* @codeCoverageIgnore Windows only.
*/
final class Runner implements ProcessRunner {
final class Runner implements ProcessRunner
{
const FD_SPEC = [
["pipe", "r"], // stdin
["pipe", "w"], // stdout
@ -33,11 +34,12 @@ final class Runner implements ProcessRunner {
private $socketConnector;
private function makeCommand(string $workingDirectory): string {
private function makeCommand(string $workingDirectory): string
{
$wrapperPath = self::WRAPPER_EXE_PATH;
// We can't execute the exe from within the PHAR, so copy it out...
if (strncmp($wrapperPath, "phar://", 7) === 0) {
if (\strncmp($wrapperPath, "phar://", 7) === 0) {
if (self::$pharWrapperPath === null) {
self::$pharWrapperPath = \tempnam(\sys_get_temp_dir(), "amphp-process-wrapper-");
\copy(self::WRAPPER_EXE_PATH, self::$pharWrapperPath);
@ -65,12 +67,14 @@ final class Runner implements ProcessRunner {
return $result;
}
public function __construct() {
public function __construct()
{
$this->socketConnector = new SocketConnector;
}
/** @inheritdoc */
public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle {
public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle
{
if (\strpos($command, "\0") !== false) {
throw new ProcessException("Can't execute commands that contain null bytes.");
}
@ -130,7 +134,8 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function join(ProcessHandle $handle): Promise {
public function join(ProcessHandle $handle): Promise
{
/** @var Handle $handle */
$handle->exitCodeRequested = true;
@ -142,7 +147,8 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function kill(ProcessHandle $handle) {
public function kill(ProcessHandle $handle)
{
/** @var Handle $handle */
// todo: send a signal to the wrapper to kill the child instead?
if (!\proc_terminate($handle->proc)) {
@ -174,12 +180,14 @@ final class Runner implements ProcessRunner {
}
/** @inheritdoc */
public function signal(ProcessHandle $handle, int $signo) {
public function signal(ProcessHandle $handle, int $signo)
{
throw new ProcessException('Signals are not supported on Windows');
}
/** @inheritdoc */
public function destroy(ProcessHandle $handle) {
public function destroy(ProcessHandle $handle)
{
/** @var Handle $handle */
if ($handle->status < ProcessStatus::ENDED && \is_resource($handle->proc)) {
try {
@ -193,7 +201,8 @@ final class Runner implements ProcessRunner {
$this->free($handle);
}
private function free(Handle $handle) {
private function free(Handle $handle)
{
if ($handle->childPidWatcher !== null) {
Loop::cancel($handle->childPidWatcher);
$handle->childPidWatcher = null;

View File

@ -6,13 +6,15 @@ namespace Amp\Process\Internal\Windows;
* @internal
* @codeCoverageIgnore Windows only.
*/
final class SignalCode {
final class SignalCode
{
const HANDSHAKE = 0x01;
const HANDSHAKE_ACK = 0x02;
const CHILD_PID = 0x03;
const EXIT_CODE = 0x04;
private function __construct() {
private function __construct()
{
// empty to prevent instances of this class
}
}

View File

@ -12,7 +12,8 @@ use Amp\Process\ProcessException;
* @internal
* @codeCoverageIgnore Windows only.
*/
final class SocketConnector {
final class SocketConnector
{
const SERVER_SOCKET_URI = 'tcp://127.0.0.1:0';
const SECURITY_TOKEN_SIZE = 16;
const CONNECT_TIMEOUT = 1000;
@ -32,7 +33,8 @@ final class SocketConnector {
/** @var int */
public $port;
public function __construct() {
public function __construct()
{
$flags = \STREAM_SERVER_LISTEN | \STREAM_SERVER_BIND;
$this->server = \stream_socket_server(self::SERVER_SOCKET_URI, $errNo, $errStr, $flags);
@ -50,14 +52,16 @@ final class SocketConnector {
Loop::unreference(Loop::onReadable($this->server, [$this, 'onServerSocketReadable']));
}
private function failClientHandshake($socket, int $code) {
private function failClientHandshake($socket, int $code)
{
\fwrite($socket, \chr(SignalCode::HANDSHAKE_ACK) . \chr($code));
\fclose($socket);
unset($this->pendingClients[(int) $socket]);
}
public function failHandleStart(Handle $handle, string $message, ...$args) {
public function failHandleStart(Handle $handle, string $message, ...$args)
{
Loop::cancel($handle->connectTimeoutWatcher);
unset($this->pendingProcesses[$handle->wrapperPid]);
@ -88,7 +92,8 @@ final class SocketConnector {
*
* @return string|null
*/
private function readDataFromPendingClient($socket, int $length, PendingSocketClient $state) {
private function readDataFromPendingClient($socket, int $length, PendingSocketClient $state)
{
$data = \fread($socket, $length);
if ($data === false || $data === '') {
@ -109,7 +114,8 @@ final class SocketConnector {
return $data;
}
public function onReadableHandshake($watcher, $socket) {
public function onReadableHandshake($watcher, $socket)
{
$socketId = (int) $socket;
$pendingClient = $this->pendingClients[$socketId];
@ -169,7 +175,8 @@ final class SocketConnector {
$pendingClient->readWatcher = Loop::onReadable($socket, [$this, 'onReadableHandshakeAck']);
}
public function onReadableHandshakeAck($watcher, $socket) {
public function onReadableHandshakeAck($watcher, $socket)
{
$socketId = (int) $socket;
$pendingClient = $this->pendingClients[$socketId];
@ -217,7 +224,8 @@ final class SocketConnector {
}
}
public function onReadableChildPid($watcher, $socket, Handle $handle) {
public function onReadableChildPid($watcher, $socket, Handle $handle)
{
$data = \fread($socket, 5);
if ($data === false || $data === '') {
@ -264,7 +272,8 @@ final class SocketConnector {
unset($this->pendingProcesses[$handle->wrapperPid]);
}
public function onReadableExitCode($watcher, $socket, Handle $handle) {
public function onReadableExitCode($watcher, $socket, Handle $handle)
{
$data = \fread($socket, 5);
if ($data === false || $data === '') {
@ -305,7 +314,8 @@ final class SocketConnector {
}
}
public function onClientSocketConnectTimeout($watcher, $socket) {
public function onClientSocketConnectTimeout($watcher, $socket)
{
$id = (int) $socket;
Loop::cancel($this->pendingClients[$id]->readWatcher);
@ -314,7 +324,8 @@ final class SocketConnector {
\fclose($socket);
}
public function onServerSocketReadable() {
public function onServerSocketReadable()
{
$socket = \stream_socket_accept($this->server);
if (!\stream_set_blocking($socket, false)) {
@ -328,7 +339,8 @@ final class SocketConnector {
$this->pendingClients[(int) $socket] = $pendingClient;
}
public function onProcessConnectTimeout($watcher, Handle $handle) {
public function onProcessConnectTimeout($watcher, Handle $handle)
{
$running = \is_resource($handle->proc) && \proc_get_status($handle->proc)['running'];
$error = null;
@ -352,7 +364,8 @@ final class SocketConnector {
$handle->joinDeferred->fail($error);
}
public function registerPendingProcess(Handle $handle) {
public function registerPendingProcess(Handle $handle)
{
// Use Loop::defer() to start the timeout only after the loop has ticked once. This prevents issues with many
// things started at once, see https://github.com/amphp/process/issues/21.
$handle->connectTimeoutWatcher = Loop::defer(function () use ($handle) {

View File

@ -10,7 +10,8 @@ use Amp\Process\Internal\ProcessStatus;
use Amp\Process\Internal\Windows\Runner as WindowsProcessRunner;
use Amp\Promise;
class Process {
class Process
{
/** @var ProcessRunner */
private $processRunner;
@ -38,7 +39,8 @@ class Process {
*
* @throws \Error If the arguments are invalid.
*/
public function __construct($command, string $cwd = null, array $env = [], array $options = []) {
public function __construct($command, string $cwd = null, array $env = [], array $options = [])
{
$command = \is_array($command)
? \implode(" ", \array_map("escapeshellarg", $command))
: (string) $command;
@ -73,13 +75,15 @@ class Process {
/**
* Stops the process if it is still running.
*/
public function __destruct() {
public function __destruct()
{
if ($this->handle !== null) {
$this->processRunner->destroy($this->handle);
}
}
public function __clone() {
public function __clone()
{
throw new \Error("Cloning is not allowed!");
}
@ -88,7 +92,8 @@ class Process {
*
* @throws StatusError If the process has already been started.
*/
public function start() {
public function start()
{
if ($this->handle) {
throw new StatusError("Process has already been started.");
}
@ -103,7 +108,8 @@ class Process {
*
* @throws StatusError If the process has already been started.
*/
public function join(): Promise {
public function join(): Promise
{
if (!$this->handle) {
throw new StatusError("Process has not been started.");
}
@ -117,7 +123,8 @@ class Process {
* @throws StatusError If the process is not running.
* @throws ProcessException If terminating the process fails.
*/
public function kill() {
public function kill()
{
if (!$this->isRunning()) {
throw new StatusError("Process is not running.");
}
@ -133,7 +140,8 @@ class Process {
* @throws StatusError If the process is not running.
* @throws ProcessException If sending the signal fails.
*/
public function signal(int $signo) {
public function signal(int $signo)
{
if (!$this->isRunning()) {
throw new StatusError("Process is not running.");
}
@ -148,7 +156,8 @@ class Process {
*
* @throws StatusError If the process has not started.
*/
public function getPid(): Promise {
public function getPid(): Promise
{
if (!$this->handle) {
throw new StatusError("Process has not been started.");
}
@ -161,7 +170,8 @@ class Process {
*
* @return string The command to execute.
*/
public function getCommand(): string {
public function getCommand(): string
{
return $this->command;
}
@ -170,7 +180,8 @@ class Process {
*
* @return string The current working directory an empty string if inherited from the current PHP process.
*/
public function getWorkingDirectory(): string {
public function getWorkingDirectory(): string
{
if ($this->cwd === "") {
return \getcwd() ?: "";
}
@ -183,7 +194,8 @@ class Process {
*
* @return string[] Array of environment variables.
*/
public function getEnv(): array {
public function getEnv(): array
{
return $this->env;
}
@ -192,7 +204,8 @@ class Process {
*
* @return mixed[] Array of options.
*/
public function getOptions(): array {
public function getOptions(): array
{
return $this->options;
}
@ -201,7 +214,8 @@ class Process {
*
* @return bool
*/
public function isRunning(): bool {
public function isRunning(): bool
{
return $this->handle && $this->handle->status !== ProcessStatus::ENDED;
}
@ -210,7 +224,8 @@ class Process {
*
* @return ProcessOutputStream
*/
public function getStdin(): ProcessOutputStream {
public function getStdin(): ProcessOutputStream
{
if (!$this->handle) {
throw new StatusError("Process has not been started.");
}
@ -223,7 +238,8 @@ class Process {
*
* @return ProcessInputStream
*/
public function getStdout(): ProcessInputStream {
public function getStdout(): ProcessInputStream
{
if (!$this->handle) {
throw new StatusError("Process has not been started.");
}
@ -236,7 +252,8 @@ class Process {
*
* @return ProcessInputStream
*/
public function getStderr(): ProcessInputStream {
public function getStderr(): ProcessInputStream
{
if (!$this->handle) {
throw new StatusError("Process has not been started.");
}

View File

@ -2,5 +2,6 @@
namespace Amp\Process;
class ProcessException extends \Exception {
class ProcessException extends \Exception
{
}

View File

@ -11,7 +11,8 @@ use Amp\Failure;
use Amp\Promise;
use Amp\Success;
class ProcessInputStream implements InputStream {
class ProcessInputStream implements InputStream
{
/** @var Deferred */
private $initialRead;
@ -27,7 +28,8 @@ class ProcessInputStream implements InputStream {
/** @var StreamException|null */
private $error;
public function __construct(Promise $resourceStreamPromise) {
public function __construct(Promise $resourceStreamPromise)
{
$resourceStreamPromise->onResolve(function ($error, $resourceStream) {
if ($error) {
$this->error = new StreamException("Failed to launch process", 0, $error);
@ -64,7 +66,8 @@ class ProcessInputStream implements InputStream {
*
* @throws PendingReadError Thrown if another read operation is still pending.
*/
public function read(): Promise {
public function read(): Promise
{
if ($this->initialRead) {
throw new PendingReadError;
}
@ -86,7 +89,8 @@ class ProcessInputStream implements InputStream {
return $this->initialRead->promise();
}
public function reference() {
public function reference()
{
$this->referenced = true;
if ($this->resourceStream) {
@ -94,7 +98,8 @@ class ProcessInputStream implements InputStream {
}
}
public function unreference() {
public function unreference()
{
$this->referenced = false;
if ($this->resourceStream) {
@ -102,7 +107,8 @@ class ProcessInputStream implements InputStream {
}
}
public function close() {
public function close()
{
$this->shouldClose = true;
if ($this->initialRead) {

View File

@ -10,7 +10,8 @@ use Amp\Deferred;
use Amp\Failure;
use Amp\Promise;
class ProcessOutputStream implements OutputStream {
class ProcessOutputStream implements OutputStream
{
/** @var \SplQueue */
private $queuedWrites;
@ -23,7 +24,8 @@ class ProcessOutputStream implements OutputStream {
/** @var StreamException|null */
private $error;
public function __construct(Promise $resourceStreamPromise) {
public function __construct(Promise $resourceStreamPromise)
{
$this->queuedWrites = new \SplQueue;
$resourceStreamPromise->onResolve(function ($error, $resourceStream) {
if ($error) {
@ -55,7 +57,8 @@ class ProcessOutputStream implements OutputStream {
}
/** @inheritdoc */
public function write(string $data): Promise {
public function write(string $data): Promise
{
if ($this->resourceStream) {
return $this->resourceStream->write($data);
}
@ -75,7 +78,8 @@ class ProcessOutputStream implements OutputStream {
}
/** @inheritdoc */
public function end(string $finalData = ""): Promise {
public function end(string $finalData = ""): Promise
{
if ($this->resourceStream) {
return $this->resourceStream->end($finalData);
}
@ -96,7 +100,8 @@ class ProcessOutputStream implements OutputStream {
return $deferred->promise();
}
public function close() {
public function close()
{
$this->shouldClose = true;
if ($this->resourceStream) {

View File

@ -2,5 +2,6 @@
namespace Amp\Process;
class StatusError extends \Error {
class StatusError extends \Error
{
}

View File

@ -11,14 +11,16 @@ use Amp\Process\ProcessOutputStream;
use Amp\Promise;
use PHPUnit\Framework\TestCase;
class ProcessTest extends TestCase {
class ProcessTest extends TestCase
{
const CMD_PROCESS = \DIRECTORY_SEPARATOR === "\\" ? "cmd /c echo foo" : "echo foo";
const CMD_PROCESS_SLOW = \DIRECTORY_SEPARATOR === "\\" ? "cmd /c ping -n 3 127.0.0.1 > nul" : "sleep 2";
/**
* @expectedException \Amp\Process\StatusError
*/
public function testMultipleExecution() {
public function testMultipleExecution()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$process->start();
@ -26,7 +28,8 @@ class ProcessTest extends TestCase {
});
}
public function testIsRunning() {
public function testIsRunning()
{
Loop::run(function () {
$process = new Process(\DIRECTORY_SEPARATOR === "\\" ? "cmd /c exit 42" : "exit 42");
$process->start();
@ -40,7 +43,8 @@ class ProcessTest extends TestCase {
});
}
public function testExecuteResolvesToExitCode() {
public function testExecuteResolvesToExitCode()
{
Loop::run(function () {
$process = new Process(\DIRECTORY_SEPARATOR === "\\" ? "cmd /c exit 42" : "exit 42");
$process->start();
@ -52,7 +56,8 @@ class ProcessTest extends TestCase {
});
}
public function testCommandCanRun() {
public function testCommandCanRun()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$process->start();
@ -62,7 +67,8 @@ class ProcessTest extends TestCase {
});
}
public function testProcessCanTerminate() {
public function testProcessCanTerminate()
{
if (\DIRECTORY_SEPARATOR === "\\") {
$this->markTestSkipped("Signals are not supported on Windows");
}
@ -76,28 +82,32 @@ class ProcessTest extends TestCase {
});
}
public function testGetWorkingDirectoryIsDefault() {
public function testGetWorkingDirectoryIsDefault()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$this->assertSame(getcwd(), $process->getWorkingDirectory());
$this->assertSame(\getcwd(), $process->getWorkingDirectory());
});
}
public function testGetWorkingDirectoryIsCustomized() {
public function testGetWorkingDirectoryIsCustomized()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS, __DIR__);
$this->assertSame(__DIR__, $process->getWorkingDirectory());
});
}
public function testGetEnv() {
public function testGetEnv()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$this->assertSame([], $process->getEnv());
});
}
public function testGetStdin() {
public function testGetStdin()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$process->start();
@ -106,7 +116,8 @@ class ProcessTest extends TestCase {
});
}
public function testGetStdout() {
public function testGetStdout()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$process->start();
@ -115,7 +126,8 @@ class ProcessTest extends TestCase {
});
}
public function testGetStderr() {
public function testGetStderr()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$process->start();
@ -124,7 +136,8 @@ class ProcessTest extends TestCase {
});
}
public function testProcessEnvIsValid() {
public function testProcessEnvIsValid()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS, null, [
'test' => 'foobar',
@ -140,7 +153,8 @@ class ProcessTest extends TestCase {
/**
* @expectedException \Error
*/
public function testProcessEnvIsInvalid() {
public function testProcessEnvIsInvalid()
{
$process = new Process(self::CMD_PROCESS, null, [
['error_value']
]);
@ -150,7 +164,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process has not been started.
*/
public function testGetStdinIsStatusError() {
public function testGetStdinIsStatusError()
{
$process = new Process(self::CMD_PROCESS, null, []);
$process->getStdin();
}
@ -159,7 +174,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process has not been started.
*/
public function testGetStdoutIsStatusError() {
public function testGetStdoutIsStatusError()
{
$process = new Process(self::CMD_PROCESS, null, []);
$process->getStdout();
}
@ -168,7 +184,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process has not been started.
*/
public function testGetStderrIsStatusError() {
public function testGetStderrIsStatusError()
{
$process = new Process(self::CMD_PROCESS, null, []);
$process->getStderr();
}
@ -177,7 +194,8 @@ class ProcessTest extends TestCase {
* @expectedException \Error
* @expectedExceptionMessage Cloning is not allowed!
*/
public function testProcessCantBeCloned() {
public function testProcessCantBeCloned()
{
$process = new Process(self::CMD_PROCESS);
clone $process;
}
@ -186,7 +204,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\ProcessException
* @expectedExceptionMessage The process was killed
*/
public function testKillImmediately() {
public function testKillImmediately()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS_SLOW);
$process->start();
@ -199,7 +218,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\ProcessException
* @expectedExceptionMessage The process was killed
*/
public function testKillThenReadStdout() {
public function testKillThenReadStdout()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS_SLOW);
$process->start();
@ -219,7 +239,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process has not been started.
*/
public function testProcessHasNotBeenStartedWithJoin() {
public function testProcessHasNotBeenStartedWithJoin()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
yield $process->join();
@ -230,7 +251,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process has not been started.
*/
public function testProcessHasNotBeenStartedWithGetPid() {
public function testProcessHasNotBeenStartedWithGetPid()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
yield $process->getPid();
@ -241,7 +263,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process is not running.
*/
public function testProcessIsNotRunningWithKill() {
public function testProcessIsNotRunningWithKill()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$process->kill();
@ -252,7 +275,8 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process is not running.
*/
public function testProcessIsNotRunningWithSignal() {
public function testProcessIsNotRunningWithSignal()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
$process->signal(0);
@ -263,24 +287,28 @@ class ProcessTest extends TestCase {
* @expectedException \Amp\Process\StatusError
* @expectedExceptionMessage Process has not been started.
*/
public function testProcessHasBeenStarted() {
public function testProcessHasBeenStarted()
{
Loop::run(function () {
$process = new Process(self::CMD_PROCESS);
yield $process->join();
});
}
public function testCommand() {
public function testCommand()
{
$process = new Process([self::CMD_PROCESS]);
$this->assertSame(\implode(" ", \array_map("escapeshellarg", [self::CMD_PROCESS])), $process->getCommand());
}
public function testOptions() {
public function testOptions()
{
$process = new Process(self::CMD_PROCESS);
$this->assertSame([], $process->getOptions());
}
public function getProcessCounts(): array {
public function getProcessCounts(): array
{
return \array_map(function (int $count): array {
return [$count];
}, \range(2, 32, 2));
@ -291,7 +319,8 @@ class ProcessTest extends TestCase {
*
* @param int $count
*/
public function testSpawnMultipleProcesses(int $count) {
public function testSpawnMultipleProcesses(int $count)
{
Loop::run(function () use ($count) {
$processes = [];
for ($i = 0; $i < $count; ++$i) {
@ -309,7 +338,8 @@ class ProcessTest extends TestCase {
});
}
public function testReadOutputAfterExit() {
public function testReadOutputAfterExit()
{
Loop::run(function () {
$process = new Process(["php", __DIR__ . "/bin/worker.php"]);
$process->start();
@ -321,14 +351,15 @@ class ProcessTest extends TestCase {
});
}
public function testReadOutputAfterExitWithLongOutput() {
public function testReadOutputAfterExitWithLongOutput()
{
Loop::run(function () {
$process = new Process(["php", __DIR__ . "/bin/worker.php"]);
$process->start();
$count = 128 * 1024 + 1;
$process->getStdin()->write("exit " . $count);
$this->assertSame(str_repeat(".", $count), yield new Message($process->getStdout()));
$this->assertSame(\str_repeat(".", $count), yield new Message($process->getStdout()));
$this->assertSame(0, yield $process->join());
});

View File

@ -1,15 +1,15 @@
<?php
$content = fread(STDIN, 1024);
$content = \fread(STDIN, 1024);
$command = explode(" ", $content);
$command = \explode(" ", $content);
if (count($command) !== 2) {
if (\count($command) !== 2) {
exit(1);
}
if ($command[0] === "exit") {
echo str_repeat(".", (int) $command[1]);
echo \str_repeat(".", (int) $command[1]);
exit;
}