Add pear modules, mail and net_smtp via composer (#93)
Add pear modules, mail and net_smtp via composer, remove php 5.6 build due to phpunit 6
This commit is contained in:
+19
-2
@@ -3,8 +3,6 @@ namespace Robo;
|
||||
|
||||
use Symfony\Component\Console\Application as SymfonyApplication;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class Application extends SymfonyApplication
|
||||
@@ -25,6 +23,11 @@ class Application extends SymfonyApplication
|
||||
->addOption(
|
||||
new InputOption('--progress-delay', null, InputOption::VALUE_REQUIRED, 'Number of seconds before progress bar is displayed in long-running task collections. Default: 2s.', Config::DEFAULT_PROGRESS_DELAY)
|
||||
);
|
||||
|
||||
$this->getDefinition()
|
||||
->addOption(
|
||||
new InputOption('--define', '-D', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Define a configuration item value.', [])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,4 +56,18 @@ class Application extends SymfonyApplication
|
||||
});
|
||||
$this->add($createRoboFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add self update command, do nothing if null is provided
|
||||
*
|
||||
* @param string $repository GitHub Repository for self update
|
||||
*/
|
||||
public function addSelfUpdateCommand($repository = null)
|
||||
{
|
||||
if (!$repository) {
|
||||
return;
|
||||
}
|
||||
$selfUpdateCommand = new SelfUpdateCommand($this->getName(), $this->getVersion(), $repository);
|
||||
$this->add($selfUpdateCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ namespace Robo\Collection;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Collection\Collection;
|
||||
use Robo\State\StateAwareInterface;
|
||||
use Robo\State\Data;
|
||||
|
||||
/**
|
||||
* Creates a task wrapper that converts any Callable into an
|
||||
@@ -35,7 +36,7 @@ class CallableTask implements TaskInterface
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$result = call_user_func($this->fn);
|
||||
$result = call_user_func($this->fn, $this->getState());
|
||||
// If the function returns no result, then count it
|
||||
// as a success.
|
||||
if (!isset($result)) {
|
||||
@@ -50,4 +51,12 @@ class CallableTask implements TaskInterface
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
if ($this->reference instanceof StateAwareInterface) {
|
||||
return $this->reference->getState();
|
||||
}
|
||||
return new Data();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\State\Data;
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Task\StackBasedTask;
|
||||
@@ -12,9 +13,9 @@ use Robo\Exception\TaskException;
|
||||
use Robo\Exception\TaskExitException;
|
||||
use Robo\Contract\CommandInterface;
|
||||
|
||||
|
||||
use Robo\Common\ProgressIndicatorAwareTrait;
|
||||
use Robo\Contract\InflectionInterface;
|
||||
use Robo\State\StateAwareInterface;
|
||||
use Robo\State\StateAwareTrait;
|
||||
|
||||
/**
|
||||
* Group tasks into a collection that run together. Supports
|
||||
@@ -30,8 +31,10 @@ use Robo\Contract\InflectionInterface;
|
||||
* called. Here, taskDeleteDir is used to remove partial results
|
||||
* of an unfinished task.
|
||||
*/
|
||||
class Collection extends BaseTask implements CollectionInterface, CommandInterface
|
||||
class Collection extends BaseTask implements CollectionInterface, CommandInterface, StateAwareInterface
|
||||
{
|
||||
use StateAwareTrait;
|
||||
|
||||
/**
|
||||
* @var \Robo\Collection\Element[]
|
||||
*/
|
||||
@@ -52,11 +55,22 @@ class Collection extends BaseTask implements CollectionInterface, CommandInterfa
|
||||
*/
|
||||
protected $parentCollection;
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $deferredCallbacks = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $messageStoreKeys = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->resetState();
|
||||
}
|
||||
|
||||
public function setProgressBarAutoDisplayInterval($interval)
|
||||
@@ -165,6 +179,7 @@ class Collection extends BaseTask implements CollectionInterface, CommandInterfa
|
||||
$context += TaskInfo::getTaskContext($this);
|
||||
return $this->addCode(
|
||||
function () use ($level, $text, $context) {
|
||||
$context += $this->getState()->getData();
|
||||
$this->printTaskOutput($level, $text, $context);
|
||||
}
|
||||
);
|
||||
@@ -552,6 +567,8 @@ class Collection extends BaseTask implements CollectionInterface, CommandInterfa
|
||||
// the incremental results, if they wish.
|
||||
$key = Result::isUnnamed($taskName) ? $name : $taskName;
|
||||
$result->accumulate($key, $taskResult);
|
||||
// The result message will be the message of the last task executed.
|
||||
$result->setMessage($taskResult->getMessage());
|
||||
}
|
||||
} catch (TaskExitException $exitException) {
|
||||
$this->fail();
|
||||
@@ -632,10 +649,79 @@ class Collection extends BaseTask implements CollectionInterface, CommandInterfa
|
||||
if ($original instanceof InflectionInterface) {
|
||||
$original->inflect($this);
|
||||
}
|
||||
if ($original instanceof StateAwareInterface) {
|
||||
$original->setState($this->getState());
|
||||
}
|
||||
$this->doDeferredInitialization($original);
|
||||
$taskResult = $task->run();
|
||||
$taskResult = Result::ensureResult($task, $taskResult);
|
||||
$this->doStateUpdates($original, $taskResult);
|
||||
return $taskResult;
|
||||
}
|
||||
|
||||
protected function doStateUpdates($task, Data $taskResult)
|
||||
{
|
||||
$this->updateState($taskResult);
|
||||
$key = spl_object_hash($task);
|
||||
if (array_key_exists($key, $this->messageStoreKeys)) {
|
||||
$state = $this->getState();
|
||||
list($stateKey, $sourceKey) = $this->messageStoreKeys[$key];
|
||||
$value = empty($sourceKey) ? $taskResult->getMessage() : $taskResult[$sourceKey];
|
||||
$state[$stateKey] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function storeState($task, $key, $source = '')
|
||||
{
|
||||
$this->messageStoreKeys[spl_object_hash($task)] = [$key, $source];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function deferTaskConfiguration($task, $functionName, $stateKey)
|
||||
{
|
||||
return $this->defer(
|
||||
$task,
|
||||
function ($task, $state) use ($functionName, $stateKey) {
|
||||
$fn = [$task, $functionName];
|
||||
$value = $state[$stateKey];
|
||||
$fn($value);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defer execution of a callback function until just before a task
|
||||
* runs. Use this time to provide more settings for the task, e.g. from
|
||||
* the collection's shared state, which is populated with the results
|
||||
* of previous test runs.
|
||||
*/
|
||||
public function defer($task, $callback)
|
||||
{
|
||||
$this->deferredCallbacks[spl_object_hash($task)][] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function doDeferredInitialization($task)
|
||||
{
|
||||
// If the task is a state consumer, then call its receiveState method
|
||||
if ($task instanceof \Robo\State\Consumer) {
|
||||
$task->receiveState($this->getState());
|
||||
}
|
||||
|
||||
// Check and see if there are any deferred callbacks for this task.
|
||||
$key = spl_object_hash($task);
|
||||
if (!array_key_exists($key, $this->deferredCallbacks)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Call all of the deferred callbacks
|
||||
foreach ($this->deferredCallbacks[$key] as $fn) {
|
||||
$fn($task, $this->getState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaskInterface|NestedCollectionInterface|WrappedTaskInterface $task
|
||||
* @param $parentCollection
|
||||
|
||||
+111
-15
@@ -1,26 +1,22 @@
|
||||
<?php
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Guzzle\Inflection\InflectorInterface;
|
||||
use Robo\Config;
|
||||
use Robo\Common\Timer;
|
||||
use Consolidation\Config\Inject\ConfigForSetters;
|
||||
use Robo\Config\Config;
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\InflectionInterface;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\CompletionInterface;
|
||||
use Robo\Contract\WrappedTaskInterface;
|
||||
use Robo\Collection\NestedCollectionInterface;
|
||||
use Robo\LoadAllTasks;
|
||||
use Robo\Task\Simulator;
|
||||
use Robo\Collection\CompletionWrapper;
|
||||
use Robo\Collection\Temporary;
|
||||
use Robo\Contract\ConfigAwareInterface;
|
||||
use Robo\Common\ConfigAwareTrait;
|
||||
use ReflectionClass;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Robo\State\StateAwareInterface;
|
||||
use Robo\State\StateAwareTrait;
|
||||
use Robo\Result;
|
||||
|
||||
/**
|
||||
* Creates a collection, and adds tasks to it. The collection builder
|
||||
@@ -49,8 +45,10 @@ use Robo\Exception\TaskException;
|
||||
* In the example above, the `taskDeleteDir` will be called if
|
||||
* ```
|
||||
*/
|
||||
class CollectionBuilder extends BaseTask implements NestedCollectionInterface, WrappedTaskInterface, CommandInterface
|
||||
class CollectionBuilder extends BaseTask implements NestedCollectionInterface, WrappedTaskInterface, CommandInterface, StateAwareInterface
|
||||
{
|
||||
use StateAwareTrait;
|
||||
|
||||
/**
|
||||
* @var \Robo\Tasks
|
||||
*/
|
||||
@@ -77,6 +75,19 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
public function __construct($commandFile)
|
||||
{
|
||||
$this->commandFile = $commandFile;
|
||||
$this->resetState();
|
||||
}
|
||||
|
||||
public static function create($container, $commandFile)
|
||||
{
|
||||
$builder = new self($commandFile);
|
||||
|
||||
$builder->setLogger($container->get('logger'));
|
||||
$builder->setProgressIndicator($container->get('progressIndicator'));
|
||||
$builder->setConfig($container->get('config'));
|
||||
$builder->setOutputAdapter($container->get('outputAdapter'));
|
||||
|
||||
return $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,9 +158,18 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addCode(callable $code)
|
||||
/**
|
||||
* Add arbitrary code to execute as a task.
|
||||
*
|
||||
* @see \Robo\Collection\CollectionInterface::addCode
|
||||
*
|
||||
* @param callable $code
|
||||
* @param int|string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function addCode(callable $code, $name = \Robo\Collection\CollectionInterface::UNNAMEDTASK)
|
||||
{
|
||||
$this->getCollection()->addCode($code);
|
||||
$this->getCollection()->addCode($code, $name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -245,6 +265,51 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
$collection = $this->getCollection();
|
||||
return $collection->getState();
|
||||
}
|
||||
|
||||
public function storeState($key, $source = '')
|
||||
{
|
||||
return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
public function deferTaskConfiguration($functionName, $stateKey)
|
||||
{
|
||||
return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
public function defer($callback)
|
||||
{
|
||||
return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
protected function callCollectionStateFuntion($functionName, $args)
|
||||
{
|
||||
$currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask;
|
||||
|
||||
array_unshift($args, $currentTask);
|
||||
$collection = $this->getCollection();
|
||||
$fn = [$collection, $functionName];
|
||||
|
||||
call_user_func_array($fn, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setVerbosityThreshold($verbosityThreshold)
|
||||
{
|
||||
$currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask;
|
||||
if ($currentTask) {
|
||||
$currentTask->setVerbosityThreshold($verbosityThreshold);
|
||||
return $this;
|
||||
}
|
||||
parent::setVerbosityThreshold($verbosityThreshold);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the current task for this collection builder.
|
||||
* TODO: Not needed?
|
||||
@@ -266,6 +331,9 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
$collectionBuilder = new self($this->commandFile);
|
||||
$collectionBuilder->inflect($this);
|
||||
$collectionBuilder->simulated($this->isSimulated());
|
||||
$collectionBuilder->setVerbosityThreshold($this->verbosityThreshold());
|
||||
$collectionBuilder->setState($this->getState());
|
||||
|
||||
return $collectionBuilder;
|
||||
}
|
||||
|
||||
@@ -355,6 +423,7 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
throw new RuntimeException("Can not construct task $name");
|
||||
}
|
||||
$task = $this->fixTask($task, $args);
|
||||
$this->configureTask($name, $task);
|
||||
return $this->addTaskToCollection($task);
|
||||
}
|
||||
|
||||
@@ -366,10 +435,15 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
*/
|
||||
protected function fixTask($task, $args)
|
||||
{
|
||||
$task->inflect($this);
|
||||
if ($task instanceof InflectionInterface) {
|
||||
$task->inflect($this);
|
||||
}
|
||||
if ($task instanceof BuilderAwareInterface) {
|
||||
$task->setBuilder($this);
|
||||
}
|
||||
if ($task instanceof VerbosityThresholdInterface) {
|
||||
$task->setVerbosityThreshold($this->verbosityThreshold());
|
||||
}
|
||||
|
||||
// Do not wrap our wrappers.
|
||||
if ($task instanceof CompletionWrapper || $task instanceof Simulator) {
|
||||
@@ -402,6 +476,25 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if there are any setter methods defined in configuration
|
||||
* for this task.
|
||||
*/
|
||||
protected function configureTask($taskClass, $task)
|
||||
{
|
||||
$taskClass = static::configClassIdentifier($taskClass);
|
||||
$configurationApplier = new ConfigForSetters($this->getConfig(), $taskClass, 'task.');
|
||||
$configurationApplier->apply($task, 'settings');
|
||||
|
||||
// TODO: If we counted each instance of $taskClass that was called from
|
||||
// this builder, then we could also apply configuration from
|
||||
// "task.{$taskClass}[$N].settings"
|
||||
|
||||
// TODO: If the builder knew what the current command name was,
|
||||
// then we could also search for task configuration under
|
||||
// command-specific keys such as "command.{$commandname}.task.{$taskClass}.settings".
|
||||
}
|
||||
|
||||
/**
|
||||
* When we run the collection builder, run everything in the collection.
|
||||
*
|
||||
@@ -413,6 +506,7 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
$result = $this->runTasks();
|
||||
$this->stopTimer();
|
||||
$result['time'] = $this->getExecutionTime();
|
||||
$result->mergeData($this->getState()->getData());
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -425,7 +519,8 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
protected function runTasks()
|
||||
{
|
||||
if (!$this->collection && $this->currentTask) {
|
||||
return $this->currentTask->run();
|
||||
$result = $this->currentTask->run();
|
||||
return Result::ensureResult($this->currentTask, $result);
|
||||
}
|
||||
return $this->getCollection()->run();
|
||||
}
|
||||
@@ -464,6 +559,7 @@ class CollectionBuilder extends BaseTask implements NestedCollectionInterface, W
|
||||
if (!isset($this->collection)) {
|
||||
$this->collection = new Collection();
|
||||
$this->collection->inflect($this);
|
||||
$this->collection->setState($this->getState());
|
||||
$this->collection->setProgressBarAutoDisplayInterval($this->getConfig()->get(Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL));
|
||||
|
||||
if (isset($this->currentTask)) {
|
||||
|
||||
+2
-1
@@ -141,7 +141,8 @@ interface CollectionInterface extends NestedCollectionInterface
|
||||
* message will not be printed.
|
||||
*
|
||||
* @param string $text Message to print.
|
||||
* @param array $context Extra context data for use by the logger.
|
||||
* @param array $context Extra context data for use by the logger. Note
|
||||
* that the data from the collection state is merged with the provided context.
|
||||
* @param \Psr\Log\LogLevel|string $level The log level to print the information at. Default is NOTICE.
|
||||
*
|
||||
* @return $this
|
||||
|
||||
-3
@@ -1,9 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\TaskInterface;
|
||||
|
||||
interface NestedCollectionInterface
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?php
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Collection\NestedCollectionInterface;
|
||||
use Robo\Result;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Common\BuilderAwareTrait;
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Contract\TaskInterface;
|
||||
|
||||
/**
|
||||
* The temporary collection keeps track of the global collection of
|
||||
* temporary cleanup tasks in instances where temporary-generating
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Robo;
|
||||
use Robo\Collection\CollectionBuilder;
|
||||
|
||||
trait BuilderAwareTrait
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace Robo\Common;
|
||||
|
||||
use Symfony\Component\Process\ProcessUtils;
|
||||
use Robo\Common\ProcessUtils;
|
||||
|
||||
/**
|
||||
* Use this to add arguments and options to the $arguments property.
|
||||
@@ -46,10 +46,14 @@ trait CommandArguments
|
||||
* Pass the provided string in its raw (as provided) form as an argument to executable.
|
||||
*
|
||||
* @param string $arg
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function rawArg($arg)
|
||||
{
|
||||
$this->arguments .= " $arg";
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,36 +78,51 @@ trait CommandArguments
|
||||
*
|
||||
* @param string $option
|
||||
* @param string $value
|
||||
* @param string $separator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function option($option, $value = null)
|
||||
public function option($option, $value = null, $separator = ' ')
|
||||
{
|
||||
if ($option !== null and strpos($option, '-') !== 0) {
|
||||
$option = "--$option";
|
||||
}
|
||||
$this->arguments .= null == $option ? '' : " " . $option;
|
||||
$this->arguments .= null == $value ? '' : " " . static::escape($value);
|
||||
$this->arguments .= null == $value ? '' : $separator . static::escape($value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass multiple options to executable. Value can be a string or array.
|
||||
* Pass multiple options to executable. The associative array contains
|
||||
* the key:value pairs that become `--key value`, for each item in the array.
|
||||
* Values are automatically escaped.
|
||||
*/
|
||||
public function options(array $options, $separator = ' ')
|
||||
{
|
||||
foreach ($options as $option => $value) {
|
||||
$this->option($option, $value, $separator);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass an option with multiple values to executable. Value can be a string or array.
|
||||
* Option values are automatically escaped.
|
||||
*
|
||||
* @param string $option
|
||||
* @param string|array $value
|
||||
* @param string $separator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function optionList($option, $value = array())
|
||||
public function optionList($option, $value = array(), $separator = ' ')
|
||||
{
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
$this->optionList($option, $item);
|
||||
$this->optionList($option, $item, $separator);
|
||||
}
|
||||
} else {
|
||||
$this->option($option, $value);
|
||||
$this->option($option, $value, $separator);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
@@ -3,25 +3,25 @@
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Robo;
|
||||
use Robo\Config;
|
||||
use Consolidation\Config\ConfigInterface;
|
||||
|
||||
trait ConfigAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \Robo\Config
|
||||
* @var ConfigInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Set the config management object.
|
||||
*
|
||||
* @param \Robo\Config $config
|
||||
* @param ConfigInterface $config
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @see \Robo\Contract\ConfigAwareInterface::setConfig()
|
||||
*/
|
||||
public function setConfig(Config $config)
|
||||
public function setConfig(ConfigInterface $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
@@ -31,7 +31,7 @@ trait ConfigAwareTrait
|
||||
/**
|
||||
* Get the config management object.
|
||||
*
|
||||
* @return \Robo\Config
|
||||
* @return ConfigInterface
|
||||
*
|
||||
* @see \Robo\Contract\ConfigAwareInterface::getConfig()
|
||||
*/
|
||||
@@ -40,6 +40,32 @@ trait ConfigAwareTrait
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Any class that uses ConfigAwareTrait SHOULD override this method
|
||||
* , and define a prefix for its configuration items. This is usually
|
||||
* done in a base class. When used, this method should return a string
|
||||
* that ends with a "."; see BaseTask::configPrefix().
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function configPrefix()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function configClassIdentifier($classname)
|
||||
{
|
||||
$configIdentifier = strtr($classname, '\\', '.');
|
||||
$configIdentifier = preg_replace('#^(.*\.Task\.|\.)#', '', $configIdentifier);
|
||||
|
||||
return $configIdentifier;
|
||||
}
|
||||
|
||||
protected static function configPostfix()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
@@ -47,18 +73,24 @@ trait ConfigAwareTrait
|
||||
*/
|
||||
private static function getClassKey($key)
|
||||
{
|
||||
return sprintf('%s.%s', get_called_class(), $key);
|
||||
$configPrefix = static::configPrefix(); // task.
|
||||
$configClass = static::configClassIdentifier(get_called_class()); // PARTIAL_NAMESPACE.CLASSNAME
|
||||
$configPostFix = static::configPostfix(); // .settings
|
||||
|
||||
return sprintf('%s%s%s.%s', $configPrefix, $configClass, $configPostFix, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @deprecated
|
||||
* @param Config|null $config
|
||||
*/
|
||||
public static function configure($key, $value)
|
||||
public static function configure($key, $value, $config = null)
|
||||
{
|
||||
Robo::config()->set(static::getClassKey($key), $value);
|
||||
if (!$config) {
|
||||
$config = Robo::config();
|
||||
}
|
||||
$config->setDefault(static::getClassKey($key), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,15 +11,7 @@ use Symfony\Component\Process\Process;
|
||||
*/
|
||||
trait ExecCommand
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isPrinted = true;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $workingDirectory;
|
||||
use ExecTrait;
|
||||
|
||||
/**
|
||||
* @var \Robo\Common\TimeKeeper
|
||||
@@ -37,45 +29,6 @@ trait ExecCommand
|
||||
return $this->execTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is command printing its output to screen
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getPrinted()
|
||||
{
|
||||
return $this->isPrinted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes working directory of command
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function dir($dir)
|
||||
{
|
||||
$this->workingDirectory = $dir;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should command output be printed
|
||||
*
|
||||
* @param bool $arg
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function printed($arg)
|
||||
{
|
||||
if (is_bool($arg)) {
|
||||
$this->isPrinted = $arg;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a "{$cmd}.phar" in the current working
|
||||
* directory; return a string to exec it if it is
|
||||
@@ -135,7 +88,8 @@ trait ExecCommand
|
||||
*/
|
||||
protected function findProjectBin()
|
||||
{
|
||||
$candidates = [ __DIR__ . '/../../vendor/bin', __DIR__ . '/../../bin' ];
|
||||
$cwd = getcwd();
|
||||
$candidates = [ __DIR__ . '/../../vendor/bin', __DIR__ . '/../../bin', $cwd . '/vendor/bin' ];
|
||||
|
||||
// If this project is inside a vendor directory, give highest priority
|
||||
// to that directory.
|
||||
@@ -170,6 +124,11 @@ trait ExecCommand
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
protected function getCommandDescription()
|
||||
{
|
||||
return $this->process->getCommandLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $command
|
||||
*
|
||||
@@ -177,21 +136,13 @@ trait ExecCommand
|
||||
*/
|
||||
protected function executeCommand($command)
|
||||
{
|
||||
$process = new Process($command);
|
||||
$process->setTimeout(null);
|
||||
if ($this->workingDirectory) {
|
||||
$process->setWorkingDirectory($this->workingDirectory);
|
||||
}
|
||||
$this->getExecTimer()->start();
|
||||
if ($this->isPrinted) {
|
||||
$process->run(function ($type, $buffer) {
|
||||
print $buffer;
|
||||
});
|
||||
} else {
|
||||
$process->run();
|
||||
}
|
||||
$this->getExecTimer()->stop();
|
||||
|
||||
return new Result($this, $process->getExitCode(), $process->getOutput(), ['time' => $this->getExecTimer()->elapsed()]);
|
||||
// TODO: Symfony 4 requires that we supply the working directory.
|
||||
$result_data = $this->execute(new Process($command, getcwd()));
|
||||
return new Result(
|
||||
$this,
|
||||
$result_data->getExitCode(),
|
||||
$result_data->getMessage(),
|
||||
$result_data->getData()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\ResultData;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Class ExecTrait
|
||||
* @package Robo\Common
|
||||
*/
|
||||
trait ExecTrait
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $background = false;
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $timeout = null;
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $idleTimeout = null;
|
||||
|
||||
/**
|
||||
* @var null|array
|
||||
*/
|
||||
protected $env = null;
|
||||
|
||||
/**
|
||||
* @var Process
|
||||
*/
|
||||
protected $process;
|
||||
|
||||
/**
|
||||
* @var resource|string
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $interactive = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isPrinted = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isMetadataPrinted = true;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $workingDirectory;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getCommandDescription();
|
||||
|
||||
/** Typically provided by Timer trait via ProgressIndicatorAwareTrait. */
|
||||
abstract public function startTimer();
|
||||
abstract public function stopTimer();
|
||||
abstract public function getExecutionTime();
|
||||
|
||||
/**
|
||||
* Typically provided by TaskIO Trait.
|
||||
*/
|
||||
abstract public function hideTaskProgress();
|
||||
abstract public function showTaskProgress($inProgress);
|
||||
abstract public function printTaskInfo($text, $context = null);
|
||||
|
||||
/**
|
||||
* Typically provided by VerbosityThresholdTrait.
|
||||
*/
|
||||
abstract public function verbosityMeetsThreshold();
|
||||
abstract public function writeMessage($message);
|
||||
|
||||
/**
|
||||
* Sets $this->interactive() based on posix_isatty().
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function detectInteractive()
|
||||
{
|
||||
// If the caller did not explicity set the 'interactive' mode,
|
||||
// and output should be produced by this task (verbosityMeetsThreshold),
|
||||
// then we will automatically set interactive mode based on whether
|
||||
// or not output was redirected when robo was executed.
|
||||
if (!isset($this->interactive) && function_exists('posix_isatty') && $this->verbosityMeetsThreshold()) {
|
||||
$this->interactive = posix_isatty(STDOUT);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes command in background mode (asynchronously)
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function background($arg = true)
|
||||
{
|
||||
$this->background = $arg;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop command if it runs longer then $timeout in seconds
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function timeout($timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops command if it does not output something for a while
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function idleTimeout($timeout)
|
||||
{
|
||||
$this->idleTimeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single environment variable, or multiple.
|
||||
*/
|
||||
public function env($env, $value = null)
|
||||
{
|
||||
if (!is_array($env)) {
|
||||
$env = [$env => ($value ? $value : true)];
|
||||
}
|
||||
return $this->envVars($env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the environment variables for the command
|
||||
*
|
||||
* @param array $env
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function envVars(array $env)
|
||||
{
|
||||
$this->env = $env;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass an input to the process. Can be resource created with fopen() or string
|
||||
*
|
||||
* @param resource|string $input
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
$this->input = $input;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach tty to process for interactive input
|
||||
*
|
||||
* @param $interactive bool
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function interactive($interactive = true)
|
||||
{
|
||||
$this->interactive = $interactive;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is command printing its output to screen
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getPrinted()
|
||||
{
|
||||
return $this->isPrinted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes working directory of command
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function dir($dir)
|
||||
{
|
||||
$this->workingDirectory = $dir;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for setting isPrinted() and isMetadataPrinted() to false.
|
||||
*
|
||||
* @param bool $arg
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function silent($arg)
|
||||
{
|
||||
if (is_bool($arg)) {
|
||||
$this->isPrinted = !$arg;
|
||||
$this->isMetadataPrinted = !$arg;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should command output be printed
|
||||
*
|
||||
* @param bool $arg
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function printed($arg)
|
||||
{
|
||||
$this->logger->warning("printed() is deprecated. Please use printOutput().");
|
||||
return $this->printOutput($arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should command output be printed
|
||||
*
|
||||
* @param bool $arg
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function printOutput($arg)
|
||||
{
|
||||
if (is_bool($arg)) {
|
||||
$this->isPrinted = $arg;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should command metadata be printed. I,e., command and timer.
|
||||
*
|
||||
* @param bool $arg
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function printMetadata($arg)
|
||||
{
|
||||
if (is_bool($arg)) {
|
||||
$this->isMetadataPrinted = $arg;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Process $process
|
||||
* @param callable $output_callback
|
||||
*
|
||||
* @return \Robo\ResultData
|
||||
*/
|
||||
protected function execute($process, $output_callback = null)
|
||||
{
|
||||
$this->process = $process;
|
||||
|
||||
if (!$output_callback) {
|
||||
$output_callback = function ($type, $buffer) {
|
||||
$progressWasVisible = $this->hideTaskProgress();
|
||||
$this->writeMessage($buffer);
|
||||
$this->showTaskProgress($progressWasVisible);
|
||||
};
|
||||
}
|
||||
|
||||
$this->detectInteractive();
|
||||
|
||||
if ($this->isMetadataPrinted) {
|
||||
$this->printAction();
|
||||
}
|
||||
$this->process->setTimeout($this->timeout);
|
||||
$this->process->setIdleTimeout($this->idleTimeout);
|
||||
if ($this->workingDirectory) {
|
||||
$this->process->setWorkingDirectory($this->workingDirectory);
|
||||
}
|
||||
if ($this->input) {
|
||||
$this->process->setInput($this->input);
|
||||
}
|
||||
|
||||
if ($this->interactive && $this->isPrinted) {
|
||||
$this->process->setTty(true);
|
||||
}
|
||||
|
||||
if (isset($this->env)) {
|
||||
$this->process->setEnv($this->env);
|
||||
}
|
||||
|
||||
if (!$this->background && !$this->isPrinted) {
|
||||
$this->startTimer();
|
||||
$this->process->run();
|
||||
$this->stopTimer();
|
||||
$output = rtrim($this->process->getOutput());
|
||||
return new ResultData(
|
||||
$this->process->getExitCode(),
|
||||
$output,
|
||||
$this->getResultData()
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->background && $this->isPrinted) {
|
||||
$this->startTimer();
|
||||
$this->process->run($output_callback);
|
||||
$this->stopTimer();
|
||||
return new ResultData(
|
||||
$this->process->getExitCode(),
|
||||
$this->process->getOutput(),
|
||||
$this->getResultData()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->process->start();
|
||||
} catch (\Exception $e) {
|
||||
return new ResultData(
|
||||
$this->process->getExitCode(),
|
||||
$e->getMessage(),
|
||||
$this->getResultData()
|
||||
);
|
||||
}
|
||||
return new ResultData($this->process->getExitCode());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function stop()
|
||||
{
|
||||
if ($this->background && isset($this->process) && $this->process->isRunning()) {
|
||||
$this->process->stop();
|
||||
$this->printTaskInfo(
|
||||
"Stopped {command}",
|
||||
['command' => $this->getCommandDescription()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $context
|
||||
*/
|
||||
protected function printAction($context = [])
|
||||
{
|
||||
$command = $this->getCommandDescription();
|
||||
$formatted_command = $this->formatCommandDisplay($command);
|
||||
|
||||
$dir = $this->workingDirectory ? " in {dir}" : "";
|
||||
$this->printTaskInfo("Running {command}$dir", [
|
||||
'command' => $formatted_command,
|
||||
'dir' => $this->workingDirectory
|
||||
] + $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $command
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function formatCommandDisplay($command)
|
||||
{
|
||||
$formatted_command = str_replace("&&", "&&\n", $command);
|
||||
$formatted_command = str_replace("||", "||\n", $formatted_command);
|
||||
|
||||
return $formatted_command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data array to be passed to Result().
|
||||
*
|
||||
* @return array
|
||||
* The data array passed to Result().
|
||||
*/
|
||||
protected function getResultData()
|
||||
{
|
||||
if ($this->isMetadataPrinted) {
|
||||
return ['time' => $this->getExecutionTime()];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,7 @@
|
||||
<?php
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Robo;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
@@ -76,7 +71,7 @@ trait IO
|
||||
* @param int $length
|
||||
* @param string $format
|
||||
*/
|
||||
private function formattedOutput($text, $length, $format)
|
||||
protected function formattedOutput($text, $length, $format)
|
||||
{
|
||||
$lines = explode("\n", trim($text, "\n"));
|
||||
$maxLineLength = array_reduce(array_map('strlen', $lines), 'max');
|
||||
@@ -143,7 +138,7 @@ trait IO
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function doAsk(Question $question)
|
||||
protected function doAsk(Question $question)
|
||||
{
|
||||
return $this->getDialog()->ask($this->input(), $this->output(), $question);
|
||||
}
|
||||
@@ -153,7 +148,7 @@ trait IO
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatQuestion($message)
|
||||
protected function formatQuestion($message)
|
||||
{
|
||||
return "<question>? $message</question> ";
|
||||
}
|
||||
@@ -169,7 +164,7 @@ trait IO
|
||||
/**
|
||||
* @param $text
|
||||
*/
|
||||
private function writeln($text)
|
||||
protected function writeln($text)
|
||||
{
|
||||
$this->output()->writeln($text);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Contract\OutputAdapterInterface;
|
||||
use Robo\Contract\OutputAwareInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Adapt OutputInterface or other output function to the VerbosityThresholdInterface.
|
||||
*/
|
||||
class OutputAdapter implements OutputAdapterInterface, OutputAwareInterface
|
||||
{
|
||||
use OutputAwareTrait;
|
||||
|
||||
protected $verbosityMap = [
|
||||
VerbosityThresholdInterface::VERBOSITY_NORMAL => OutputInterface::VERBOSITY_NORMAL,
|
||||
VerbosityThresholdInterface::VERBOSITY_VERBOSE => OutputInterface::VERBOSITY_VERBOSE,
|
||||
VerbosityThresholdInterface::VERBOSITY_VERY_VERBOSE => OutputInterface::VERBOSITY_VERY_VERBOSE,
|
||||
VerbosityThresholdInterface::VERBOSITY_DEBUG => OutputInterface::VERBOSITY_DEBUG,
|
||||
];
|
||||
|
||||
public function verbosityMeetsThreshold($verbosityThreshold)
|
||||
{
|
||||
if (!isset($this->verbosityMap[$verbosityThreshold])) {
|
||||
return true;
|
||||
}
|
||||
$verbosityThreshold = $this->verbosityMap[$verbosityThreshold];
|
||||
$verbosity = $this->output()->getVerbosity();
|
||||
|
||||
return $verbosity >= $verbosityThreshold;
|
||||
}
|
||||
|
||||
public function writeMessage($message)
|
||||
{
|
||||
$this->output()->write($message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Robo\Contract\ConfigAwareInterface;
|
||||
use Robo\Contract\OutputAwareInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class ProcessExecutor implements ConfigAwareInterface, LoggerAwareInterface, OutputAwareInterface, VerbosityThresholdInterface
|
||||
{
|
||||
use ExecTrait;
|
||||
use TaskIO; // uses LoggerAwareTrait and ConfigAwareTrait
|
||||
use ProgressIndicatorAwareTrait;
|
||||
use OutputAwareTrait;
|
||||
|
||||
/**
|
||||
* @param Process $process
|
||||
* @return type
|
||||
*/
|
||||
public function __construct(Process $process)
|
||||
{
|
||||
$this->process = $process;
|
||||
}
|
||||
|
||||
public static function create($container, $process)
|
||||
{
|
||||
$processExecutor = new self($process);
|
||||
|
||||
$processExecutor->setLogger($container->get('logger'));
|
||||
$processExecutor->setProgressIndicator($container->get('progressIndicator'));
|
||||
$processExecutor->setConfig($container->get('config'));
|
||||
$processExecutor->setOutputAdapter($container->get('outputAdapter'));
|
||||
|
||||
return $processExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getCommandDescription()
|
||||
{
|
||||
return $this->process->getCommandLine();
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
return $this->execute($this->process);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is derived from part of the Symfony package, which is
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Symfony\Component\Process\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* ProcessUtils is a bunch of utility methods. We want to allow Robo 1.x
|
||||
* to work with Symfony 4.x while remaining backwards compatibility. This
|
||||
* requires us to replace some deprecated functionality removed in Symfony.
|
||||
*/
|
||||
class ProcessUtils
|
||||
{
|
||||
/**
|
||||
* This class should not be instantiated.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a string to be used as a shell argument.
|
||||
*
|
||||
* @param string $argument The argument that will be escaped
|
||||
*
|
||||
* @return string The escaped argument
|
||||
*
|
||||
* @deprecated since version 3.3, to be removed in 4.0. Use a command line array or give env vars to the `Process::start/run()` method instead.
|
||||
*/
|
||||
public static function escapeArgument($argument)
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.'() method is a copy of a method that was deprecated by Symfony 3.3 and removed in Symfony 4; it will be removed in Robo 2.0.', E_USER_DEPRECATED);
|
||||
|
||||
//Fix for PHP bug #43784 escapeshellarg removes % from given string
|
||||
//Fix for PHP bug #49446 escapeshellarg doesn't work on Windows
|
||||
//@see https://bugs.php.net/bug.php?id=43784
|
||||
//@see https://bugs.php.net/bug.php?id=49446
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
if ('' === $argument) {
|
||||
return escapeshellarg($argument);
|
||||
}
|
||||
|
||||
$escapedArgument = '';
|
||||
$quote = false;
|
||||
foreach (preg_split('/(")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
|
||||
if ('"' === $part) {
|
||||
$escapedArgument .= '\\"';
|
||||
} elseif (self::isSurroundedBy($part, '%')) {
|
||||
// Avoid environment variable expansion
|
||||
$escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
|
||||
} else {
|
||||
// escape trailing backslash
|
||||
if ('\\' === substr($part, -1)) {
|
||||
$part .= '\\';
|
||||
}
|
||||
$quote = true;
|
||||
$escapedArgument .= $part;
|
||||
}
|
||||
}
|
||||
if ($quote) {
|
||||
$escapedArgument = '"'.$escapedArgument.'"';
|
||||
}
|
||||
|
||||
return $escapedArgument;
|
||||
}
|
||||
|
||||
return "'".str_replace("'", "'\\''", $argument)."'";
|
||||
}
|
||||
|
||||
private static function isSurroundedBy($arg, $char)
|
||||
{
|
||||
return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
|
||||
}
|
||||
}
|
||||
+11
@@ -1,6 +1,9 @@
|
||||
<?php
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
|
||||
trait ProgressIndicatorAwareTrait
|
||||
{
|
||||
use Timer;
|
||||
@@ -20,10 +23,14 @@ trait ProgressIndicatorAwareTrait
|
||||
|
||||
/**
|
||||
* @param null|\Robo\Common\ProgressIndicator $progressIndicator
|
||||
*
|
||||
* @return ProgressIndicatorAwareInterface
|
||||
*/
|
||||
public function setProgressIndicator($progressIndicator)
|
||||
{
|
||||
$this->progressIndicator = $progressIndicator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,6 +77,10 @@ trait ProgressIndicatorAwareTrait
|
||||
protected function startProgressIndicator()
|
||||
{
|
||||
$this->startTimer();
|
||||
if ($this instanceof VerbosityThresholdInterface
|
||||
&& !$this->verbosityMeetsThreshold()) {
|
||||
return;
|
||||
}
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ namespace Robo\Common;
|
||||
use Robo\Robo;
|
||||
use Robo\TaskInfo;
|
||||
use Consolidation\Log\ConsoleLogLevel;
|
||||
use Robo\Common\ConfigAwareTrait;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
|
||||
@@ -21,6 +19,7 @@ trait TaskIO
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
use ConfigAwareTrait;
|
||||
use VerbosityThresholdTrait;
|
||||
|
||||
/**
|
||||
* @return mixed|null|\Psr\Log\LoggerInterface
|
||||
@@ -137,6 +136,9 @@ trait TaskIO
|
||||
*/
|
||||
protected function printTaskOutput($level, $text, $context)
|
||||
{
|
||||
if (!$this->verbosityMeetsThreshold()) {
|
||||
return;
|
||||
}
|
||||
$logger = $this->logger();
|
||||
if (!$logger) {
|
||||
return;
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Robo;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Contract\OutputAdapterInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Consolidation\Log\ConsoleLogLevel;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Task input/output methods. TaskIO is 'used' in BaseTask, so any
|
||||
* task that extends this class has access to all of the methods here.
|
||||
* printTaskInfo, printTaskSuccess, and printTaskError are the three
|
||||
* primary output methods that tasks are encouraged to use. Tasks should
|
||||
* avoid using the IO trait output methods.
|
||||
*/
|
||||
trait VerbosityThresholdTrait
|
||||
{
|
||||
/** var OutputAdapterInterface */
|
||||
protected $outputAdapter;
|
||||
protected $verbosityThreshold = 0;
|
||||
|
||||
/**
|
||||
* Required verbocity level before any TaskIO output will be produced.
|
||||
* e.g. OutputInterface::VERBOSITY_VERBOSE
|
||||
*/
|
||||
public function setVerbosityThreshold($verbosityThreshold)
|
||||
{
|
||||
$this->verbosityThreshold = $verbosityThreshold;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function verbosityThreshold()
|
||||
{
|
||||
return $this->verbosityThreshold;
|
||||
}
|
||||
|
||||
public function setOutputAdapter(OutputAdapterInterface $outputAdapter)
|
||||
{
|
||||
$this->outputAdapter = $outputAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OutputAdapterInterface
|
||||
*/
|
||||
public function outputAdapter()
|
||||
{
|
||||
return $this->outputAdapter;
|
||||
}
|
||||
|
||||
public function hasOutputAdapter()
|
||||
{
|
||||
return isset($this->outputAdapter);
|
||||
}
|
||||
|
||||
public function verbosityMeetsThreshold()
|
||||
{
|
||||
if ($this->hasOutputAdapter()) {
|
||||
return $this->outputAdapter()->verbosityMeetsThreshold($this->verbosityThreshold());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a message if the selected verbosity level is over this task's
|
||||
* verbosity threshhold.
|
||||
*/
|
||||
public function writeMessage($message)
|
||||
{
|
||||
if (!$this->verbosityMeetsThreshold()) {
|
||||
return;
|
||||
}
|
||||
$this->outputAdapter()->writeMessage($message);
|
||||
}
|
||||
}
|
||||
+4
-117
@@ -1,122 +1,9 @@
|
||||
<?php
|
||||
namespace Robo;
|
||||
|
||||
class Config
|
||||
/**
|
||||
* @deprecated Use \Robo\Config\Config
|
||||
*/
|
||||
class Config extends \Robo\Config\Config
|
||||
{
|
||||
const PROGRESS_BAR_AUTO_DISPLAY_INTERVAL = 'progress-delay';
|
||||
const DEFAULT_PROGRESS_DELAY = 2;
|
||||
const SIMULATE = 'simulate';
|
||||
const DECORATED = 'decorated';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* Fet a configuration value
|
||||
*
|
||||
* @param string $key Which config item to look up
|
||||
* @param string|null $defaultOverride Override usual default value with a different default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $defaultOverride = null)
|
||||
{
|
||||
if (isset($this->config[$key])) {
|
||||
return $this->config[$key];
|
||||
}
|
||||
return $this->getDefault($key, $defaultOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a config value
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->config[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an associative array containing all of the global configuration
|
||||
* options and their default values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGlobalOptionDefaultValues()
|
||||
{
|
||||
$globalOptions =
|
||||
[
|
||||
self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL => self::DEFAULT_PROGRESS_DELAY,
|
||||
self::SIMULATE => false,
|
||||
];
|
||||
|
||||
return $globalOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value for a given configuration item.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $defaultOverride
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault($key, $defaultOverride = null)
|
||||
{
|
||||
$globalOptions = $this->getGlobalOptionDefaultValues();
|
||||
return isset($globalOptions[$key]) ? $globalOptions[$key] : $defaultOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSimulated()
|
||||
{
|
||||
return $this->get(self::SIMULATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $simulated
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSimulated($simulated = true)
|
||||
{
|
||||
return $this->set(self::SIMULATE, $simulated);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDecorated()
|
||||
{
|
||||
return $this->get(self::DECORATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $decorated
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDecorated($decorated = true)
|
||||
{
|
||||
return $this->set(self::DECORATED, $decorated);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $interval
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProgressBarAutoDisplayInterval($interval)
|
||||
{
|
||||
return $this->set(self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL, $interval);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
namespace Robo\Config;
|
||||
|
||||
class Config extends \Consolidation\Config\Config implements GlobalOptionDefaultValuesInterface
|
||||
{
|
||||
const PROGRESS_BAR_AUTO_DISPLAY_INTERVAL = 'options.progress-delay';
|
||||
const DEFAULT_PROGRESS_DELAY = 2;
|
||||
const SIMULATE = 'options.simulate';
|
||||
|
||||
// Read-only configuration properties; changing these has no effect.
|
||||
const INTERACTIVE = 'options.interactive';
|
||||
const DECORATED = 'options.decorated';
|
||||
|
||||
/**
|
||||
* Create a new configuration object, and initialize it with
|
||||
* the provided nested array containing configuration data.
|
||||
*/
|
||||
public function __construct(array $data = null)
|
||||
{
|
||||
parent::__construct($data);
|
||||
$this->defaults = $this->getGlobalOptionDefaultValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an associative array containing all of the global configuration
|
||||
* options and their default values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGlobalOptionDefaultValues()
|
||||
{
|
||||
$globalOptions =
|
||||
[
|
||||
self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL => self::DEFAULT_PROGRESS_DELAY,
|
||||
self::SIMULATE => false,
|
||||
];
|
||||
return $this->trimPrefixFromGlobalOptions($globalOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the 'options.' prefix from the global options list.
|
||||
*/
|
||||
protected function trimPrefixFromGlobalOptions($globalOptions)
|
||||
{
|
||||
$result = [];
|
||||
foreach ($globalOptions as $option => $value) {
|
||||
$option = str_replace('options.', '', $option);
|
||||
$result[$option] = $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $config->get(Config::SIMULATE)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSimulated()
|
||||
{
|
||||
return $this->get(self::SIMULATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $config->set(Config::SIMULATE, true)
|
||||
*
|
||||
* @param bool $simulated
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSimulated($simulated = true)
|
||||
{
|
||||
return $this->set(self::SIMULATE, $simulated);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $config->get(Config::INTERACTIVE)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInteractive()
|
||||
{
|
||||
return $this->get(self::INTERACTIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $config->set(Config::INTERACTIVE, true)
|
||||
*
|
||||
* @param bool $interactive
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setInteractive($interactive = true)
|
||||
{
|
||||
return $this->set(self::INTERACTIVE, $interactive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $config->get(Config::DECORATED)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDecorated()
|
||||
{
|
||||
return $this->get(self::DECORATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $config->set(Config::DECORATED, true)
|
||||
*
|
||||
* @param bool $decorated
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDecorated($decorated = true)
|
||||
{
|
||||
return $this->set(self::DECORATED, $decorated);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $config->set(Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL, $interval)
|
||||
*
|
||||
* @param int $interval
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProgressBarAutoDisplayInterval($interval)
|
||||
{
|
||||
return $this->set(self::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL, $interval);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace Robo\Config;
|
||||
|
||||
/**
|
||||
* @deprecated Use robo.yml instead
|
||||
*
|
||||
* robo.yml:
|
||||
*
|
||||
* options:
|
||||
* simulated: false
|
||||
* progress-delay: 2
|
||||
*
|
||||
* etc.
|
||||
*/
|
||||
interface GlobalOptionDefaultValuesInterface extends \Consolidation\Config\GlobalOptionDefaultValuesInterface
|
||||
{
|
||||
}
|
||||
+4
-4
@@ -2,23 +2,23 @@
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
use Robo\Config;
|
||||
use Consolidation\Config\ConfigInterface;
|
||||
|
||||
interface ConfigAwareInterface
|
||||
{
|
||||
/**
|
||||
* Set the config reference
|
||||
*
|
||||
* @param \Robo\Config $config
|
||||
* @param ConfigInterface $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfig(Config $config);
|
||||
public function setConfig(ConfigInterface $config);
|
||||
|
||||
/**
|
||||
* Get the config reference
|
||||
*
|
||||
* @return \Robo\Config
|
||||
* @return ConfigInterface
|
||||
*/
|
||||
public function getConfig();
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Adapt OutputInterface or other output function to the VerbosityThresholdInterface.
|
||||
*/
|
||||
interface OutputAdapterInterface
|
||||
{
|
||||
public function verbosityMeetsThreshold($verbosityThreshold);
|
||||
public function writeMessage($message);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace Robo\Contract;
|
||||
|
||||
use Robo\Contract\OutputAdapterInterface;
|
||||
|
||||
/**
|
||||
* Record and determine whether the current verbosity level exceeds the
|
||||
* desired threshold level to produce output.
|
||||
*/
|
||||
interface VerbosityThresholdInterface
|
||||
{
|
||||
const VERBOSITY_NORMAL = 1;
|
||||
const VERBOSITY_VERBOSE = 2;
|
||||
const VERBOSITY_VERY_VERBOSE = 3;
|
||||
const VERBOSITY_DEBUG = 4;
|
||||
|
||||
public function setVerbosityThreshold($verbosityThreshold);
|
||||
public function verbosityThreshold();
|
||||
public function setOutputAdapter(OutputAdapterInterface $outputAdapter);
|
||||
public function outputAdapter();
|
||||
public function hasOutputAdapter();
|
||||
public function verbosityMeetsThreshold();
|
||||
public function writeMessage($message);
|
||||
}
|
||||
+105
-4
@@ -3,21 +3,63 @@ namespace Robo;
|
||||
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\Event\ConsoleCommandEvent;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Robo\Contract\ConfigAwareInterface;
|
||||
use Robo\Common\ConfigAwareTrait;
|
||||
use Robo\Config\GlobalOptionDefaultValuesInterface;
|
||||
|
||||
class GlobalOptionsEventListener implements EventSubscriberInterface, ConfigAwareInterface
|
||||
{
|
||||
use ConfigAwareTrait;
|
||||
|
||||
/** @var Application */
|
||||
protected $application;
|
||||
|
||||
/** @var string */
|
||||
protected $prefix;
|
||||
|
||||
/**
|
||||
* GlobalOptionsEventListener listener
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->prefix = 'options';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a reference to the Symfony Console application object.
|
||||
*/
|
||||
public function setApplication($application)
|
||||
{
|
||||
$this->application = $application;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stipulate the prefix to use for option injection.
|
||||
* @param string $prefix
|
||||
*/
|
||||
public function setGlobalOptionsPrefix($prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [ConsoleEvents::COMMAND => 'setGlobalOptions'];
|
||||
return [ConsoleEvents::COMMAND => 'handleCommandEvent'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all of our individual operations when a command event is received.
|
||||
*/
|
||||
public function handleCommandEvent(ConsoleCommandEvent $event)
|
||||
{
|
||||
$this->setGlobalOptions($event);
|
||||
$this->setConfigurationValues($event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,15 +73,74 @@ class GlobalOptionsEventListener implements EventSubscriberInterface, ConfigAwar
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$input = $event->getInput();
|
||||
$globalOptions = $config->getGlobalOptionDefaultValues();
|
||||
|
||||
$globalOptions = $config->get($this->prefix, []);
|
||||
if ($config instanceof \Consolidation\Config\GlobalOptionDefaultValuesInterface) {
|
||||
$globalOptions += $config->getGlobalOptionDefaultValues();
|
||||
}
|
||||
|
||||
$globalOptions += $this->applicationOptionDefaultValues();
|
||||
|
||||
// Set any config value that has a defined global option (e.g. --simulate)
|
||||
foreach ($globalOptions as $option => $default) {
|
||||
$value = $input->hasOption($option) ? $input->getOption($option) : null;
|
||||
// Unfortunately, the `?:` operator does not differentate between `0` and `null`
|
||||
if (!isset($value)) {
|
||||
$value = $default;
|
||||
}
|
||||
$config->set($option, $value);
|
||||
$config->set($this->prefix . '.' . $option, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine the commandline --define / -D options, and apply the provided
|
||||
* values to the active configuration.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event
|
||||
*/
|
||||
public function setConfigurationValues(ConsoleCommandEvent $event)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$input = $event->getInput();
|
||||
|
||||
// Also set any `-D config.key=value` options from the commandline.
|
||||
if ($input->hasOption('define')) {
|
||||
$configDefinitions = $input->getOption('define');
|
||||
foreach ($configDefinitions as $value) {
|
||||
list($key, $value) = $this->splitConfigKeyValue($value);
|
||||
$config->set($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split up the key=value config setting into its component parts. If
|
||||
* the input string contains no '=' character, then the value will be 'true'.
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
protected function splitConfigKeyValue($value)
|
||||
{
|
||||
$parts = explode('=', $value, 2);
|
||||
$parts[] = true;
|
||||
return $parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default option values from the Symfony Console application, if
|
||||
* it is available.
|
||||
*/
|
||||
protected function applicationOptionDefaultValues()
|
||||
{
|
||||
if (!$this->application) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($this->application->getDefinition()->getOptions() as $key => $option) {
|
||||
$result[$key] = $option->acceptValue() ? $option->getDefault() : null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
namespace Robo\Log;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Robo\Common\ProgressIndicatorAwareTrait;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Consolidation\Log\ConsoleLogLevel;
|
||||
@@ -32,6 +31,10 @@ class ResultPrinter implements LoggerAwareInterface, ProgressIndicatorAwareInter
|
||||
*/
|
||||
public function printResult(Result $result)
|
||||
{
|
||||
$task = $result->getTask();
|
||||
if ($task instanceof VerbosityThresholdInterface && !$task->verbosityMeetsThreshold()) {
|
||||
return;
|
||||
}
|
||||
if (!$result->wasSuccessful()) {
|
||||
return $this->printError($result);
|
||||
} else {
|
||||
|
||||
@@ -3,8 +3,6 @@ namespace Robo\Log;
|
||||
|
||||
use Robo\Common\TimeKeeper;
|
||||
use Consolidation\Log\LogOutputStyler;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\OutputStyle;
|
||||
|
||||
/**
|
||||
* Robo Log Styler.
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
<?php
|
||||
namespace Robo\Log;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Contract\LogResultInterface;
|
||||
use Consolidation\Log\ConsoleLogLevel;
|
||||
use Consolidation\Log\Logger;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use Psr\Log\AbstractLogger;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Logger\ConsoleLogger;
|
||||
|
||||
/**
|
||||
* Robo's default logger
|
||||
|
||||
+26
-2
@@ -2,8 +2,8 @@
|
||||
namespace Robo;
|
||||
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\LogResultInterface;
|
||||
use Robo\Exception\TaskExitException;
|
||||
use Robo\State\Data;
|
||||
|
||||
class Result extends ResultData
|
||||
{
|
||||
@@ -34,6 +34,30 @@ class Result extends ResultData
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tasks should always return a Result. However, they are also
|
||||
* allowed to return NULL or an array to indicate success.
|
||||
*/
|
||||
public static function ensureResult($task, $result)
|
||||
{
|
||||
if ($result instanceof Result) {
|
||||
return $result;
|
||||
}
|
||||
if (!isset($result)) {
|
||||
return static::success($task);
|
||||
}
|
||||
if ($result instanceof Data) {
|
||||
return static::success($task, $result->getMessage(), $result->getData());
|
||||
}
|
||||
if ($result instanceof ResultData) {
|
||||
return new Result($task, $result->getExitCode(), $result->getMessage(), $result->getData());
|
||||
}
|
||||
if (is_array($result)) {
|
||||
return static::success($task, '', $result);
|
||||
}
|
||||
throw new \Exception(sprintf('Task %s returned a %s instead of a \Robo\Result.', get_class($task), get_class($result)));
|
||||
}
|
||||
|
||||
protected function printResult()
|
||||
{
|
||||
// For historic reasons, the Result constructor is responsible
|
||||
@@ -45,7 +69,7 @@ class Result extends ResultData
|
||||
$resultPrinter = Robo::resultPrinter();
|
||||
if ($resultPrinter) {
|
||||
if ($resultPrinter->printResult($this)) {
|
||||
$this->data['already-printed'] = true;
|
||||
$this->alreadyPrinted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-57
@@ -1,22 +1,17 @@
|
||||
<?php
|
||||
namespace Robo;
|
||||
|
||||
use Robo\Contract\LogResultInterface;
|
||||
use Consolidation\AnnotatedCommand\ExitCodeInterface;
|
||||
use Consolidation\AnnotatedCommand\OutputDataInterface;
|
||||
use Robo\State\Data;
|
||||
|
||||
class ResultData extends \ArrayObject implements ExitCodeInterface, OutputDataInterface
|
||||
class ResultData extends Data implements ExitCodeInterface, OutputDataInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $exitCode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
const EXITCODE_OK = 0;
|
||||
const EXITCODE_ERROR = 1;
|
||||
/** Symfony Console handles these conditions; Robo returns the status
|
||||
@@ -38,9 +33,7 @@ class ResultData extends \ArrayObject implements ExitCodeInterface, OutputDataIn
|
||||
public function __construct($exitCode = self::EXITCODE_OK, $message = '', $data = [])
|
||||
{
|
||||
$this->exitCode = $exitCode;
|
||||
$this->message = $message;
|
||||
|
||||
parent::__construct($data);
|
||||
parent::__construct($message, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,14 +58,6 @@ class ResultData extends \ArrayObject implements ExitCodeInterface, OutputDataIn
|
||||
return new ResultData(self::EXITCODE_USER_CANCEL, $message, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->getArrayCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
@@ -86,17 +71,25 @@ class ResultData extends \ArrayObject implements ExitCodeInterface, OutputDataIn
|
||||
*/
|
||||
public function getOutputData()
|
||||
{
|
||||
if (!empty($this->message) && !isset($this['already-printed'])) {
|
||||
if (!empty($this->message) && !isset($this['already-printed']) && isset($this['provide-outputdata'])) {
|
||||
return $this->message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* Indicate that the message in this data has already been displayed.
|
||||
*/
|
||||
public function getMessage()
|
||||
public function alreadyPrinted()
|
||||
{
|
||||
return $this->message;
|
||||
$this['already-printed'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opt-in to providing the result message as the output data
|
||||
*/
|
||||
public function provideOutputdata()
|
||||
{
|
||||
$this['provide-outputdata'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,39 +107,4 @@ class ResultData extends \ArrayObject implements ExitCodeInterface, OutputDataIn
|
||||
{
|
||||
return $this->exitCode == self::EXITCODE_USER_CANCEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge another result into this result. Data already
|
||||
* existing in this result takes precedence over the
|
||||
* data in the Result being merged.
|
||||
*
|
||||
* @param \Robo\ResultData $result
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(ResultData $result)
|
||||
{
|
||||
$mergedData = $this->getArrayCopy() + $result->getArrayCopy();
|
||||
$this->exchangeArray($mergedData);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasExecutionTime()
|
||||
{
|
||||
return isset($this['time']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|float
|
||||
*/
|
||||
public function getExecutionTime()
|
||||
{
|
||||
if (!$this->hasExecutionTime()) {
|
||||
return null;
|
||||
}
|
||||
return $this['time'];
|
||||
}
|
||||
}
|
||||
|
||||
+70
-13
@@ -3,8 +3,13 @@ namespace Robo;
|
||||
|
||||
use League\Container\Container;
|
||||
use League\Container\ContainerInterface;
|
||||
use Robo\Common\ProcessExecutor;
|
||||
use Consolidation\Config\ConfigInterface;
|
||||
use Consolidation\Config\Loader\ConfigProcessor;
|
||||
use Consolidation\Config\Loader\YamlConfigLoader;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Application as SymfonyApplication;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Manages the container reference and other static data. Favor
|
||||
@@ -14,7 +19,7 @@ use Symfony\Component\Console\Application as SymfonyApplication;
|
||||
class Robo
|
||||
{
|
||||
const APPLICATION_NAME = 'Robo';
|
||||
const VERSION = '1.0.4';
|
||||
const VERSION = '1.2.1';
|
||||
|
||||
/**
|
||||
* The currently active container object, or NULL if not initialized yet.
|
||||
@@ -34,9 +39,10 @@ class Robo
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function run($argv, $commandClasses, $appName = null, $appVersion = null, $output = null)
|
||||
public static function run($argv, $commandClasses, $appName = null, $appVersion = null, $output = null, $repository = null)
|
||||
{
|
||||
$runner = new \Robo\Runner($commandClasses);
|
||||
$runner->setSelfUpdateRepository($repository);
|
||||
$statusCode = $runner->execute($argv, $appName, $appVersion, $output);
|
||||
return $statusCode;
|
||||
}
|
||||
@@ -85,6 +91,33 @@ class Robo
|
||||
return static::$container !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a config object and load it from the provided paths.
|
||||
*/
|
||||
public static function createConfiguration($paths)
|
||||
{
|
||||
$config = new \Robo\Config\Config();
|
||||
static::loadConfiguration($paths, $config);
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a simple config loader to load configuration values from specified paths
|
||||
*/
|
||||
public static function loadConfiguration($paths, $config = null)
|
||||
{
|
||||
if ($config == null) {
|
||||
$config = static::config();
|
||||
}
|
||||
$loader = new YamlConfigLoader();
|
||||
$processor = new ConfigProcessor();
|
||||
$processor->add($config->export());
|
||||
foreach ($paths as $path) {
|
||||
$processor->extend($loader->load($path));
|
||||
}
|
||||
$config->import($processor->export());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a container and initiailze it. If you wish to *change*
|
||||
* anything defined in the container, then you should call
|
||||
@@ -93,7 +126,7 @@ class Robo
|
||||
* @param null|\Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @param null|\Robo\Application $app
|
||||
* @param null|\Robo\Config $config
|
||||
* @param null|ConfigInterface $config
|
||||
*
|
||||
* @return \League\Container\Container|\League\Container\ContainerInterface
|
||||
*/
|
||||
@@ -109,7 +142,7 @@ class Robo
|
||||
}
|
||||
|
||||
if (!$config) {
|
||||
$config = new Config();
|
||||
$config = new \Robo\Config\Config();
|
||||
}
|
||||
|
||||
// Set up our dependency injection container.
|
||||
@@ -139,11 +172,11 @@ class Robo
|
||||
*
|
||||
* @param \League\Container\ContainerInterface $container
|
||||
* @param \Symfony\Component\Console\Application $app
|
||||
* @param \Robo\Config $config
|
||||
* @param ConfigInterface $config
|
||||
* @param null|\Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
*/
|
||||
public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, Config $config, $input = null, $output = null)
|
||||
public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, ConfigInterface $config, $input = null, $output = null)
|
||||
{
|
||||
// Self-referential container refernce for the inflector
|
||||
$container->add('container', $container);
|
||||
@@ -156,12 +189,14 @@ class Robo
|
||||
if (!$output) {
|
||||
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
|
||||
}
|
||||
$config->setDecorated($output->isDecorated());
|
||||
$config->set(Config::DECORATED, $output->isDecorated());
|
||||
$config->set(Config::INTERACTIVE, $input->isInteractive());
|
||||
|
||||
$container->share('application', $app);
|
||||
$container->share('config', $config);
|
||||
$container->share('input', $input);
|
||||
$container->share('output', $output);
|
||||
$container->share('outputAdapter', \Robo\Common\OutputAdapter::class);
|
||||
|
||||
// Register logging and related services.
|
||||
$container->share('logStyler', \Robo\Log\RoboLogStyle::class);
|
||||
@@ -175,22 +210,30 @@ class Robo
|
||||
->withArgument('output');
|
||||
$container->share('resultPrinter', \Robo\Log\ResultPrinter::class);
|
||||
$container->add('simulator', \Robo\Task\Simulator::class);
|
||||
$container->share('globalOptionsEventListener', \Robo\GlobalOptionsEventListener::class);
|
||||
$container->share('globalOptionsEventListener', \Robo\GlobalOptionsEventListener::class)
|
||||
->withMethodCall('setApplication', ['application']);
|
||||
$container->share('injectConfigEventListener', \Consolidation\Config\Inject\ConfigForCommand::class)
|
||||
->withArgument('config')
|
||||
->withMethodCall('setApplication', ['application']);
|
||||
$container->share('collectionProcessHook', \Robo\Collection\CollectionProcessHook::class);
|
||||
$container->share('hookManager', \Consolidation\AnnotatedCommand\Hooks\HookManager::class)
|
||||
->withMethodCall('addResultProcessor', ['collectionProcessHook', '*']);
|
||||
$container->share('alterOptionsCommandEvent', \Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent::class)
|
||||
->withArgument('application');
|
||||
$container->share('hookManager', \Consolidation\AnnotatedCommand\Hooks\HookManager::class)
|
||||
->withMethodCall('addCommandEvent', ['alterOptionsCommandEvent'])
|
||||
->withMethodCall('addCommandEvent', ['injectConfigEventListener'])
|
||||
->withMethodCall('addCommandEvent', ['globalOptionsEventListener'])
|
||||
->withMethodCall('addResultProcessor', ['collectionProcessHook', '*']);
|
||||
$container->share('eventDispatcher', \Symfony\Component\EventDispatcher\EventDispatcher::class)
|
||||
->withMethodCall('addSubscriber', ['globalOptionsEventListener'])
|
||||
->withMethodCall('addSubscriber', ['alterOptionsCommandEvent'])
|
||||
->withMethodCall('addSubscriber', ['hookManager']);
|
||||
$container->share('formatterManager', \Consolidation\OutputFormatters\FormatterManager::class)
|
||||
->withMethodCall('addDefaultFormatters', [])
|
||||
->withMethodCall('addDefaultSimplifiers', []);
|
||||
$container->share('prepareTerminalWidthOption', \Consolidation\AnnotatedCommand\Options\PrepareTerminalWidthOption::class)
|
||||
->withMethodCall('setApplication', ['application']);
|
||||
$container->share('commandProcessor', \Consolidation\AnnotatedCommand\CommandProcessor::class)
|
||||
->withArgument('hookManager')
|
||||
->withMethodCall('setFormatterManager', ['formatterManager'])
|
||||
->withMethodCall('addPrepareFormatter', ['prepareTerminalWidthOption'])
|
||||
->withMethodCall(
|
||||
'setDisplayErrorFunction',
|
||||
[
|
||||
@@ -202,8 +245,13 @@ class Robo
|
||||
);
|
||||
$container->share('commandFactory', \Consolidation\AnnotatedCommand\AnnotatedCommandFactory::class)
|
||||
->withMethodCall('setCommandProcessor', ['commandProcessor']);
|
||||
|
||||
// Deprecated: favor using collection builders to direct use of collections.
|
||||
$container->add('collection', \Robo\Collection\Collection::class);
|
||||
// Deprecated: use CollectionBuilder::create() instead -- or, better
|
||||
// yet, BuilderAwareInterface::collectionBuilder() if available.
|
||||
$container->add('collectionBuilder', \Robo\Collection\CollectionBuilder::class);
|
||||
|
||||
static::addInflectors($container);
|
||||
|
||||
// Make sure the application is appropriately initialized.
|
||||
@@ -246,6 +294,10 @@ class Robo
|
||||
->invokeMethod('setOutput', ['output']);
|
||||
$container->inflector(\Robo\Contract\ProgressIndicatorAwareInterface::class)
|
||||
->invokeMethod('setProgressIndicator', ['progressIndicator']);
|
||||
$container->inflector(\Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface::class)
|
||||
->invokeMethod('setHookManager', ['hookManager']);
|
||||
$container->inflector(\Robo\Contract\VerbosityThresholdInterface::class)
|
||||
->invokeMethod('setOutputAdapter', ['outputAdapter']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +344,7 @@ class Robo
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Config
|
||||
* @return ConfigInterface
|
||||
*/
|
||||
public static function config()
|
||||
{
|
||||
@@ -334,4 +386,9 @@ class Robo
|
||||
{
|
||||
return static::service('input');
|
||||
}
|
||||
|
||||
public static function process(Process $process)
|
||||
{
|
||||
return ProcessExecutor::create(static::getContainer(), $process);
|
||||
}
|
||||
}
|
||||
|
||||
+59
-13
@@ -1,15 +1,12 @@
|
||||
<?php
|
||||
namespace Robo;
|
||||
|
||||
use League\Container\Container;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Consolidation\AnnotatedCommand\PassThroughArgsInput;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Collection\CollectionBuilder;
|
||||
use Robo\Common\IO;
|
||||
use Robo\Exception\TaskExitException;
|
||||
use League\Container\ContainerInterface;
|
||||
use League\Container\ContainerAwareInterface;
|
||||
use League\Container\ContainerAwareTrait;
|
||||
|
||||
@@ -36,6 +33,16 @@ class Runner implements ContainerAwareInterface
|
||||
*/
|
||||
protected $dir;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $errorConditions = [];
|
||||
|
||||
/**
|
||||
* @var string GitHub Repo for SelfUpdate
|
||||
*/
|
||||
protected $selfUpdateRepository = null;
|
||||
|
||||
/**
|
||||
* Class Constructor
|
||||
*
|
||||
@@ -50,6 +57,11 @@ class Runner implements ContainerAwareInterface
|
||||
$this->dir = getcwd();
|
||||
}
|
||||
|
||||
protected function errorCondtion($msg, $errorType)
|
||||
{
|
||||
$this->errorConditions[$msg] = $errorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
@@ -70,7 +82,7 @@ class Runner implements ContainerAwareInterface
|
||||
return true;
|
||||
}
|
||||
if (!file_exists($this->dir)) {
|
||||
$output->writeln("<error>Path `{$this->dir}` is invalid; please provide a valid absolute path to the Robofile to load.</error>");
|
||||
$this->errorCondtion("Path `{$this->dir}` is invalid; please provide a valid absolute path to the Robofile to load.", 'red');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -79,13 +91,13 @@ class Runner implements ContainerAwareInterface
|
||||
$roboFilePath = $realDir . DIRECTORY_SEPARATOR . $this->roboFile;
|
||||
if (!file_exists($roboFilePath)) {
|
||||
$requestedRoboFilePath = $this->dir . DIRECTORY_SEPARATOR . $this->roboFile;
|
||||
$output->writeln("<error>Requested RoboFile `$requestedRoboFilePath` is invalid, please provide valid absolute path to load Robofile</error>");
|
||||
$this->errorCondtion("Requested RoboFile `$requestedRoboFilePath` is invalid, please provide valid absolute path to load Robofile.", 'red');
|
||||
return false;
|
||||
}
|
||||
require_once $roboFilePath;
|
||||
|
||||
if (!class_exists($this->roboClass)) {
|
||||
$output->writeln("<error>Class ".$this->roboClass." was not loaded</error>");
|
||||
$this->errorCondtion("Class {$this->roboClass} was not loaded.", 'red');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -136,7 +148,10 @@ class Runner implements ContainerAwareInterface
|
||||
|
||||
// If we were not provided a container, then create one
|
||||
if (!$this->getContainer()) {
|
||||
$container = Robo::createDefaultContainer($input, $output, $app);
|
||||
$userConfig = 'robo.yml';
|
||||
$roboAppConfig = dirname(__DIR__) . '/robo.yml';
|
||||
$config = Robo::createConfiguration([$userConfig, $roboAppConfig]);
|
||||
$container = Robo::createDefaultContainer($input, $output, $app, $config);
|
||||
$this->setContainer($container);
|
||||
// Automatically register a shutdown function and
|
||||
// an error handler when we provide the container.
|
||||
@@ -146,10 +161,13 @@ class Runner implements ContainerAwareInterface
|
||||
if (!$app) {
|
||||
$app = Robo::application();
|
||||
}
|
||||
if (!isset($commandFiles)) {
|
||||
$this->yell("Robo is not initialized here. Please run `robo init` to create a new RoboFile", 40, 'yellow');
|
||||
$app->addInitRoboFileCommand($this->roboFile, $this->roboClass);
|
||||
$commandFiles = [];
|
||||
if ($app instanceof \Robo\Application) {
|
||||
$app->addSelfUpdateCommand($this->getSelfUpdateRepository());
|
||||
if (!isset($commandFiles)) {
|
||||
$this->errorCondtion("Robo is not initialized here. Please run `robo init` to create a new RoboFile.", 'yellow');
|
||||
$app->addInitRoboFileCommand($this->roboFile, $this->roboClass);
|
||||
$commandFiles = [];
|
||||
}
|
||||
}
|
||||
$this->registerCommandClasses($app, $commandFiles);
|
||||
|
||||
@@ -158,6 +176,15 @@ class Runner implements ContainerAwareInterface
|
||||
} catch (TaskExitException $e) {
|
||||
$statusCode = $e->getCode() ?: 1;
|
||||
}
|
||||
|
||||
// If there were any error conditions in bootstrapping Robo,
|
||||
// print them only if the requested command did not complete
|
||||
// successfully.
|
||||
if ($statusCode) {
|
||||
foreach ($this->errorConditions as $msg => $color) {
|
||||
$this->yell($msg, 40, $color);
|
||||
}
|
||||
}
|
||||
return $statusCode;
|
||||
}
|
||||
|
||||
@@ -222,6 +249,9 @@ class Runner implements ContainerAwareInterface
|
||||
// If the command class is already an instantiated object, then
|
||||
// just use it exactly as it was provided to us.
|
||||
if (is_string($commandClass)) {
|
||||
if (!class_exists($commandClass)) {
|
||||
return;
|
||||
}
|
||||
$reflectionClass = new \ReflectionClass($commandClass);
|
||||
if ($reflectionClass->isAbstract()) {
|
||||
return;
|
||||
@@ -235,7 +265,7 @@ class Runner implements ContainerAwareInterface
|
||||
// ensure that it has a builder. Every command class needs
|
||||
// its own collection builder, as they have references to each other.
|
||||
if ($commandClass instanceof BuilderAwareInterface) {
|
||||
$builder = $container->get('collectionBuilder', [$commandClass]);
|
||||
$builder = CollectionBuilder::create($container, $commandClass);
|
||||
$commandClass->setBuilder($builder);
|
||||
}
|
||||
if ($commandClass instanceof ContainerAwareInterface) {
|
||||
@@ -416,4 +446,20 @@ class Runner implements ContainerAwareInterface
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSelfUpdateRepository()
|
||||
{
|
||||
return $this->selfUpdateRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $selfUpdateRepository
|
||||
*/
|
||||
public function setSelfUpdateRepository($selfUpdateRepository)
|
||||
{
|
||||
$this->selfUpdateRepository = $selfUpdateRepository;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem as sfFilesystem;
|
||||
|
||||
/**
|
||||
* Update the robo.phar from the latest github release
|
||||
*
|
||||
* @author Alexander Menk <alex.menk@gmail.com>
|
||||
*/
|
||||
class SelfUpdateCommand extends Command
|
||||
{
|
||||
const SELF_UPDATE_COMMAND_NAME = 'self:update';
|
||||
|
||||
protected $gitHubRepository;
|
||||
|
||||
protected $currentVersion;
|
||||
|
||||
protected $applicationName;
|
||||
|
||||
public function __construct($applicationName = null, $currentVersion = null, $gitHubRepository = null)
|
||||
{
|
||||
parent::__construct(self::SELF_UPDATE_COMMAND_NAME);
|
||||
|
||||
$this->applicationName = $applicationName;
|
||||
$this->currentVersion = $currentVersion;
|
||||
$this->gitHubRepository = $gitHubRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setAliases(array('update'))
|
||||
->setDescription('Updates the robo.phar to the latest version.')
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>self-update</info> command checks github for newer
|
||||
versions of robo and if found, installs the latest.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
protected function getLatestReleaseFromGithub()
|
||||
{
|
||||
$opts = [
|
||||
'http' => [
|
||||
'method' => 'GET',
|
||||
'header' => [
|
||||
'User-Agent: ' . $this->applicationName . ' (' . $this->gitHubRepository . ')' . ' Self-Update (PHP)'
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$context = stream_context_create($opts);
|
||||
|
||||
$releases = file_get_contents('https://api.github.com/repos/' . $this->gitHubRepository . '/releases', false, $context);
|
||||
$releases = json_decode($releases);
|
||||
|
||||
if (! isset($releases[0])) {
|
||||
throw new \Exception('API error - no release found at GitHub repository ' . $this->gitHubRepository);
|
||||
}
|
||||
|
||||
$version = $releases[0]->tag_name;
|
||||
$url = $releases[0]->assets[0]->browser_download_url;
|
||||
|
||||
return [ $version, $url ];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (empty(\Phar::running())) {
|
||||
throw new \Exception(self::SELF_UPDATE_COMMAND_NAME . ' only works when running the phar version of ' . $this->applicationName . '.');
|
||||
}
|
||||
|
||||
$localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
|
||||
$programName = basename($localFilename);
|
||||
$tempFilename = dirname($localFilename) . '/' . basename($localFilename, '.phar') . '-temp.phar';
|
||||
|
||||
// check for permissions in local filesystem before start connection process
|
||||
if (! is_writable($tempDirectory = dirname($tempFilename))) {
|
||||
throw new \Exception(
|
||||
$programName . ' update failed: the "' . $tempDirectory .
|
||||
'" directory used to download the temp file could not be written'
|
||||
);
|
||||
}
|
||||
|
||||
if (! is_writable($localFilename)) {
|
||||
throw new \Exception(
|
||||
$programName . ' update failed: the "' . $localFilename . '" file could not be written (execute with sudo)'
|
||||
);
|
||||
}
|
||||
|
||||
list( $latest, $downloadUrl ) = $this->getLatestReleaseFromGithub();
|
||||
|
||||
|
||||
if ($this->currentVersion == $latest) {
|
||||
$output->writeln('No update available');
|
||||
return;
|
||||
}
|
||||
|
||||
$fs = new sfFilesystem();
|
||||
|
||||
$output->writeln('Downloading ' . $this->applicationName . ' (' . $this->gitHubRepository . ') ' . $latest);
|
||||
|
||||
$fs->copy($downloadUrl, $tempFilename);
|
||||
|
||||
$output->writeln('Download finished');
|
||||
|
||||
try {
|
||||
\error_reporting(E_ALL); // supress notices
|
||||
|
||||
@chmod($tempFilename, 0777 & ~umask());
|
||||
// test the phar validity
|
||||
$phar = new \Phar($tempFilename);
|
||||
// free the variable to unlock the file
|
||||
unset($phar);
|
||||
@rename($tempFilename, $localFilename);
|
||||
$output->writeln('<info>Successfully updated ' . $programName . '</info>');
|
||||
$this->_exit();
|
||||
} catch (\Exception $e) {
|
||||
@unlink($tempFilename);
|
||||
if (! $e instanceof \UnexpectedValueException && ! $e instanceof \PharException) {
|
||||
throw $e;
|
||||
}
|
||||
$output->writeln('<error>The download is corrupted (' . $e->getMessage() . ').</error>');
|
||||
$output->writeln('<error>Please re-run the self-update command to try again.</error>');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop execution
|
||||
*
|
||||
* This is a workaround to prevent warning of dispatcher after replacing
|
||||
* the phar file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _exit()
|
||||
{
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace Robo\State;
|
||||
|
||||
use Robo\State\Data;
|
||||
|
||||
interface Consumer
|
||||
{
|
||||
/**
|
||||
* @return Data
|
||||
*/
|
||||
public function receiveState(Data $state);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
namespace Robo\State;
|
||||
|
||||
/**
|
||||
* A State\Data object contains a "message" (the primary result) and a
|
||||
* data array (the persistent state). The message is transient, and does
|
||||
* not move into the persistent state unless explicitly copied there.
|
||||
*/
|
||||
class Data extends \ArrayObject
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct($message = '', $data = [])
|
||||
{
|
||||
$this->message = $message;
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->getArrayCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string message
|
||||
*/
|
||||
public function setMessage($message)
|
||||
{
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge another result into this result. Data already
|
||||
* existing in this result takes precedence over the
|
||||
* data in the Result being merged.
|
||||
*
|
||||
* @param \Robo\ResultData $result
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(Data $result)
|
||||
{
|
||||
$mergedData = $this->getArrayCopy() + $result->getArrayCopy();
|
||||
$this->exchangeArray($mergedData);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current data with the data provided in the parameter.
|
||||
* Provided data takes precedence.
|
||||
*
|
||||
* @param \ArrayObject $update
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function update(\ArrayObject $update)
|
||||
{
|
||||
$iterator = $update->getIterator();
|
||||
|
||||
while ($iterator->valid()) {
|
||||
$this[$iterator->key()] = $iterator->current();
|
||||
$iterator->next();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge another result into this result. Data already
|
||||
* existing in this result takes precedence over the
|
||||
* data in the Result being merged.
|
||||
*
|
||||
* $data['message'] is handled specially, and is appended
|
||||
* to $this->message if set.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function mergeData(array $data)
|
||||
{
|
||||
$mergedData = $this->getArrayCopy() + $data;
|
||||
$this->exchangeArray($mergedData);
|
||||
return $mergedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasExecutionTime()
|
||||
{
|
||||
return isset($this['time']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|float
|
||||
*/
|
||||
public function getExecutionTime()
|
||||
{
|
||||
if (!$this->hasExecutionTime()) {
|
||||
return null;
|
||||
}
|
||||
return $this['time'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulate execution time
|
||||
*/
|
||||
public function accumulateExecutionTime($duration)
|
||||
{
|
||||
// Convert data arrays to scalar
|
||||
if (is_array($duration)) {
|
||||
$duration = isset($duration['time']) ? $duration['time'] : 0;
|
||||
}
|
||||
$this['time'] = $this->getExecutionTime() + $duration;
|
||||
return $this->getExecutionTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulate the message.
|
||||
*/
|
||||
public function accumulateMessage($message)
|
||||
{
|
||||
if (!empty($this->message)) {
|
||||
$this->message .= "\n";
|
||||
}
|
||||
$this->message .= $message;
|
||||
return $this->getMessage();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace Robo\State;
|
||||
|
||||
use Robo\State\Data;
|
||||
|
||||
interface StateAwareInterface
|
||||
{
|
||||
/**
|
||||
* @return Data
|
||||
*/
|
||||
public function getState();
|
||||
|
||||
/**
|
||||
* @param Data state
|
||||
*/
|
||||
public function setState(Data $state);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param value
|
||||
*/
|
||||
public function setStateValue($key, $value);
|
||||
|
||||
/**
|
||||
* @param Data update state takes precedence over current state.
|
||||
*/
|
||||
public function updateState(Data $update);
|
||||
|
||||
public function resetState();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace Robo\State;
|
||||
|
||||
use Robo\State\Data;
|
||||
|
||||
trait StateAwareTrait
|
||||
{
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setState(Data $state)
|
||||
{
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStateValue($key, $value)
|
||||
{
|
||||
$this->state[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateState(Data $update)
|
||||
{
|
||||
$this->state->update($update);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetState()
|
||||
{
|
||||
$this->state = new Data();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,8 @@ use Traversable;
|
||||
* ``` php
|
||||
* <?php
|
||||
* // ApiGen Command
|
||||
* $this->taskApiGen('./apigen.neon')
|
||||
* $this->taskApiGen('./vendor/apigen/apigen.phar')
|
||||
* ->config('./apigen.neon')
|
||||
* ->templateConfig('vendor/apigen/apigen/templates/bootstrap/config.neon')
|
||||
* ->wipeout(true)
|
||||
* ->run();
|
||||
@@ -30,6 +31,7 @@ class ApiGen extends BaseTask implements CommandInterface
|
||||
* @var string
|
||||
*/
|
||||
protected $command;
|
||||
protected $operation = 'generate';
|
||||
|
||||
/**
|
||||
* @param null|string $pathToApiGen
|
||||
@@ -39,6 +41,15 @@ class ApiGen extends BaseTask implements CommandInterface
|
||||
public function __construct($pathToApiGen = null)
|
||||
{
|
||||
$this->command = $pathToApiGen;
|
||||
$command_parts = [];
|
||||
preg_match('/((?:.+)?apigen(?:\.phar)?) ?( \w+)? ?(.+)?/', $this->command, $command_parts);
|
||||
if (count($command_parts) === 3) {
|
||||
list(, $this->command, $this->operation) = $command_parts;
|
||||
}
|
||||
if (count($command_parts) === 4) {
|
||||
list(, $this->command, $this->operation, $arg) = $command_parts;
|
||||
$this->arg($arg);
|
||||
}
|
||||
if (!$this->command) {
|
||||
$this->command = $this->findExecutablePhar('apigen');
|
||||
}
|
||||
@@ -47,6 +58,31 @@ class ApiGen extends BaseTask implements CommandInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass methods parameters as arguments to executable. Argument values
|
||||
* are automatically escaped.
|
||||
*
|
||||
* @param string|string[] $args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function args($args)
|
||||
{
|
||||
if (!is_array($args)) {
|
||||
$args = func_get_args();
|
||||
}
|
||||
$args = array_map(function ($arg) {
|
||||
if (preg_match('/^\w+$/', trim($arg)) === 1) {
|
||||
$this->operation = $arg;
|
||||
return null;
|
||||
}
|
||||
return $arg;
|
||||
}, $args);
|
||||
$args = array_filter($args);
|
||||
$this->arguments .= ' ' . implode(' ', array_map('static::escape', $args));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|Traversable|string $arg a single object or something traversable
|
||||
*
|
||||
@@ -468,7 +504,7 @@ class ApiGen extends BaseTask implements CommandInterface
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->command . $this->arguments;
|
||||
return "$this->command $this->operation$this->arguments";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,8 +31,6 @@ use Robo\Common\BuilderAwareTrait;
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @method to(string) location to store extracted files
|
||||
*/
|
||||
class Extract extends BaseTask implements BuilderAwareInterface
|
||||
{
|
||||
|
||||
+30
-129
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Robo\Common\ExecTrait;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Contract\SimulatedInterface;
|
||||
@@ -41,31 +42,6 @@ class Exec extends BaseTask implements CommandInterface, PrintedInterface, Simul
|
||||
*/
|
||||
protected $command;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $background = false;
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $timeout = null;
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $idleTimeout = null;
|
||||
|
||||
/**
|
||||
* @var null|array
|
||||
*/
|
||||
protected $env = null;
|
||||
|
||||
/**
|
||||
* @var Process
|
||||
*/
|
||||
protected $process;
|
||||
|
||||
/**
|
||||
* @param string|\Robo\Contract\CommandInterface $command
|
||||
*/
|
||||
@@ -75,11 +51,11 @@ class Exec extends BaseTask implements CommandInterface, PrintedInterface, Simul
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
*/
|
||||
public function getCommand()
|
||||
public function __destruct()
|
||||
{
|
||||
return trim($this->command . $this->arguments);
|
||||
$this->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,116 +63,26 @@ class Exec extends BaseTask implements CommandInterface, PrintedInterface, Simul
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function background()
|
||||
public function background($arg = true)
|
||||
{
|
||||
self::$instances[] = $this;
|
||||
$this->background = true;
|
||||
$this->background = $arg;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop command if it runs longer then $timeout in seconds
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function timeout($timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops command if it does not output something for a while
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function idleTimeout($timeout)
|
||||
{
|
||||
$this->idleTimeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the environment variables for the command
|
||||
*
|
||||
* @param array $env
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function env(array $env)
|
||||
{
|
||||
$this->env = $env;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->stop();
|
||||
}
|
||||
|
||||
protected function stop()
|
||||
{
|
||||
if ($this->background && $this->process->isRunning()) {
|
||||
$this->process->stop();
|
||||
$this->printTaskInfo("Stopped {command}", ['command' => $this->getCommand()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $context
|
||||
*/
|
||||
protected function printAction($context = [])
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$dir = $this->workingDirectory ? " in {dir}" : "";
|
||||
$this->printTaskInfo("Running {command}$dir", ['command' => $command, 'dir' => $this->workingDirectory] + $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
protected function getCommandDescription()
|
||||
{
|
||||
$this->printAction();
|
||||
$this->process = new Process($this->getCommand());
|
||||
$this->process->setTimeout($this->timeout);
|
||||
$this->process->setIdleTimeout($this->idleTimeout);
|
||||
$this->process->setWorkingDirectory($this->workingDirectory);
|
||||
|
||||
if (isset($this->env)) {
|
||||
$this->process->setEnv($this->env);
|
||||
}
|
||||
|
||||
if (!$this->background and !$this->isPrinted) {
|
||||
$this->startTimer();
|
||||
$this->process->run();
|
||||
$this->stopTimer();
|
||||
return new Result($this, $this->process->getExitCode(), $this->process->getOutput(), ['time' => $this->getExecutionTime()]);
|
||||
}
|
||||
|
||||
if (!$this->background and $this->isPrinted) {
|
||||
$this->startTimer();
|
||||
$this->process->run(
|
||||
function ($type, $buffer) {
|
||||
$progressWasVisible = $this->hideTaskProgress();
|
||||
print($buffer);
|
||||
$this->showTaskProgress($progressWasVisible);
|
||||
}
|
||||
);
|
||||
$this->stopTimer();
|
||||
return new Result($this, $this->process->getExitCode(), $this->process->getOutput(), ['time' => $this->getExecutionTime()]);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->process->start();
|
||||
} catch (\Exception $e) {
|
||||
return Result::fromException($this, $e);
|
||||
}
|
||||
return Result::success($this);
|
||||
return $this->getCommand();
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return trim($this->command . $this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,6 +101,21 @@ class Exec extends BaseTask implements CommandInterface, PrintedInterface, Simul
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// TODO: Symfony 4 requires that we supply the working directory.
|
||||
$result_data = $this->execute(new Process($this->getCommand(), getcwd()));
|
||||
return new Result(
|
||||
$this,
|
||||
$result_data->getExitCode(),
|
||||
$result_data->getMessage(),
|
||||
$result_data->getData()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (function_exists('pcntl_signal')) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Robo\Task\CommandStack;
|
||||
use Robo\Task\Base;
|
||||
|
||||
/**
|
||||
* Execute commands one by one in stack.
|
||||
@@ -18,8 +17,6 @@ use Robo\Task\Base;
|
||||
*
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @method $this stopOnFail()
|
||||
*/
|
||||
class ExecStack extends CommandStack
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Robo\Common\ProgressIndicatorAwareTrait;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Result;
|
||||
@@ -22,10 +20,6 @@ use Symfony\Component\Process\Process;
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @method \Robo\Task\Base\ParallelExec timeout(int $timeout) stops process if it runs longer then `$timeout` (seconds)
|
||||
* @method \Robo\Task\Base\ParallelExec idleTimeout(int $timeout) stops process if it does not output for time longer then `$timeout` (seconds)
|
||||
*/
|
||||
class ParallelExec extends BaseTask implements CommandInterface, PrintedInterface
|
||||
{
|
||||
@@ -46,6 +40,11 @@ class ParallelExec extends BaseTask implements CommandInterface, PrintedInterfac
|
||||
*/
|
||||
protected $idleTimeout = null;
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $waitInterval = 0;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@@ -77,11 +76,14 @@ class ParallelExec extends BaseTask implements CommandInterface, PrintedInterfac
|
||||
*/
|
||||
public function process($command)
|
||||
{
|
||||
$this->processes[] = new Process($this->receiveCommand($command));
|
||||
// TODO: Symfony 4 requires that we supply the working directory.
|
||||
$this->processes[] = new Process($this->receiveCommand($command), getcwd());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops process if it runs longer then `$timeout` (seconds).
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return $this
|
||||
@@ -93,6 +95,8 @@ class ParallelExec extends BaseTask implements CommandInterface, PrintedInterfac
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops process if it does not output for time longer then `$timeout` (seconds).
|
||||
*
|
||||
* @param int $idleTimeout
|
||||
*
|
||||
* @return $this
|
||||
@@ -103,6 +107,20 @@ class ParallelExec extends BaseTask implements CommandInterface, PrintedInterfac
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parallel processing will wait `$waitInterval` seconds after launching each process and before
|
||||
* the next one.
|
||||
*
|
||||
* @param int $waitInterval
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function waitInterval($waitInterval)
|
||||
{
|
||||
$this->waitInterval = $waitInterval;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -124,16 +142,20 @@ class ParallelExec extends BaseTask implements CommandInterface, PrintedInterfac
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
foreach ($this->processes as $process) {
|
||||
$process->setIdleTimeout($this->idleTimeout);
|
||||
$process->setTimeout($this->timeout);
|
||||
$process->start();
|
||||
$this->printTaskInfo($process->getCommandLine());
|
||||
}
|
||||
|
||||
$this->startProgressIndicator();
|
||||
$running = $this->processes;
|
||||
$running = [];
|
||||
$queue = $this->processes;
|
||||
$nextTime = time();
|
||||
while (true) {
|
||||
if (($nextTime <= time()) && !empty($queue)) {
|
||||
$process = array_shift($queue);
|
||||
$process->setIdleTimeout($this->idleTimeout);
|
||||
$process->setTimeout($this->timeout);
|
||||
$process->start();
|
||||
$this->printTaskInfo($process->getCommandLine());
|
||||
$running[] = $process;
|
||||
$nextTime = time() + $this->waitInterval;
|
||||
}
|
||||
foreach ($running as $k => $process) {
|
||||
try {
|
||||
$process->checkTimeout();
|
||||
@@ -152,7 +174,7 @@ class ParallelExec extends BaseTask implements CommandInterface, PrintedInterfac
|
||||
unset($running[$k]);
|
||||
}
|
||||
}
|
||||
if (empty($running)) {
|
||||
if (empty($running) && empty($queue)) {
|
||||
break;
|
||||
}
|
||||
usleep(1000);
|
||||
|
||||
@@ -6,7 +6,6 @@ use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Executes Symfony Command
|
||||
|
||||
@@ -13,6 +13,9 @@ trait loadTasks
|
||||
return $this->task(Exec::class, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ExecStack
|
||||
*/
|
||||
protected function taskExecStack()
|
||||
{
|
||||
return $this->task(ExecStack::class);
|
||||
|
||||
@@ -7,16 +7,38 @@ use Robo\Contract\InflectionInterface;
|
||||
use Robo\Common\TaskIO;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Robo\Common\ProgressIndicatorAwareTrait;
|
||||
use Robo\Contract\ConfigAwareInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Robo\Contract\OutputAwareInterface;
|
||||
|
||||
abstract class BaseTask implements TaskInterface, LoggerAwareInterface, ConfigAwareInterface, ProgressIndicatorAwareInterface, InflectionInterface
|
||||
abstract class BaseTask implements TaskInterface, LoggerAwareInterface, VerbosityThresholdInterface, ConfigAwareInterface, ProgressIndicatorAwareInterface, InflectionInterface
|
||||
{
|
||||
use TaskIO; // uses LoggerAwareTrait and ConfigAwareTrait
|
||||
use TaskIO; // uses LoggerAwareTrait, VerbosityThresholdTrait and ConfigAwareTrait
|
||||
use ProgressIndicatorAwareTrait;
|
||||
use InflectionTrait;
|
||||
|
||||
/**
|
||||
* ConfigAwareInterface uses this to decide where configuration
|
||||
* items come from. Default is this prefix + class name + key,
|
||||
* e.g. `task.Remote.Ssh.remoteDir`.
|
||||
*/
|
||||
protected static function configPrefix()
|
||||
{
|
||||
return 'task.';
|
||||
}
|
||||
|
||||
/**
|
||||
* ConfigAwareInterface uses this to decide where configuration
|
||||
* items come from. Default is this prefix + class name + key,
|
||||
* e.g. `task.Ssh.remoteDir`.
|
||||
*/
|
||||
protected static function configPostfix()
|
||||
{
|
||||
return '.settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -31,5 +53,8 @@ abstract class BaseTask implements TaskInterface, LoggerAwareInterface, ConfigAw
|
||||
if ($child instanceof ConfigAwareInterface && $this->getConfig()) {
|
||||
$child->setConfig($this->getConfig());
|
||||
}
|
||||
if ($child instanceof VerbosityThresholdInterface && $this->outputAdapter()) {
|
||||
$child->setOutputAdapter($this->outputAdapter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Task\Bower;
|
||||
|
||||
use Robo\Task\Bower;
|
||||
use Robo\Contract\CommandInterface;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Task\Bower;
|
||||
|
||||
use Robo\Task\Bower;
|
||||
|
||||
/**
|
||||
* Bower Update
|
||||
*
|
||||
|
||||
@@ -6,7 +6,6 @@ use Robo\Common\ExecCommand;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Result;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Common\DynamicParams;
|
||||
use Robo\Exception\TaskException;
|
||||
|
||||
abstract class CommandStack extends BaseTask implements CommandInterface, PrintedInterface
|
||||
@@ -60,8 +59,8 @@ abstract class CommandStack extends BaseTask implements CommandInterface, Printe
|
||||
$command = implode(' ', array_filter($command));
|
||||
}
|
||||
|
||||
$command = $this->executable . ' ' . $this->stripExecutableFromCommand($command);
|
||||
array_push($this->exec, trim($command));
|
||||
$command = $this->executable . ' ' . $this->stripExecutableFromCommand($command);
|
||||
$this->exec[] = trim($command);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -105,19 +104,31 @@ abstract class CommandStack extends BaseTask implements CommandInterface, Printe
|
||||
if (empty($this->exec)) {
|
||||
throw new TaskException($this, 'You must add at least one command');
|
||||
}
|
||||
if (!$this->stopOnFail) {
|
||||
// If 'stopOnFail' is not set, or if there is only one command to run,
|
||||
// then execute the single command to run.
|
||||
if (!$this->stopOnFail || (count($this->exec) == 1)) {
|
||||
$this->printTaskInfo('{command}', ['command' => $this->getCommand()]);
|
||||
return $this->executeCommand($this->getCommand());
|
||||
}
|
||||
|
||||
// When executing multiple commands in 'stopOnFail' mode, run them
|
||||
// one at a time so that the result will have the exact command
|
||||
// that failed available to the caller. This is at the expense of
|
||||
// losing the output from all successful commands.
|
||||
$data = [];
|
||||
$message = '';
|
||||
$result = null;
|
||||
foreach ($this->exec as $command) {
|
||||
$this->printTaskInfo("Executing {command}", ['command' => $command]);
|
||||
$result = $this->executeCommand($command);
|
||||
$result->accumulateExecutionTime($data);
|
||||
$message = $result->accumulateMessage($message);
|
||||
$data = $result->mergeData($data);
|
||||
if (!$result->wasSuccessful()) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return Result::success($this);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
+184
-81
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
namespace Robo\Task\Composer;
|
||||
|
||||
use Robo\Robo;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Task\BaseTask;
|
||||
|
||||
abstract class Base extends BaseTask
|
||||
abstract class Base extends BaseTask implements CommandInterface
|
||||
{
|
||||
use \Robo\Common\ExecOneCommand;
|
||||
|
||||
@@ -14,6 +14,11 @@ abstract class Base extends BaseTask
|
||||
*/
|
||||
protected $command = '';
|
||||
|
||||
/**
|
||||
* @var boolena
|
||||
*/
|
||||
protected $built = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -24,11 +29,6 @@ abstract class Base extends BaseTask
|
||||
*/
|
||||
protected $dev;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $optimizeAutoloader;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -37,7 +37,7 @@ abstract class Base extends BaseTask
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $dir;
|
||||
protected $nointeraction;
|
||||
|
||||
/**
|
||||
* Action to use
|
||||
@@ -46,72 +46,6 @@ abstract class Base extends BaseTask
|
||||
*/
|
||||
protected $action = '';
|
||||
|
||||
/**
|
||||
* adds `prefer-dist` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function preferDist()
|
||||
{
|
||||
$this->prefer = '--prefer-dist';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `prefer-source` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function preferSource()
|
||||
{
|
||||
$this->prefer = '--prefer-source';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `no-dev` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noDev()
|
||||
{
|
||||
$this->dev = '--no-dev';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `no-ansi` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noAnsi()
|
||||
{
|
||||
$this->ansi = '--no-ansi';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `ansi` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function ansi()
|
||||
{
|
||||
$this->ansi = '--ansi';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `optimize-autoloader` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function optimizeAutoloader()
|
||||
{
|
||||
$this->optimizeAutoloader = '--optimize-autoloader';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $pathToComposer
|
||||
*
|
||||
@@ -128,18 +62,187 @@ abstract class Base extends BaseTask
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `prefer-dist` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function preferDist($preferDist = true)
|
||||
{
|
||||
if (!$preferDist) {
|
||||
return $this->preferSource();
|
||||
}
|
||||
$this->prefer = '--prefer-dist';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `prefer-source` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function preferSource()
|
||||
{
|
||||
$this->prefer = '--prefer-source';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `dev` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function dev($dev = true)
|
||||
{
|
||||
if (!$dev) {
|
||||
return $this->noDev();
|
||||
}
|
||||
$this->dev = '--dev';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `no-dev` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noDev()
|
||||
{
|
||||
$this->dev = '--no-dev';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `ansi` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function ansi($ansi = true)
|
||||
{
|
||||
if (!$ansi) {
|
||||
return $this->noAnsi();
|
||||
}
|
||||
$this->ansi = '--ansi';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `no-ansi` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noAnsi()
|
||||
{
|
||||
$this->ansi = '--no-ansi';
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function interaction($interaction = true)
|
||||
{
|
||||
if (!$interaction) {
|
||||
return $this->noInteraction();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `no-interaction` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noInteraction()
|
||||
{
|
||||
$this->nointeraction = '--no-interaction';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `optimize-autoloader` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function optimizeAutoloader($optimize = true)
|
||||
{
|
||||
if ($optimize) {
|
||||
$this->option('--optimize-autoloader');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `ignore-platform-reqs` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function ignorePlatformRequirements($ignore = true)
|
||||
{
|
||||
$this->option('--ignore-platform-reqs');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* disable plugins
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function disablePlugins($disable = true)
|
||||
{
|
||||
if ($disable) {
|
||||
$this->option('--no-plugins');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* skip scripts
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noScripts($disable = true)
|
||||
{
|
||||
if ($disable) {
|
||||
$this->option('--no-scripts');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `--working-dir $dir` option to composer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function workingDir($dir)
|
||||
{
|
||||
$this->option("--working-dir", $dir);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy class fields into command options as directed.
|
||||
*/
|
||||
public function buildCommand()
|
||||
{
|
||||
if (!isset($this->ansi) && $this->getConfig()->get(\Robo\Config\Config::DECORATED)) {
|
||||
$this->ansi();
|
||||
}
|
||||
if (!isset($this->nointeraction) && !$this->getConfig()->get(\Robo\Config\Config::INTERACTIVE)) {
|
||||
$this->noInteraction();
|
||||
}
|
||||
$this->option($this->prefer)
|
||||
->option($this->dev)
|
||||
->option($this->nointeraction)
|
||||
->option($this->ansi);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
if (!isset($this->ansi) && $this->getConfig()->isDecorated()) {
|
||||
$this->ansi();
|
||||
if (!$this->built) {
|
||||
$this->buildCommand();
|
||||
$this->built = true;
|
||||
}
|
||||
$this->option($this->prefer)
|
||||
->option($this->dev)
|
||||
->option($this->optimizeAutoloader)
|
||||
->option($this->ansi);
|
||||
return "{$this->command} {$this->action}{$this->arguments}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace Robo\Task\Composer;
|
||||
|
||||
/**
|
||||
* Composer Config
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple execution
|
||||
* $this->taskComposerConfig()->set('bin-dir', 'bin/')->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Config extends Base
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $action = 'config';
|
||||
|
||||
/**
|
||||
* Set a configuration value
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->arg($key);
|
||||
$this->arg($value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operate on the global repository
|
||||
* @return $this
|
||||
*/
|
||||
public function useGlobal($useGlobal = true)
|
||||
{
|
||||
if ($useGlobal) {
|
||||
$this->option('global');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function repository($id, $uri, $repoType = 'vcs')
|
||||
{
|
||||
$this->arg("repositories.$id");
|
||||
$this->arg($repoType);
|
||||
$this->arg($uri);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function removeRepository($id)
|
||||
{
|
||||
$this->option('unset', "repositories.$id");
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function disableRepository($id)
|
||||
{
|
||||
$this->arg("repositories.$id");
|
||||
$this->arg('false');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function enableRepository($id)
|
||||
{
|
||||
$this->arg("repositories.$id");
|
||||
$this->arg('true');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$this->printTaskInfo('Configuring composer.json: {command}', ['command' => $command]);
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
namespace Robo\Task\Composer;
|
||||
|
||||
/**
|
||||
* Composer CreateProject
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple execution
|
||||
* $this->taskComposerCreateProject()->source('foo/bar')->target('myBar')->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class CreateProject extends Base
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $action = 'create-project';
|
||||
|
||||
protected $source;
|
||||
protected $target = '';
|
||||
protected $version = '';
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function source($source)
|
||||
{
|
||||
$this->source = $source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function target($target)
|
||||
{
|
||||
$this->target = $target;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function version($version)
|
||||
{
|
||||
$this->version = $version;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function keepVcs($keep = true)
|
||||
{
|
||||
if ($keep) {
|
||||
$this->option('--keep-vcs');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function noInstall($noInstall = true)
|
||||
{
|
||||
if ($noInstall) {
|
||||
$this->option('--no-install');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function repository($repository)
|
||||
{
|
||||
if (!empty($repository)) {
|
||||
$this->option('repository', $repository);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function stability($stability)
|
||||
{
|
||||
if (!empty($stability)) {
|
||||
$this->option('stability', $stability);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function buildCommand()
|
||||
{
|
||||
$this->arg($this->source);
|
||||
if (!empty($this->target)) {
|
||||
$this->arg($this->target);
|
||||
}
|
||||
if (!empty($this->version)) {
|
||||
$this->arg($this->version);
|
||||
}
|
||||
|
||||
return parent::buildCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$this->printTaskInfo('Creating project: {command}', ['command' => $command]);
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
}
|
||||
@@ -42,21 +42,14 @@ class DumpAutoload extends Base
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function optimize()
|
||||
public function optimize($optimize = true)
|
||||
{
|
||||
$this->optimize = "--optimize";
|
||||
if ($optimize) {
|
||||
$this->option("--optimize");
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
$this->option($this->optimize);
|
||||
return parent::getCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
namespace Robo\Task\Composer;
|
||||
|
||||
/**
|
||||
* Composer Init
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple execution
|
||||
* $this->taskComposerInit()->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Init extends Base
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $action = 'init';
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function projectName($projectName)
|
||||
{
|
||||
$this->option('name', $projectName);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function description($description)
|
||||
{
|
||||
$this->option('description', $description);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function author($author)
|
||||
{
|
||||
$this->option('author', $author);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function projectType($type)
|
||||
{
|
||||
$this->option('type', $type);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function homepage($homepage)
|
||||
{
|
||||
$this->option('homepage', $homepage);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'require' is a keyword, so it cannot be a method name.
|
||||
* @return $this
|
||||
*/
|
||||
public function dependency($project, $version = null)
|
||||
{
|
||||
if (isset($version)) {
|
||||
$project .= ":$version";
|
||||
}
|
||||
$this->option('require', $project);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function stability($stability)
|
||||
{
|
||||
$this->option('stability', $stability);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function license($license)
|
||||
{
|
||||
$this->option('license', $license);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function repository($repository)
|
||||
{
|
||||
$this->option('repository', $repository);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$this->printTaskInfo('Creating composer.json: {command}', ['command' => $command]);
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
namespace Robo\Task\Composer;
|
||||
|
||||
/**
|
||||
* Composer Validate
|
||||
* Composer Remove
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple execution
|
||||
* $this->taskComposerValidate()->run();
|
||||
* $this->taskComposerRemove()->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
@@ -21,45 +21,55 @@ class Remove extends Base
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function dev()
|
||||
public function dev($dev = true)
|
||||
{
|
||||
$this->option('--dev');
|
||||
if ($dev) {
|
||||
$this->option('--dev');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function noProgress()
|
||||
public function noProgress($noProgress = true)
|
||||
{
|
||||
$this->option('--no-progress');
|
||||
if ($noProgress) {
|
||||
$this->option('--no-progress');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function noUpdate()
|
||||
public function noUpdate($noUpdate = true)
|
||||
{
|
||||
$this->option('--no-update');
|
||||
if ($noUpdate) {
|
||||
$this->option('--no-update');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function updateNoDev()
|
||||
public function updateNoDev($updateNoDev = true)
|
||||
{
|
||||
$this->option('--update-no-dev');
|
||||
if ($updateNoDev) {
|
||||
$this->option('--update-no-dev');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function noUpdateWithDependencies()
|
||||
public function noUpdateWithDependencies($updateWithDependencies = true)
|
||||
{
|
||||
$this->option('--no-update-with-dependencies');
|
||||
if ($updateWithDependencies) {
|
||||
$this->option('--no-update-with-dependencies');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace Robo\Task\Composer;
|
||||
|
||||
/**
|
||||
* Composer Require
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple execution
|
||||
* $this->taskComposerRequire()->dependency('foo/bar', '^.2.4.8')->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class RequireDependency extends Base
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $action = 'require';
|
||||
|
||||
/**
|
||||
* 'require' is a keyword, so it cannot be a method name.
|
||||
* @return $this
|
||||
*/
|
||||
public function dependency($project, $version = null)
|
||||
{
|
||||
$project = (array)$project;
|
||||
|
||||
if (isset($version)) {
|
||||
$project = array_map(
|
||||
function ($item) use ($version) {
|
||||
return "$item:$version";
|
||||
},
|
||||
$project
|
||||
);
|
||||
}
|
||||
$this->args($project);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$this->printTaskInfo('Requiring packages: {command}', ['command' => $command]);
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
}
|
||||
@@ -18,90 +18,61 @@ class Validate extends Base
|
||||
*/
|
||||
protected $action = 'validate';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $noCheckAll;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $noCheckLock;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $noCheckPublish;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $withDependencies;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $strict;
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function noCheckAll()
|
||||
public function noCheckAll($noCheckAll = true)
|
||||
{
|
||||
$this->noCheckAll = '--no-check-all';
|
||||
if ($noCheckAll) {
|
||||
$this->option('--no-check-all');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function noCheckLock()
|
||||
public function noCheckLock($noCheckLock = true)
|
||||
{
|
||||
$this->noCheckLock = '--no-check-lock';
|
||||
if ($noCheckLock) {
|
||||
$this->option('--no-check-lock');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function noCheckPublish()
|
||||
public function noCheckPublish($noCheckPublish = true)
|
||||
{
|
||||
$this->noCheckPublish = '--no-check-publish';
|
||||
if ($noCheckPublish) {
|
||||
$this->option('--no-check-publish');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function withDependencies()
|
||||
public function withDependencies($withDependencies = true)
|
||||
{
|
||||
$this->withDependencies = '--with-dependencies';
|
||||
if ($withDependencies) {
|
||||
$this->option('--with-dependencies');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function strict()
|
||||
public function strict($strict = true)
|
||||
{
|
||||
$this->strict = '--strict';
|
||||
if ($strict) {
|
||||
$this->option('--strict');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
$this->option($this->noCheckAll);
|
||||
$this->option($this->noCheckLock);
|
||||
$this->option($this->noCheckPublish);
|
||||
$this->option($this->withDependencies);
|
||||
$this->option($this->strict);
|
||||
|
||||
return parent::getCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -33,6 +33,26 @@ trait loadTasks
|
||||
return $this->task(DumpAutoload::class, $pathToComposer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $pathToComposer
|
||||
*
|
||||
* @return Init
|
||||
*/
|
||||
protected function taskComposerInit($pathToComposer = null)
|
||||
{
|
||||
return $this->task(Init::class, $pathToComposer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $pathToComposer
|
||||
*
|
||||
* @return Init
|
||||
*/
|
||||
protected function taskComposerConfig($pathToComposer = null)
|
||||
{
|
||||
return $this->task(Config::class, $pathToComposer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $pathToComposer
|
||||
*
|
||||
@@ -52,4 +72,24 @@ trait loadTasks
|
||||
{
|
||||
return $this->task(Remove::class, $pathToComposer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $pathToComposer
|
||||
*
|
||||
* @return Remove
|
||||
*/
|
||||
protected function taskComposerRequire($pathToComposer = null)
|
||||
{
|
||||
return $this->task(RequireDependency::class, $pathToComposer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $pathToComposer
|
||||
*
|
||||
* @return Remove
|
||||
*/
|
||||
protected function taskComposerCreateProject($pathToComposer = null)
|
||||
{
|
||||
return $this->task(CreateProject::class, $pathToComposer);
|
||||
}
|
||||
}
|
||||
|
||||
+78
-23
@@ -2,10 +2,7 @@
|
||||
namespace Robo\Task\Development;
|
||||
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Task\File\Replace;
|
||||
use Robo\Task\Filesystem;
|
||||
use Robo\Result;
|
||||
use Robo\Task\Development;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Common\BuilderAwareTrait;
|
||||
|
||||
@@ -33,10 +30,6 @@ use Robo\Common\BuilderAwareTrait;
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @method Development\Changelog filename(string $filename)
|
||||
* @method Development\Changelog anchor(string $anchor)
|
||||
* @method Development\Changelog version(string $version)
|
||||
*/
|
||||
class Changelog extends BaseTask implements BuilderAwareInterface
|
||||
{
|
||||
@@ -62,6 +55,16 @@ class Changelog extends BaseTask implements BuilderAwareInterface
|
||||
*/
|
||||
protected $version = "";
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $body = "";
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $header = "";
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
@@ -73,6 +76,32 @@ class Changelog extends BaseTask implements BuilderAwareInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the changelog body text.
|
||||
*
|
||||
* This method permits the raw changelog text to be set directly If this is set, $this->log changes will be ignored.
|
||||
*
|
||||
* @param string $body
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBody($body)
|
||||
{
|
||||
$this->body = $body;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $header
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHeader($header)
|
||||
{
|
||||
$this->header = $header;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $item
|
||||
*
|
||||
@@ -149,20 +178,17 @@ class Changelog extends BaseTask implements BuilderAwareInterface
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (empty($this->log)) {
|
||||
return Result::error($this, "Changelog is empty");
|
||||
if (empty($this->body)) {
|
||||
if (empty($this->log)) {
|
||||
return Result::error($this, "Changelog is empty");
|
||||
}
|
||||
$this->body = $this->generateBody();
|
||||
}
|
||||
$text = implode(
|
||||
"\n",
|
||||
array_map(
|
||||
function ($i) {
|
||||
return "* $i *" . date('Y-m-d') . "*";
|
||||
},
|
||||
$this->log
|
||||
)
|
||||
) . "\n";
|
||||
$ver = "#### {$this->version}\n\n";
|
||||
$text = $ver . $text;
|
||||
if (empty($this->header)) {
|
||||
$this->header = $this->generateHeader();
|
||||
}
|
||||
|
||||
$text = $this->header . $this->body;
|
||||
|
||||
if (!file_exists($this->filename)) {
|
||||
$this->printTaskInfo('Creating {filename}', ['filename' => $this->filename]);
|
||||
@@ -174,13 +200,13 @@ class Changelog extends BaseTask implements BuilderAwareInterface
|
||||
|
||||
/** @var \Robo\Result $result */
|
||||
// trying to append to changelog for today
|
||||
$result = $this->collectionBuilder()->taskReplace($this->filename)
|
||||
->from($ver)
|
||||
$result = $this->collectionBuilder()->taskReplaceInFile($this->filename)
|
||||
->from($this->header)
|
||||
->to($text)
|
||||
->run();
|
||||
|
||||
if (!isset($result['replaced']) || !$result['replaced']) {
|
||||
$result = $this->collectionBuilder()->taskReplace($this->filename)
|
||||
$result = $this->collectionBuilder()->taskReplaceInFile($this->filename)
|
||||
->from($this->anchor)
|
||||
->to($this->anchor . "\n\n" . $text)
|
||||
->run();
|
||||
@@ -188,4 +214,33 @@ class Changelog extends BaseTask implements BuilderAwareInterface
|
||||
|
||||
return new Result($this, $result->getExitCode(), $result->getMessage(), $this->log);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Result|string
|
||||
*/
|
||||
protected function generateBody()
|
||||
{
|
||||
$text = implode("\n", array_map([$this, 'processLogRow'], $this->log));
|
||||
$text .= "\n";
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function generateHeader()
|
||||
{
|
||||
return "#### {$this->version}\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $i
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function processLogRow($i)
|
||||
{
|
||||
return "* $i *" . date('Y-m-d') . "*";
|
||||
}
|
||||
}
|
||||
|
||||
+34
-21
@@ -2,10 +2,7 @@
|
||||
namespace Robo\Task\Development;
|
||||
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Task\File\Write;
|
||||
use Robo\Task\Filesystem;
|
||||
use Robo\Result;
|
||||
use Robo\Task\Development;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Common\BuilderAwareTrait;
|
||||
|
||||
@@ -41,24 +38,6 @@ use Robo\Common\BuilderAwareTrait;
|
||||
* return strpos($r->name, 'save')===0 ? "[Saves to the database]\n" . $text : $text;
|
||||
* })->run();
|
||||
* ```
|
||||
*
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc docClass(string $classname) put a class you want to be documented
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc filterMethods(\Closure $func) using callback function filter out methods that won't be documented
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc filterClasses(\Closure $func) using callback function filter out classes that won't be documented
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc filterProperties(\Closure $func) using callback function filter out properties that won't be documented
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processClass(\Closure $func) post-process class documentation
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processClassSignature(\Closure $func) post-process class signature. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processClassDocBlock(\Closure $func) post-process class docblock contents. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processMethod(\Closure $func) post-process method documentation. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processMethodSignature(\Closure $func) post-process method signature. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processMethodDocBlock(\Closure $func) post-process method docblock contents. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processProperty(\Closure $func) post-process property documentation. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processPropertySignature(\Closure $func) post-process property signature. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc processPropertyDocBlock(\Closure $func) post-process property docblock contents. Provide *false* to skip.
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc reorder(\Closure $func) use a function to reorder classes
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc reorderMethods(\Closure $func) use a function to reorder methods in class
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc prepend($text) inserts text into beginning of markdown file
|
||||
* @method \Robo\Task\Development\GenerateMarkdownDoc append($text) inserts text in the end of markdown file
|
||||
*/
|
||||
class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
{
|
||||
@@ -190,6 +169,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a class you want to be documented.
|
||||
*
|
||||
* @param string $item
|
||||
*
|
||||
* @return $this
|
||||
@@ -201,6 +182,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Using a callback function filter out methods that won't be documented.
|
||||
*
|
||||
* @param callable $filterMethods
|
||||
*
|
||||
* @return $this
|
||||
@@ -212,6 +195,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Using a callback function filter out classes that won't be documented.
|
||||
*
|
||||
* @param callable $filterClasses
|
||||
*
|
||||
* @return $this
|
||||
@@ -223,6 +208,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Using a callback function filter out properties that won't be documented.
|
||||
*
|
||||
* @param callable $filterProperties
|
||||
*
|
||||
* @return $this
|
||||
@@ -234,6 +221,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process class documentation.
|
||||
*
|
||||
* @param callable $processClass
|
||||
*
|
||||
* @return $this
|
||||
@@ -245,6 +234,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process class signature. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processClassSignature
|
||||
*
|
||||
* @return $this
|
||||
@@ -256,6 +247,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process class docblock contents. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processClassDocBlock
|
||||
*
|
||||
* @return $this
|
||||
@@ -267,6 +260,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process method documentation. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processMethod
|
||||
*
|
||||
* @return $this
|
||||
@@ -278,6 +273,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process method signature. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processMethodSignature
|
||||
*
|
||||
* @return $this
|
||||
@@ -289,6 +286,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process method docblock contents. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processMethodDocBlock
|
||||
*
|
||||
* @return $this
|
||||
@@ -300,6 +299,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process property documentation. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processProperty
|
||||
*
|
||||
* @return $this
|
||||
@@ -311,6 +312,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process property signature. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processPropertySignature
|
||||
*
|
||||
* @return $this
|
||||
@@ -322,6 +325,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process property docblock contents. Provide *false* to skip.
|
||||
*
|
||||
* @param callable|false $processPropertyDocBlock
|
||||
*
|
||||
* @return $this
|
||||
@@ -333,6 +338,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a function to reorder classes.
|
||||
*
|
||||
* @param callable $reorder
|
||||
*
|
||||
* @return $this
|
||||
@@ -344,6 +351,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a function to reorder methods in class.
|
||||
*
|
||||
* @param callable $reorderMethods
|
||||
*
|
||||
* @return $this
|
||||
@@ -377,6 +386,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts text at the beginning of markdown file.
|
||||
*
|
||||
* @param string $prepend
|
||||
*
|
||||
* @return $this
|
||||
@@ -388,6 +399,8 @@ class GenerateMarkdownDoc extends BaseTask implements BuilderAwareInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts text at the end of markdown file.
|
||||
*
|
||||
* @param string $append
|
||||
*
|
||||
* @return $this
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
namespace Robo\Task\Development;
|
||||
|
||||
use Robo\Task\BaseTask;
|
||||
use Symfony\Component\Process\ProcessUtils;
|
||||
use Robo\Result;
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,9 @@ namespace Robo\Task\Development;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Task\BaseTask;
|
||||
|
||||
/**
|
||||
* @method \Robo\Task\Development\GitHub repo(string)
|
||||
* @method \Robo\Task\Development\GitHub owner(string)
|
||||
*/
|
||||
abstract class GitHub extends BaseTask
|
||||
{
|
||||
const GITHUB_URL = 'https://Api.github.com';
|
||||
const GITHUB_URL = 'https://api.github.com';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@@ -32,6 +28,11 @@ abstract class GitHub extends BaseTask
|
||||
*/
|
||||
protected $owner;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @param string $repo
|
||||
*
|
||||
@@ -95,6 +96,17 @@ abstract class GitHub extends BaseTask
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function accessToken($token)
|
||||
{
|
||||
$this->accessToken = $token;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param array $params
|
||||
@@ -119,6 +131,10 @@ abstract class GitHub extends BaseTask
|
||||
curl_setopt($ch, CURLOPT_USERPWD, $this->user . ':' . $this->password);
|
||||
}
|
||||
|
||||
if (!empty($this->accessToken)) {
|
||||
$url .= "?access_token=" . $this->accessToken;
|
||||
}
|
||||
|
||||
curl_setopt_array(
|
||||
$ch,
|
||||
array(
|
||||
|
||||
+1
-1
@@ -190,7 +190,7 @@ class GitHubRelease extends GitHub
|
||||
[
|
||||
"tag_name" => $this->tag,
|
||||
"target_commitish" => $this->comittish,
|
||||
"name" => $this->tag,
|
||||
"name" => $this->name,
|
||||
"body" => $this->getBody(),
|
||||
"draft" => $this->draft,
|
||||
"prerelease" => $this->prerelease
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
namespace Robo\Task\Development;
|
||||
|
||||
use Robo\Task\BaseTask;
|
||||
use Symfony\Component\Process\ProcessUtils;
|
||||
use Robo\Common\ProcessUtils;
|
||||
use Robo\Result;
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
namespace Robo\Task\Development;
|
||||
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Robo\Common\ProgressIndicatorAwareTrait;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
|
||||
@@ -23,6 +23,8 @@ class SemVer implements TaskInterface
|
||||
|
||||
const REGEX = "/^\-\-\-\n:major:\s(0|[1-9]\d*)\n:minor:\s(0|[1-9]\d*)\n:patch:\s(0|[1-9]\d*)\n:special:\s'([a-zA-z0-9]*\.?(?:0|[1-9]\d*)?)'\n:metadata:\s'((?:0|[1-9]\d*)?(?:\.[a-zA-z0-9\.]*)?)'/";
|
||||
|
||||
const REGEX_STRING = '/^(?<major>[0-9]+)\.(?<minor>[0-9]+)\.(?<patch>[0-9]+)(|-(?<special>[0-9a-zA-Z.]+))(|\+(?<metadata>[0-9a-zA-Z.]+))$/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -62,7 +64,8 @@ class SemVer implements TaskInterface
|
||||
$this->path = $filename;
|
||||
|
||||
if (file_exists($this->path)) {
|
||||
$this->parse();
|
||||
$semverFileContents = file_get_contents($this->path);
|
||||
$this->parseFile($semverFileContents);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +88,12 @@ class SemVer implements TaskInterface
|
||||
return str_replace($search, $replace, $this->format);
|
||||
}
|
||||
|
||||
public function version($version)
|
||||
{
|
||||
$this->parseString($version);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $format
|
||||
*
|
||||
@@ -208,6 +217,9 @@ class SemVer implements TaskInterface
|
||||
*/
|
||||
protected function dump()
|
||||
{
|
||||
if (empty($this->path)) {
|
||||
return true;
|
||||
}
|
||||
extract($this->version);
|
||||
$semver = sprintf(self::SEMVER, $major, $minor, $patch, $special, $metadata);
|
||||
if (is_writeable($this->path) === false || file_put_contents($this->path, $semver) === false) {
|
||||
@@ -216,14 +228,24 @@ class SemVer implements TaskInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function parseString($semverString)
|
||||
{
|
||||
if (!preg_match_all(self::REGEX_STRING, $semverString, $matches)) {
|
||||
throw new TaskException($this, 'Bad semver value: ' . $semverString);
|
||||
}
|
||||
|
||||
$this->version = array_intersect_key($matches, $this->version);
|
||||
$this->version = array_map(function ($item) {
|
||||
return $item[0];
|
||||
}, $this->version);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Robo\Exception\TaskException
|
||||
*/
|
||||
protected function parse()
|
||||
protected function parseFile($semverFileContents)
|
||||
{
|
||||
$output = file_get_contents($this->path);
|
||||
|
||||
if (!preg_match_all(self::REGEX, $output, $matches)) {
|
||||
if (!preg_match_all(self::REGEX, $semverFileContents, $matches)) {
|
||||
throw new TaskException($this, 'Bad semver file.');
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
namespace Robo\Task\Docker;
|
||||
|
||||
use Robo\Common\ExecOneCommand;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Task\BaseTask;
|
||||
|
||||
abstract class Base extends BaseTask implements PrintedInterface
|
||||
abstract class Base extends BaseTask implements CommandInterface, PrintedInterface
|
||||
{
|
||||
use ExecOneCommand;
|
||||
|
||||
@@ -20,7 +21,6 @@ abstract class Base extends BaseTask implements PrintedInterface
|
||||
public function run()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$this->printTaskInfo('Running {command}', ['command' => $command]);
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,12 +64,14 @@ class Exec extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* {@inheritdoc)}
|
||||
*/
|
||||
public function interactive()
|
||||
public function interactive($interactive = true)
|
||||
{
|
||||
$this->option('-i');
|
||||
return $this;
|
||||
if ($interactive) {
|
||||
$this->option('-i');
|
||||
}
|
||||
return parent::interactive($interactive);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -115,12 +115,14 @@ class Run extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* {@inheritdoc)}
|
||||
*/
|
||||
public function interactive()
|
||||
public function interactive($interactive = true)
|
||||
{
|
||||
$this->option('-i');
|
||||
return $this;
|
||||
if ($interactive) {
|
||||
$this->option('-i');
|
||||
}
|
||||
return parent::interactive($interactive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,13 +149,29 @@ class Run extends Base
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set environment variables.
|
||||
* n.b. $this->env($variable, $value) also available here,
|
||||
* inherited from ExecTrait.
|
||||
*
|
||||
* @param array $env
|
||||
* @return type
|
||||
*/
|
||||
public function envVars(array $env)
|
||||
{
|
||||
foreach ($env as $variable => $value) {
|
||||
$this->setDockerEnv($variable, $value);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $variable
|
||||
* @param null|string $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function env($variable, $value = null)
|
||||
protected function setDockerEnv($variable, $value = null)
|
||||
{
|
||||
$env = $value ? "$variable=$value" : $variable;
|
||||
return $this->option("-e", $env);
|
||||
|
||||
@@ -30,10 +30,6 @@ use Robo\Task\BaseTask;
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @method regex(string) regex to match string to be replaced
|
||||
* @method from(string|array) string(s) to be replaced
|
||||
* @method to(string|array) value(s) to be set as a replacement
|
||||
*/
|
||||
class Replace extends BaseTask
|
||||
{
|
||||
@@ -43,12 +39,12 @@ class Replace extends BaseTask
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @var string|string[]
|
||||
*/
|
||||
protected $from;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @var string|string[]
|
||||
*/
|
||||
protected $to;
|
||||
|
||||
@@ -77,7 +73,9 @@ class Replace extends BaseTask
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* String(s) to be replaced.
|
||||
*
|
||||
* @param string|string[] $from
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -88,7 +86,9 @@ class Replace extends BaseTask
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $to
|
||||
* Value(s) to be set as a replacement.
|
||||
*
|
||||
* @param string|string[] $to
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -99,6 +99,8 @@ class Replace extends BaseTask
|
||||
}
|
||||
|
||||
/**
|
||||
* Regex to match string to be replaced.
|
||||
*
|
||||
* @param string $regex
|
||||
*
|
||||
* @return $this
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Robo\Task\File;
|
||||
|
||||
use Robo\Collection\Collection;
|
||||
use Robo\Contract\CompletionInterface;
|
||||
|
||||
/**
|
||||
@@ -36,15 +35,15 @@ class TmpFile extends Write implements CompletionInterface
|
||||
*/
|
||||
public function __construct($filename = 'tmp', $extension = '', $baseDir = '', $includeRandomPart = true)
|
||||
{
|
||||
if (empty($base)) {
|
||||
$base = sys_get_temp_dir();
|
||||
if (empty($baseDir)) {
|
||||
$baseDir = sys_get_temp_dir();
|
||||
}
|
||||
if ($includeRandomPart) {
|
||||
$random = static::randomString();
|
||||
$filename = "{$filename}_{$random}";
|
||||
}
|
||||
$filename .= $extension;
|
||||
parent::__construct("{$base}/{$filename}");
|
||||
parent::__construct("{$baseDir}/{$filename}");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,8 +17,6 @@ use Robo\Task\BaseTask;
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @method append()
|
||||
*/
|
||||
class Write extends BaseTask
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Task\File;
|
||||
|
||||
use Robo\Collection\Temporary;
|
||||
|
||||
trait loadTasks
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,15 @@ class CopyDir extends BaseDir
|
||||
{
|
||||
use ResourceExistenceChecker;
|
||||
|
||||
/**
|
||||
* Explicitly declare our consturctor, so that
|
||||
* our copyDir() method does not look like a php4 constructor.
|
||||
*/
|
||||
public function __construct($dirs)
|
||||
{
|
||||
parent::__construct($dirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
@@ -32,6 +41,11 @@ class CopyDir extends BaseDir
|
||||
*/
|
||||
protected $exclude = [];
|
||||
|
||||
/**
|
||||
* Overwrite destination files newer than source files.
|
||||
*/
|
||||
protected $overwrite = true;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -73,7 +87,20 @@ class CopyDir extends BaseDir
|
||||
*/
|
||||
public function exclude($exclude = [])
|
||||
{
|
||||
$this->exclude = $exclude;
|
||||
$this->exclude = $this->simplifyForCompare($exclude);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destination files newer than source files are overwritten.
|
||||
*
|
||||
* @param bool $overwrite
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function overwrite($overwrite)
|
||||
{
|
||||
$this->overwrite = $overwrite;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -82,10 +109,11 @@ class CopyDir extends BaseDir
|
||||
*
|
||||
* @param string $src Source directory
|
||||
* @param string $dst Destination directory
|
||||
* @param string $parent Parent directory
|
||||
*
|
||||
* @throws \Robo\Exception\TaskException
|
||||
*/
|
||||
protected function copyDir($src, $dst)
|
||||
protected function copyDir($src, $dst, $parent = '')
|
||||
{
|
||||
$dir = @opendir($src);
|
||||
if (false === $dir) {
|
||||
@@ -95,19 +123,40 @@ class CopyDir extends BaseDir
|
||||
mkdir($dst, $this->chmod, true);
|
||||
}
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if (in_array($file, $this->exclude)) {
|
||||
continue;
|
||||
// Support basename and full path exclusion.
|
||||
if ($this->excluded($file, $src, $parent)) {
|
||||
continue;
|
||||
}
|
||||
if (($file !== '.') && ($file !== '..')) {
|
||||
$srcFile = $src . '/' . $file;
|
||||
$destFile = $dst . '/' . $file;
|
||||
if (is_dir($srcFile)) {
|
||||
$this->copyDir($srcFile, $destFile);
|
||||
} else {
|
||||
copy($srcFile, $destFile);
|
||||
}
|
||||
$srcFile = $src . '/' . $file;
|
||||
$destFile = $dst . '/' . $file;
|
||||
if (is_dir($srcFile)) {
|
||||
$this->copyDir($srcFile, $destFile, $parent . $file . DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
$this->fs->copy($srcFile, $destFile, $this->overwrite);
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the current item is excluded.
|
||||
*/
|
||||
protected function excluded($file, $src, $parent)
|
||||
{
|
||||
return
|
||||
($file == '.') ||
|
||||
($file == '..') ||
|
||||
in_array($file, $this->exclude) ||
|
||||
in_array($this->simplifyForCompare($parent . $file), $this->exclude) ||
|
||||
in_array($this->simplifyForCompare($src . DIRECTORY_SEPARATOR . $file), $this->exclude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid problems comparing paths on Windows that may have a
|
||||
* combination of DIRECTORY_SEPARATOR and /.
|
||||
*/
|
||||
protected function simplifyForCompare($item)
|
||||
{
|
||||
return str_replace(DIRECTORY_SEPARATOR, '/', $item);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-12
@@ -1,10 +1,8 @@
|
||||
<?php
|
||||
namespace Robo\Task\Filesystem;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Task\StackBasedTask;
|
||||
use Symfony\Component\Filesystem\Filesystem as sfFilesystem;
|
||||
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Common\BuilderAwareTrait;
|
||||
@@ -29,16 +27,16 @@ use Robo\Common\BuilderAwareTrait;
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @method $this mkdir($dir)
|
||||
* @method $this touch($file)
|
||||
* @method $this copy($from, $to, $force = null)
|
||||
* @method $this chmod($file, $permissions, $umask = null, $recursive = null)
|
||||
* @method $this chgrp($file, $group, $recursive = null)
|
||||
* @method $this chown($file, $user, $recursive = null)
|
||||
* @method $this remove($file)
|
||||
* @method $this rename($from, $to)
|
||||
* @method $this symlink($from, $to)
|
||||
* @method $this mirror($from, $to)
|
||||
* @method $this mkdir(string|array|\Traversable $dir, int $mode = 0777)
|
||||
* @method $this touch(string|array|\Traversable $file, int $time = null, int $atime = null)
|
||||
* @method $this copy(string $from, string $to, bool $force = false)
|
||||
* @method $this chmod(string|array|\Traversable $file, int $permissions, int $umask = 0000, bool $recursive = false)
|
||||
* @method $this chgrp(string|array|\Traversable $file, string $group, bool $recursive = false)
|
||||
* @method $this chown(string|array|\Traversable $file, string $user, bool $recursive = false)
|
||||
* @method $this remove(string|array|\Traversable $file)
|
||||
* @method $this rename(string $from, string $to, bool $force = false)
|
||||
* @method $this symlink(string $from, string $to, bool $copyOnWindows = false)
|
||||
* @method $this mirror(string $from, string $to, \Traversable $iterator = null, array $options = [])
|
||||
*/
|
||||
class FilesystemStack extends StackBasedTask implements BuilderAwareInterface
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Robo\Task\Filesystem;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Collection\Collection;
|
||||
use Robo\Contract\CompletionInterface;
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
namespace Robo\Task\Filesystem;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Collection\Collection;
|
||||
use Robo\Contract\CompletionInterface;
|
||||
use Robo\Contract\RollbackInterface;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Common\BuilderAwareTrait;
|
||||
|
||||
+3
-4
@@ -1,8 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Task\Filesystem;
|
||||
|
||||
use Robo\Collection\Temporary;
|
||||
|
||||
trait loadShortcuts
|
||||
{
|
||||
/**
|
||||
@@ -50,12 +48,13 @@ trait loadShortcuts
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @param bool $overwrite
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function _rename($from, $to)
|
||||
protected function _rename($from, $to, $overwrite = false)
|
||||
{
|
||||
return $this->taskFilesystemStack()->rename($from, $to)->run();
|
||||
return $this->taskFilesystemStack()->rename($from, $to, $overwrite)->run();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Task\Filesystem;
|
||||
|
||||
use Robo\Collection\Temporary;
|
||||
|
||||
trait loadTasks
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Robo\Task\Gulp;
|
||||
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Exception\TaskException;
|
||||
use Symfony\Component\Process\ProcessUtils;
|
||||
use Robo\Common\ProcessUtils;
|
||||
|
||||
abstract class Base extends BaseTask
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
namespace Robo\Task\Gulp;
|
||||
|
||||
use Robo\Task\Gulp;
|
||||
use Robo\Contract\CommandInterface;
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,6 @@ namespace Robo\Task\Remote;
|
||||
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Task\Remote;
|
||||
use Robo\Exception\TaskException;
|
||||
|
||||
/**
|
||||
@@ -44,11 +43,6 @@ use Robo\Exception\TaskException;
|
||||
* $rsync->run();
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @method \Robo\Task\Remote\Rsync fromUser(string $user)
|
||||
* @method \Robo\Task\Remote\Rsync fromHost(string $hostname)
|
||||
* @method \Robo\Task\Remote\Rsync toUser(string $user)
|
||||
* @method \Robo\Task\Remote\Rsync toHost(string $hostname)
|
||||
*/
|
||||
class Rsync extends BaseTask implements CommandInterface
|
||||
{
|
||||
@@ -432,7 +426,6 @@ class Rsync extends BaseTask implements CommandInterface
|
||||
public function run()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$this->printTaskInfo("Running {command}", ['command' => $command]);
|
||||
|
||||
return $this->executeCommand($command);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Robo\Task\Remote;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Task\BaseTask;
|
||||
@@ -41,10 +40,6 @@ use Robo\Contract\SimulatedInterface;
|
||||
* ```php
|
||||
* \Robo\Task\Remote\Ssh::configure('remoteDir', '/some-dir');
|
||||
* ```
|
||||
*
|
||||
* @method $this stopOnFail(bool $stopOnFail) Whether or not to chain commands together with &&
|
||||
* and stop the chain if one command fails
|
||||
* @method $this remoteDir(string $remoteWorkingDirectory) Changes to the given directory before running commands
|
||||
*/
|
||||
class Ssh extends BaseTask implements CommandInterface, SimulatedInterface
|
||||
{
|
||||
@@ -111,6 +106,8 @@ class Ssh extends BaseTask implements CommandInterface, SimulatedInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not to chain commands together with && and stop the chain if one command fails.
|
||||
*
|
||||
* @param bool $stopOnFail
|
||||
*
|
||||
* @return $this
|
||||
@@ -122,6 +119,8 @@ class Ssh extends BaseTask implements CommandInterface, SimulatedInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes to the given directory before running commands.
|
||||
*
|
||||
* @param string $remoteDir
|
||||
*
|
||||
* @return $this
|
||||
@@ -269,6 +268,6 @@ class Ssh extends BaseTask implements CommandInterface, SimulatedInterface
|
||||
$hostSpec = $this->user . '@' . $hostSpec;
|
||||
}
|
||||
|
||||
return sprintf("ssh{$sshOptions} {$hostSpec} '{$command}'");
|
||||
return "ssh{$sshOptions} {$hostSpec} '{$command}'";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ use Robo\Result;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\SimulatedInterface;
|
||||
use Robo\Log\RoboLogLevel;
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\CommandInterface;
|
||||
|
||||
class Simulator extends BaseTask implements CommandInterface
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
namespace Robo\Task;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Contract\TaskInterface;
|
||||
|
||||
/**
|
||||
* Extend StackBasedTask to create a Robo task that
|
||||
@@ -116,7 +114,7 @@ abstract class StackBasedTask extends BaseTask
|
||||
*/
|
||||
protected function printTaskProgress($command, $action)
|
||||
{
|
||||
$this->printTaskInfo('{command} {action}', ['command' => "{$command[1]}", 'action' => json_encode($action)]);
|
||||
$this->printTaskInfo('{command} {action}', ['command' => "{$command[1]}", 'action' => json_encode($action, JSON_UNESCAPED_SLASHES)]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,6 @@ class Behat extends BaseTask implements CommandInterface, PrintedInterface
|
||||
if (!$this->command) {
|
||||
throw new \Robo\Exception\TaskException(__CLASS__, "Neither composer nor phar installation of Behat found");
|
||||
}
|
||||
$this->arg('run');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@ use Robo\Contract\PrintedInterface;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Executes Codeception tests
|
||||
@@ -27,17 +28,7 @@ use Robo\Contract\CommandInterface;
|
||||
class Codecept extends BaseTask implements CommandInterface, PrintedInterface
|
||||
{
|
||||
use \Robo\Common\ExecOneCommand;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $suite = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $test = '';
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -67,7 +58,7 @@ class Codecept extends BaseTask implements CommandInterface, PrintedInterface
|
||||
*/
|
||||
public function suite($suite)
|
||||
{
|
||||
$this->suite = $suite;
|
||||
$this->option(null, $suite);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -78,7 +69,7 @@ class Codecept extends BaseTask implements CommandInterface, PrintedInterface
|
||||
*/
|
||||
public function test($testName)
|
||||
{
|
||||
$this->test = $testName;
|
||||
$this->option(null, $testName);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -241,13 +232,30 @@ class Codecept extends BaseTask implements CommandInterface, PrintedInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function noRebuild()
|
||||
{
|
||||
$this->option("no-rebuild");
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $failGroup
|
||||
* @return $this
|
||||
*/
|
||||
public function failGroup($failGroup)
|
||||
{
|
||||
$this->option('override', "extensions: config: Codeception\\Extension\\RunFailed: fail-group: {$failGroup}");
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
$this->option(null, $this->suite)
|
||||
->option(null, $this->test);
|
||||
return $this->command . $this->arguments;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace Robo\Task\Vcs;
|
||||
|
||||
use Robo\Task\CommandStack;
|
||||
use Symfony\Component\Process\ProcessUtils;
|
||||
use Robo\Common\ProcessUtils;
|
||||
|
||||
/**
|
||||
* Runs Git commands in stack. You can use `stopOnFail()` to point that stack should be terminated on first fail.
|
||||
@@ -45,9 +45,33 @@ class GitStack extends CommandStack
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cloneRepo($repo, $to = "")
|
||||
public function cloneRepo($repo, $to = "", $branch = "")
|
||||
{
|
||||
return $this->exec(['clone', $repo, $to]);
|
||||
$cmd = ['clone', $repo, $to];
|
||||
if (!empty($branch)) {
|
||||
$cmd[] = "--branch $branch";
|
||||
}
|
||||
return $this->exec($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes `git clone` with depth 1 as default
|
||||
*
|
||||
* @param string $repo
|
||||
* @param string $to
|
||||
* @param string $branch
|
||||
* @param int $depth
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cloneShallow($repo, $to = '', $branch = "", $depth = 1)
|
||||
{
|
||||
$cmd = ["clone --depth $depth", $repo, $to];
|
||||
if (!empty($branch)) {
|
||||
$cmd[] = "--branch $branch";
|
||||
}
|
||||
|
||||
return $this->exec($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user