scratch

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 114  →  ?path2? @ 115
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/AbstractBinary.php
@@ -0,0 +1,220 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Listeners\Listeners;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Evenement\EventEmitter;
use Monolog\Logger;
use Monolog\Handler\NullHandler;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
 
abstract class AbstractBinary extends EventEmitter implements BinaryInterface
{
/** @var ConfigurationInterface */
protected $configuration;
 
/** @var ProcessBuilderFactoryInterface */
protected $factory;
 
/** @var ProcessRunner */
private $processRunner;
 
/** @var Listeners */
private $listenersManager;
 
public function __construct(ProcessBuilderFactoryInterface $factory, LoggerInterface $logger, ConfigurationInterface $configuration)
{
$this->factory = $factory;
$this->configuration = $configuration;
$this->processRunner = new ProcessRunner($logger, $this->getName());
$this->listenersManager = new Listeners();
$this->applyProcessConfiguration();
}
 
/**
* {@inheritdoc}
*/
public function listen(ListenerInterface $listener)
{
$this->listenersManager->register($listener, $this);
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function unlisten(ListenerInterface $listener)
{
$this->listenersManager->unregister($listener, $this);
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function getConfiguration()
{
return $this->configuration;
}
 
/**
* {@inheritdoc}
*
* @return BinaryInterface
*/
public function setConfiguration(ConfigurationInterface $configuration)
{
$this->configuration = $configuration;
$this->applyProcessConfiguration();
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function getProcessBuilderFactory()
{
return $this->factory;
}
 
/**
* {@inheritdoc}
*
* @return BinaryInterface
*/
public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory)
{
$this->factory = $factory;
$this->applyProcessConfiguration();
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function getProcessRunner()
{
return $this->processRunner;
}
 
/**
* {@inheritdoc}
*/
public function setProcessRunner(ProcessRunnerInterface $runner)
{
$this->processRunner = $runner;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function command($command, $bypassErrors = false, $listeners = null)
{
if (!is_array($command)) {
$command = array($command);
}
 
return $this->run($this->factory->create($command), $bypassErrors, $listeners);
}
 
/**
* {@inheritdoc}
*/
public static function load($binaries, LoggerInterface $logger = null, $configuration = array())
{
$finder = new ExecutableFinder();
$binary = null;
$binaries = is_array($binaries) ? $binaries : array($binaries);
 
foreach ($binaries as $candidate) {
if (file_exists($candidate) && is_executable($candidate)) {
$binary = $candidate;
break;
}
if (null !== $binary = $finder->find($candidate)) {
break;
}
}
 
if (null === $binary) {
throw new ExecutableNotFoundException(sprintf(
'Executable not found, proposed : %s', implode(', ', $binaries)
));
}
 
if (null === $logger) {
$logger = new Logger(__NAMESPACE__ . ' logger');
$logger->pushHandler(new NullHandler());
}
 
$configuration = $configuration instanceof ConfigurationInterface ? $configuration : new Configuration($configuration);
 
return new static(new ProcessBuilderFactory($binary), $logger, $configuration);
}
 
/**
* Returns the name of the driver
*
* @return string
*/
abstract public function getName();
 
/**
* Executes a process, logs events
*
* @param Process $process
* @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions
* @param ListenerInterface|array $listeners A listener or an array of listener to register for this unique run
*
* @return string The Process output
*
* @throws ExecutionFailureException in case of process failure.
*/
protected function run(Process $process, $bypassErrors = false, $listeners = null)
{
if (null !== $listeners) {
if (!is_array($listeners)) {
$listeners = array($listeners);
}
 
$listenersManager = clone $this->listenersManager;
 
foreach ($listeners as $listener) {
$listenersManager->register($listener, $this);
}
} else {
$listenersManager = $this->listenersManager;
}
 
return $this->processRunner->run($process, $listenersManager->storage, $bypassErrors);
}
 
private function applyProcessConfiguration()
{
if ($this->configuration->has('timeout')) {
$this->factory->setTimeout($this->configuration->get('timeout'));
}
 
return $this;
}
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryDriverTestCase.php
@@ -0,0 +1,76 @@
<?php
 
namespace Alchemy\BinaryDriver;
 
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
 
/**
* Convenient PHPUnit methods for testing BinaryDriverInterface implementations.
*/
class BinaryDriverTestCase extends \PHPUnit_Framework_TestCase
{
/**
* @return ProcessBuilderFactoryInterface
*/
public function createProcessBuilderFactoryMock()
{
return $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface');
}
 
/**
* @param integer $runs The number of runs expected
* @param Boolean $success True if the process expects to be successfull
* @param string $commandLine The commandline executed
* @param string $output The process output
* @param string $error The process error output
*
* @return Process
*/
public function createProcessMock($runs = 1, $success = true, $commandLine = null, $output = null, $error = null, $callback = false)
{
$process = $this->getMockBuilder('Symfony\Component\Process\Process')
->disableOriginalConstructor()
->getMock();
 
$builder = $process->expects($this->exactly($runs))
->method('run');
 
if (true === $callback) {
$builder->with($this->isInstanceOf('Closure'));
}
 
$process->expects($this->any())
->method('isSuccessful')
->will($this->returnValue($success));
 
foreach (array(
'getOutput' => $output,
'getErrorOutput' => $error,
'getCommandLine' => $commandLine,
) as $command => $value) {
$process
->expects($this->any())
->method($command)
->will($this->returnValue($value));
}
 
return $process;
}
 
/**
* @return LoggerInterface
*/
public function createLoggerMock()
{
return $this->getMock('Psr\Log\LoggerInterface');
}
 
/**
* @return ConfigurationInterface
*/
public function createConfigurationMock()
{
return $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface');
}
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryInterface.php
@@ -0,0 +1,67 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException;
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Alchemy\BinaryDriver\Listeners\ListenerInterface;
use Psr\Log\LoggerInterface;
use Evenement\EventEmitterInterface;
 
interface BinaryInterface extends ConfigurationAwareInterface, ProcessBuilderFactoryAwareInterface, ProcessRunnerAwareInterface, EventEmitterInterface
{
/**
* Adds a listener to the binary driver
*
* @param ListenerInterface $listener
*
* @return BinaryInterface
*/
public function listen(ListenerInterface $listener);
 
/**
* Removes a listener from the binary driver
*
* @param ListenerInterface $listener
*
* @return BinaryInterface
*/
public function unlisten(ListenerInterface $listener);
 
/**
* Runs a command against the driver.
*
* Calling this method on a `ls` driver with the command `-a` would run `ls -a`.
*
* @param array|string $command A command or an array of command
* @param Boolean $bypassErrors If set to true, an erronous process will not throw an exception
* @param ListenerInterface|array $listeners A listener or an array of listeners to register for this unique run
*
* @return string The command output
*
* @throws ExecutionFailureException in case of process failure.
*/
public function command($command, $bypassErrors = false, $listeners = null);
 
/**
* Loads a binary
*
* @param string|array $binaries A binary name or an array of binary names
* @param null|LoggerInterface $logger A Logger
* @param array|ConfigurationInterface $configuration The configuration
*
* @throws ExecutableNotFoundException In case none of the binaries were found
*
* @return BinaryInterface
*/
public static function load($binaries, LoggerInterface $logger = null, $configuration = array());
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Configuration.php
@@ -0,0 +1,107 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
class Configuration implements ConfigurationInterface
{
private $data;
 
public function __construct(array $data = array())
{
$this->data = $data;
}
 
/**
* {@inheritdoc}
*/
public function getIterator()
{
return new \ArrayIterator($this->data);
}
 
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
return isset($this->data[$key]) ? $this->data[$key] : $default;
}
 
/**
* {@inheritdoc}
*/
public function set($key, $value)
{
$this->data[$key] = $value;
 
return $this;
}
 
/**
* {@inheritdoc}
*/
public function has($key)
{
return array_key_exists($key, $this->data);
}
 
/**
* {@inheritdoc}
*/
public function remove($key)
{
$value = $this->get($key);
unset($this->data[$key]);
 
return $value;
}
 
/**
* {@inheritdoc}
*/
public function all()
{
return $this->data;
}
 
/**
* {@inheritdoc}
*/
public function offsetExists($offset)
{
return $this->has($offset);
}
 
/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
 
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value)
{
$this->set($offset, $value);
}
 
/**
* {@inheritdoc}
*/
public function offsetUnset($offset)
{
$this->remove($offset);
}
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationAwareInterface.php
@@ -0,0 +1,29 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
interface ConfigurationAwareInterface
{
/**
* Returns the configuration
*
* @return ConfigurationInterface
*/
public function getConfiguration();
 
/**
* Set the configuration
*
* @param ConfigurationInterface $configuration
*/
public function setConfiguration(ConfigurationInterface $configuration);
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationInterface.php
@@ -0,0 +1,58 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
interface ConfigurationInterface extends \ArrayAccess, \IteratorAggregate
{
/**
* Returns the value given a key from configuration
*
* @param string $key
* @param mixed $default The default value in case the key does not exist
*
* @return mixed
*/
public function get($key, $default = null);
 
/**
* Set a value to configuration
*
* @param string $key The key
* @param mixed $value The value corresponding to the key
*/
public function set($key, $value);
 
/**
* Tells if Configuration contains `$key`
*
* @param string $key
*
* @return Boolean
*/
public function has($key);
 
/**
* Removes a value given a key
*
* @param string $key
*
* @return mixed The previous value
*/
public function remove($key);
 
/**
* Returns all values set in the configuration
*
* @return array
*/
public function all();
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExceptionInterface.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver\Exception;
 
interface ExceptionInterface
{
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutableNotFoundException.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver\Exception;
 
class ExecutableNotFoundException extends \RuntimeException implements ExceptionInterface
{
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutionFailureException.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver\Exception;
 
class ExecutionFailureException extends \RuntimeException implements ExceptionInterface
{
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/InvalidArgumentException.php
@@ -0,0 +1,16 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver\Exception;
 
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/DebugListener.php
@@ -0,0 +1,58 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver\Listeners;
 
use Evenement\EventEmitter;
use Symfony\Component\Process\Process;
 
class DebugListener extends EventEmitter implements ListenerInterface
{
private $prefixOut;
private $prefixErr;
private $eventOut;
private $eventErr;
 
public function __construct($prefixOut = '[OUT] ', $prefixErr = '[ERROR] ', $eventOut = 'debug', $eventErr = 'debug')
{
$this->prefixOut = $prefixOut;
$this->prefixErr = $prefixErr;
$this->eventOut = $eventOut;
$this->eventErr = $eventErr;
}
 
/**
* {@inheritdoc}
*/
public function handle($type, $data)
{
if (Process::ERR === $type) {
$this->emitLines($this->eventErr, $this->prefixErr, $data);
} elseif (Process::OUT === $type) {
$this->emitLines($this->eventOut, $this->prefixOut, $data);
}
}
 
/**
* {@inheritdoc}
*/
public function forwardedEvents()
{
return array_unique(array($this->eventErr, $this->eventOut));
}
 
private function emitLines($event, $prefix, $lines)
{
foreach (explode("\n", $lines) as $line) {
$this->emit($event, array($prefix . $line));
}
}
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/ListenerInterface.php
@@ -0,0 +1,32 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver\Listeners;
 
use Evenement\EventEmitterInterface;
 
interface ListenerInterface extends EventEmitterInterface
{
/**
* Handle the output of a ProcessRunner
*
* @param string $type The data type, one of Process::ERR, Process::OUT constants
* @param string $data The output
*/
public function handle($type, $data);
 
/**
* An array of events that should be forwarded to BinaryInterface
*
* @return array
*/
public function forwardedEvents();
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/Listeners.php
@@ -0,0 +1,88 @@
<?php
 
namespace Alchemy\BinaryDriver\Listeners;
 
use SplObjectStorage;
use Evenement\EventEmitter;
 
class Listeners extends EventEmitter
{
/** @var SplObjectStorage */
public $storage;
 
public function __construct()
{
$this->storage = new SplObjectStorage();
}
 
public function __clone()
{
$storage = $this->storage;
$this->storage = new SplObjectStorage();
$this->storage->addAll($storage);
}
 
/**
* Registers a listener, pass the listener events to the target.
*
* @param ListenerInterface $listener
* @param null|EventEmitter $target
*
* @return ListenersInterface
*/
public function register(ListenerInterface $listener, EventEmitter $target = null)
{
$EElisteners = array();
 
if (null !== $target) {
$EElisteners = $this->forwardEvents($listener, $target, $listener->forwardedEvents());
}
 
$this->storage->attach($listener, $EElisteners);
 
return $this;
}
 
/**
* Unregisters a listener, removes the listener events from the target.
*
* @param ListenerInterface $listener
*
* @return ListenersInterface
*
* @throws InvalidArgumentException In case the listener is not registered
*/
public function unregister(ListenerInterface $listener)
{
if (!isset($this->storage[$listener])) {
throw new InvalidArgumentException('Listener is not registered.');
}
 
foreach ($this->storage[$listener] as $event => $EElistener) {
$listener->removeListener($event, $EElistener);
}
 
$this->storage->detach($listener);
 
return $this;
}
 
private function forwardEvents($source, $target, array $events)
{
$EElisteners = array();
 
foreach ($events as $event) {
$listener = $this->createListener($event, $target);
$source->on($event, $EElisteners[$event] = $listener);
}
 
return $EElisteners;
}
 
private function createListener($event, $target)
{
return function () use ($event, $target) {
$target->emit($event, func_get_args());
};
}
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactory.php
@@ -0,0 +1,177 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
use Symfony\Component\Process\ProcessBuilder;
 
class ProcessBuilderFactory implements ProcessBuilderFactoryInterface
{
/**
* The binary path
*
* @var String
*/
protected $binary;
 
/**
* The timeout for the generated processes
*
* @var integer|float
*/
private $timeout;
 
/**
* An internal ProcessBuilder.
*
* Note that this one is used only if Symfony ProcessBuilder has method
* setPrefix (2.3)
*
* @var ProcessBuilder
*/
private $builder;
 
/**
* Tells whether Symfony LTS ProcessBuilder should be emulated or not.
*
* This symfony version provided a brand new ::setPrefix method.
*
* @var Boolean
*/
public static $emulateSfLTS;
 
/**
* Constructor
*
* @param String $binary The path to the binary
*
* @throws InvalidArgumentException In case binary path is invalid
*/
public function __construct($binary)
{
$this->detectEmulation();
 
if (!self::$emulateSfLTS) {
$this->builder = new ProcessBuilder();
}
 
$this->useBinary($binary);
}
 
/**
* Covenient method for unit testing
*
* @return type
*/
public function getBuilder()
{
return $this->builder;
}
 
/**
* Covenient method for unit testing
*
* @param ProcessBuilder $builder
* @return ProcessBuilderFactory
*/
public function setBuilder(ProcessBuilder $builder)
{
$this->builder = $builder;
 
return $this;
}
 
/**
* @inheritdoc
*/
public function getBinary()
{
return $this->binary;
}
 
/**
* @inheritdoc
*/
public function useBinary($binary)
{
if (!is_executable($binary)) {
throw new InvalidArgumentException(sprintf('`%s` is not an executable binary', $binary));
}
 
$this->binary = $binary;
 
if (!static::$emulateSfLTS) {
$this->builder->setPrefix($binary);
}
 
return $this;
}
 
/**
* @inheritdoc
*/
public function setTimeout($timeout)
{
$this->timeout = $timeout;
 
if (!static::$emulateSfLTS) {
$this->builder->setTimeout($this->timeout);
}
 
return $this;
}
 
/**
* @inheritdoc
*/
public function getTimeout()
{
return $this->timeout;
}
 
/**
* @inheritdoc
*/
public function create($arguments = array())
{
if (null === $this->binary) {
throw new InvalidArgumentException('No binary set');
}
 
if (!is_array($arguments)) {
$arguments = array($arguments);
}
 
if (static::$emulateSfLTS) {
array_unshift($arguments, $this->binary);
 
return ProcessBuilder::create($arguments)
->setTimeout($this->timeout)
->getProcess();
} else {
return $this->builder
->setArguments($arguments)
->getProcess();
}
}
 
private function detectEmulation()
{
if (null !== static::$emulateSfLTS) {
return $this;
}
 
static::$emulateSfLTS = !method_exists('Symfony\Component\Process\ProcessBuilder', 'setPrefix');
 
return $this;
}
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryAwareInterface.php
@@ -0,0 +1,29 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
interface ProcessBuilderFactoryAwareInterface
{
/**
* Returns the current process builder factory
*
* @return ProcessBuilderFactoryInterface
*/
public function getProcessBuilderFactory();
 
/**
* Set a process builder factory
*
* @param ProcessBuilderFactoryInterface $factory
*/
public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory);
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryInterface.php
@@ -0,0 +1,65 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
use Symfony\Component\Process\Process;
 
interface ProcessBuilderFactoryInterface
{
/**
* Returns a new instance of Symfony Process
*
* @param string|array $arguments An argument or an array of arguments
*
* @return Process
*
* @throws InvalidArgumentException
*/
public function create($arguments = array());
 
/**
* Returns the path to the binary that is used
*
* @return String
*/
public function getBinary();
 
/**
* Sets the path to the binary
*
* @param String $binary A path to a binary
*
* @return ProcessBuilderFactoryInterface
*
* @throws InvalidArgumentException In case binary is not executable
*/
public function useBinary($binary);
 
/**
* Set the default timeout to apply on created processes.
*
* @param integer|float $timeout
*
* @return ProcessBuilderFactoryInterface
*
* @throws InvalidArgumentException In case the timeout is not valid
*/
public function setTimeout($timeout);
 
/**
* Returns the current timeout applied to the created processes.
*
* @return integer|float
*/
public function getTimeout();
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunner.php
@@ -0,0 +1,104 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Psr\Log\LoggerInterface;
use SplObjectStorage;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;
 
class ProcessRunner implements ProcessRunnerInterface
{
/** @var LoggerInterface */
private $logger;
 
/** @var string */
private $name;
 
public function __construct(LoggerInterface $logger, $name)
{
$this->logger = $logger;
$this->name = $name;
}
 
/**
* {@inheritdoc}
*
* @return ProcessRunner
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
 
return $this;
}
 
/**
* @return LoggerInterface
*/
public function getLogger()
{
return $this->logger;
}
 
/**
* {@inheritdoc}
*/
public function run(Process $process, SplObjectStorage $listeners, $bypassErrors)
{
$this->logger->info(sprintf(
'%s running command %s', $this->name, $process->getCommandLine()
));
 
try {
$process->run($this->buildCallback($listeners));
} catch (RuntimeException $e) {
if (!$bypassErrors) {
$this->doExecutionFailure($process->getCommandLine(), $e);
}
}
 
if (!$bypassErrors && !$process->isSuccessful()) {
$this->doExecutionFailure($process->getCommandLine());
} elseif (!$process->isSuccessful()) {
$this->logger->error(sprintf(
'%s failed to execute command %s', $this->name, $process->getCommandLine()
));
 
return;
} else {
$this->logger->info(sprintf('%s executed command successfully', $this->name));
 
return $process->getOutput();
}
}
 
private function buildCallback(SplObjectStorage $listeners)
{
return function ($type, $data) use ($listeners) {
foreach ($listeners as $listener) {
$listener->handle($type, $data);
}
};
}
 
private function doExecutionFailure($command, \Exception $e = null)
{
$this->logger->error(sprintf(
'%s failed to execute command %s', $this->name, $command
));
throw new ExecutionFailureException(sprintf(
'%s failed to execute command %s', $this->name, $command
), $e ? $e->getCode() : null, $e ?: null);
}
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerAwareInterface.php
@@ -0,0 +1,29 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
interface ProcessRunnerAwareInterface
{
/**
* Returns the current process runner
*
* @return ProcessRunnerInterface
*/
public function getProcessRunner();
 
/**
* Sets a process runner
*
* @param ProcessRunnerInterface $runner
*/
public function setProcessRunner(ProcessRunnerInterface $runner);
}
/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerInterface.php
@@ -0,0 +1,33 @@
<?php
 
/*
* This file is part of Alchemy\BinaryDriver.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
 
namespace Alchemy\BinaryDriver;
 
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
use Psr\Log\LoggerAwareInterface;
use SplObjectStorage;
use Symfony\Component\Process\Process;
 
interface ProcessRunnerInterface extends LoggerAwareInterface
{
/**
* Executes a process, logs events
*
* @param Process $process
* @param SplObjectStorage $listeners Some listeners
* @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions
*
* @return string The Process output
*
* @throws ExecutionFailureException in case of process failure.
*/
public function run(Process $process, SplObjectStorage $listeners, $bypassErrors);
}