File: //usr/local/wp/php/WP_CLI/Process.php
<?php
namespace WP_CLI;
use RuntimeException;
/**
* Run a system process, and learn what happened.
*/
class Process {
/**
* @var string The full command to execute by the system.
*/
private $command;
/**
* @var string|null The path of the working directory for the process or NULL if not specified (defaults to current working directory).
*/
private $cwd;
/**
* @var array Environment variables to set when running the command.
*/
private $env;
/**
* @var array Descriptor spec for `proc_open()`.
*/
private static $descriptors = [
0 => STDIN,
1 => [ 'pipe', 'w' ],
2 => [ 'pipe', 'w' ],
];
/**
* @var bool Whether to log run time info or not.
*/
public static $log_run_times = false;
/**
* @var array Array of process run time info, keyed by process command, each a 2-element array containing run time and run count.
*/
public static $run_times = [];
/**
* @param string $command Command to execute.
* @param string|null $cwd Directory to execute the command in.
* @param array|null $env Environment variables to set when running the command.
*
* @return Process
*/
public static function create( $command, $cwd = null, $env = [] ) {
$proc = new self();
$proc->command = $command;
$proc->cwd = $cwd;
$proc->env = $env;
return $proc;
}
private function __construct() {}
/**
* Run the command.
*
* @return ProcessRun
*/
public function run() {
Utils\check_proc_available( 'Process::run' );
$start_time = microtime( true );
$pipes = [];
$proc = Utils\proc_open_compat( $this->command, self::$descriptors, $pipes, $this->cwd, $this->env );
$stdout = stream_get_contents( $pipes[1] );
fclose( $pipes[1] );
$stderr = stream_get_contents( $pipes[2] );
fclose( $pipes[2] );
$return_code = proc_close( $proc );
$run_time = microtime( true ) - $start_time;
if ( self::$log_run_times ) {
if ( ! isset( self::$run_times[ $this->command ] ) ) {
self::$run_times[ $this->command ] = [ 0, 0 ];
}
self::$run_times[ $this->command ][0] += $run_time;
++self::$run_times[ $this->command ][1];
}
return new ProcessRun(
[
'stdout' => $stdout,
'stderr' => $stderr,
'return_code' => $return_code,
'command' => $this->command,
'cwd' => $this->cwd,
'env' => $this->env,
'run_time' => $run_time,
]
);
}
/**
* Run the command, but throw an Exception on error.
*
* @return ProcessRun
*/
public function run_check() {
$r = $this->run();
if ( $r->return_code ) {
throw new RuntimeException( $r );
}
return $r;
}
/**
* Run the command, but throw an Exception on error.
* Same as `run_check()` above, but checks the correct stderr.
*
* @return ProcessRun
*/
public function run_check_stderr() {
$r = $this->run();
if ( $r->return_code ) {
throw new RuntimeException( $r );
}
if ( ! empty( $r->stderr ) ) {
// If the only thing that STDERR caught was the Requests deprecated message, ignore it.
// This is a temporary fix until we have a better solution for dealing with Requests
// as a dependency shared between WP Core and WP-CLI.
$stderr_lines = array_filter( explode( "\n", $r->stderr ) );
if ( 1 === count( $stderr_lines ) ) {
$stderr_line = $stderr_lines[0];
if (
false !== strpos(
$stderr_line,
'The PSR-0 `Requests_...` class names in the Request library are deprecated.'
)
) {
return $r;
}
}
throw new RuntimeException( $r );
}
return $r;
}
}