Skip to content

Commit

Permalink
Fixed issue with output mode and missing $PATH
Browse files Browse the repository at this point in the history
  • Loading branch information
jamielsharief committed Jan 31, 2021
1 parent 7af11cb commit 63c9862
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 134 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [3.17.2] - 2021-01-31

### Fixed

- Fixed issue with standard process during output mode
- Fixed commands not working properly due to missing environment variables like PATH.

## [3.17.1] - 2021-01-31

### Fixed
Expand Down
121 changes: 121 additions & 0 deletions src/Process/BackgroundProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@ class BackgroundProcess extends BaseProcess
*/
private $timeout = null;

/**
* @var array
*/
protected $env = [];

/**
* @var string
*/
protected $directory;

/**
* @var string
*/
protected $command;

/**
* @var boolean
*/
protected $outputEnabled = false;

/**
* @param string|array $stringOrArray
* @param array $options The following options are supported
Expand All @@ -80,6 +100,7 @@ public function __construct($stringOrArray, array $options = [])
];

$this->setDirectory($options['directory']);
$this->setupEnvironment();
$this->setEnv((array) $options['env']);
$this->setCommand($stringOrArray, $options['escape']);

Expand Down Expand Up @@ -322,4 +343,104 @@ private function status(string $key)

return $this->status[$key] ?? null;
}

/**
* @param string $directory
* @return void
*/
protected function setDirectory(string $directory): void
{
if (! is_dir($directory)) {
throw new RuntimeException('Invalid directory');
}
$this->directory = $directory;
}

/**
* Any value as false will delete a current var
*
* @param array $env
* @return void
*/
protected function setEnv(array $env): void
{
foreach ($env as $key => $value) {
if ($value === false) {
unset($this->env[$key]);
continue;
}
$this->env[$key] = $value;
}
}

/**
* Copy the ENV vars so commands can work as expected
*
* @return void
*/
protected function setupEnvironment(): void
{
foreach ($_SERVER as $key => $value) {
$found = getenv($key);
if ($found !== false) {
$this->env[$key] = $value;
}
}

foreach ($_ENV as $key => $value) {
$this->env[$key] = $value;
}
}

/**
* Escapes a command for use
*
* @param string|array $stringOrArray
* @return string|array
*/
private function escapeCommand($stringOrArray)
{
if (is_string($stringOrArray)) {
return escapeshellcmd($stringOrArray);
}

return array_map('escapeshellarg', $stringOrArray);
}

/**
* @param string|array $stringOrArray
* @param boolean $escape
* @return void
*/
protected function setCommand($stringOrArray, bool $escape = true): void
{
if ($escape) {
$stringOrArray = $this->escapeCommand($stringOrArray);
}

$this->command = is_array($stringOrArray) ? implode(' ', $stringOrArray) : $stringOrArray;
}

/**
* @see https://www.php.net/manual/en/function.proc-open.php
*
* @param boolean $output
* @return array
*/
protected function descriptorspec(): array
{
if ($this->outputEnabled && $this->isTTY()) {
return [
['file', '/dev/tty', 'r'],
['file', '/dev/tty', 'w'],
['file', '/dev/tty', 'w'],
];
}

return [
['pipe','r'],
['pipe','w'],
['pipe','w']
];
}
}
99 changes: 2 additions & 97 deletions src/Process/BaseProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,112 +14,17 @@
declare(strict_types = 1);
namespace Origin\Process;

use RuntimeException;

abstract class BaseProcess
{
/**
* @var array
*/
protected $env = [];

/**
* @var string
*/
protected $directory;

/**
* @var string
*/
protected $command;

/**
* @var boolean
*/
protected $outputEnabled = false;

/**
* @param string $directory
* @return void
*/
protected function setDirectory(string $directory): void
{
if (! is_dir($directory)) {
throw new RuntimeException('Invalid directory');
}
$this->directory = $directory;
}

/**
* @param array $env
* @return void
*/
protected function setEnv(array $env): void
{
foreach ($env as $key => $value) {
$this->env[$key] = $value;
}
}

/**
* @return boolean
*/
public function isTTY(): bool
{
return function_exists('posix_isatty') && posix_isatty(STDOUT);
}

/**
* Escapes a command for use
*
* @param string|array $stringOrArray
* @return string|array
*/
private function escapeCommand($stringOrArray)
{
if (is_string($stringOrArray)) {
return escapeshellcmd($stringOrArray);
}

return array_map('escapeshellarg', $stringOrArray);
}

/**
* @param string|array $stringOrArray
* @param boolean $escape
* @return void
*/
protected function setCommand($stringOrArray, bool $escape = true): void
{
if ($escape) {
$stringOrArray = $this->escapeCommand($stringOrArray);
}

$this->command = is_array($stringOrArray) ? implode(' ', $stringOrArray) : $stringOrArray;
}

/**
* @see https://www.php.net/manual/en/function.proc-open.php
*
* @param boolean $output
* @return array
*/
protected function descriptorspec(): array
{
if ($this->outputEnabled && $this->isTTY()) {
return [
['file', '/dev/tty', 'r'],
['file', '/dev/tty', 'w'],
['file', '/dev/tty', 'w'],
];
}

return [
['pipe','r'],
['pipe','w'],
['pipe','w']
];
}


/**
* Checks if the process ended successfully
*
Expand Down
60 changes: 23 additions & 37 deletions src/Process/Process.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
declare(strict_types = 1);
namespace Origin\Process;

/**
* Process
*
* @internal refactored to go through background process due to issue with getting output, cant use stream
* so you have to go through a loop, essentially recreating code in the background process
*/
class Process extends BaseProcess
{
/**
Expand All @@ -32,9 +38,12 @@ class Process extends BaseProcess
protected $exitCode = null;

/**
* @var integer|null
* Raw command
*
* @var string|array
*/
protected $timeout = null;
protected $command;
protected $options;

/**
* @param string|array $stringOrArray
Expand All @@ -43,59 +52,36 @@ class Process extends BaseProcess
* - env: an array of key values for environment variables
* - output: (bool) default if TTY is supported output will be sent to screen
* - escape: default: true escapes the command
* - timeout: set the timeout value in seconds
* @return void
*/
public function __construct($stringOrArray, array $options = [])
{
$options += [
'directory' => getcwd(),
'env' => [],
'output' => false,
'escape' => true
];

$this->setDirectory($options['directory']);
$this->setEnv((array) $options['env']);
$this->setCommand($stringOrArray, $options['escape']);

$this->outputEnabled = $options['output'];
$this->command = $stringOrArray;
$this->options = $options;
}

/**
* Executes a command
*
* @param string|array $stringOrArray
* @param array $options The following options are supported
* - directory: the directory to execute the command in, default is getcwd
* - env: an array of key values for environment variables
* - output: (bool) default if TTY is supported output will be sent to screen
* - escape: default: true escapes the command
* @return boolean
*/
public function execute(): bool
{
$this->stdout = $this->stderr = '';
$this->exitCode = null;

$process = proc_open(
$this->command, $this->descriptorspec($this->outputEnabled), $pipes, $this->directory, $this->env
);
if (! $process) {
return false;
}

$this->stdout = stream_get_contents($pipes[1]);
$this->stderr = stream_get_contents($pipes[2]);

fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
$this->exitCode = proc_close($process);
$process = new BackgroundProcess($this->command, $this->options);
$process->start();
$process->wait();

$this->stdout = $process->output();
$this->stderr = $process->error();

$this->exitCode = $process->exitCode();

return $this->exitCode === 0;
}

/**
* Gets the exit code or null if it was not run
*
Expand Down

0 comments on commit 63c9862

Please sign in to comment.