Initial Drupal 11 with DDEV setup
This commit is contained in:
66
vendor/consolidation/robo/src/Collection/CallableTask.php
vendored
Normal file
66
vendor/consolidation/robo/src/Collection/CallableTask.php
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\State\StateAwareInterface;
|
||||
use Robo\State\Data;
|
||||
|
||||
/**
|
||||
* Creates a task wrapper that converts any Callable into an
|
||||
* object that can be used directly with a task collection.
|
||||
*
|
||||
* It is not necessary to use this class directly; Collection will
|
||||
* automatically wrap Callables when they are added.
|
||||
*/
|
||||
class CallableTask implements TaskInterface
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $fn;
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface
|
||||
*/
|
||||
protected $reference;
|
||||
|
||||
public function __construct(callable $fn, TaskInterface $reference)
|
||||
{
|
||||
$this->fn = $fn;
|
||||
$this->reference = $reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$result = call_user_func($this->fn, $this->getState());
|
||||
// If the function returns no result, then count it
|
||||
// as a success.
|
||||
if (!isset($result)) {
|
||||
$result = Result::success($this->reference);
|
||||
}
|
||||
// If the function returns a result, it must either return
|
||||
// a \Robo\Result or an exit code. In the later case, we
|
||||
// convert it to a \Robo\Result.
|
||||
if (!$result instanceof Result) {
|
||||
$result = new Result($this->reference, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\State\Data
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
if ($this->reference instanceof StateAwareInterface) {
|
||||
return $this->reference->getState();
|
||||
}
|
||||
return new Data();
|
||||
}
|
||||
}
|
||||
815
vendor/consolidation/robo/src/Collection/Collection.php
vendored
Normal file
815
vendor/consolidation/robo/src/Collection/Collection.php
vendored
Normal file
@ -0,0 +1,815 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Exception\AbortTasksException;
|
||||
use Robo\Result;
|
||||
use Robo\State\Data;
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Task\StackBasedTask;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Contract\WrappedTaskInterface;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Exception\TaskExitException;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Contract\InflectionInterface;
|
||||
use Robo\State\StateAwareInterface;
|
||||
use Robo\State\StateAwareTrait;
|
||||
|
||||
/**
|
||||
* Group tasks into a collection that run together. Supports
|
||||
* rollback operations for handling error conditions.
|
||||
*
|
||||
* This is an internal class. Clients should use a CollectionBuilder
|
||||
* rather than direct use of the Collection class. @see CollectionBuilder.
|
||||
*
|
||||
* Below, the example FilesystemStack task is added to a collection,
|
||||
* and associated with a rollback task. If any of the operations in
|
||||
* the FilesystemStack, or if any of the other tasks also added to
|
||||
* the task collection should fail, then the rollback function is
|
||||
* called. Here, taskDeleteDir is used to remove partial results
|
||||
* of an unfinished task.
|
||||
*/
|
||||
class Collection extends BaseTask implements CollectionInterface, CommandInterface, StateAwareInterface
|
||||
{
|
||||
use StateAwareTrait;
|
||||
|
||||
/**
|
||||
* @var \Robo\Collection\Element[]
|
||||
*/
|
||||
protected $taskList = [];
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface[]
|
||||
*/
|
||||
protected $rollbackStack = [];
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface[]
|
||||
*/
|
||||
protected $completionStack = [];
|
||||
|
||||
/**
|
||||
* @var \Robo\Collection\CollectionInterface
|
||||
*/
|
||||
protected $parentCollection;
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $deferredCallbacks = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $messageStoreKeys = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->resetState();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $interval
|
||||
*/
|
||||
public function setProgressBarAutoDisplayInterval($interval)
|
||||
{
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
return $this->progressIndicator->setProgressBarAutoDisplayInterval($interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add(TaskInterface $task, $name = self::UNNAMEDTASK)
|
||||
{
|
||||
$task = new CompletionWrapper($this, $task);
|
||||
$this->addToTaskList($name, $task);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCode(callable $code, $name = self::UNNAMEDTASK)
|
||||
{
|
||||
return $this->add(new CallableTask($code, $this), $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addIterable($iterable, callable $code)
|
||||
{
|
||||
$callbackTask = (new IterationTask($iterable, $code, $this))->inflect($this);
|
||||
return $this->add($callbackTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollback(TaskInterface $rollbackTask)
|
||||
{
|
||||
// Rollback tasks always try as hard as they can, and never report failures.
|
||||
$rollbackTask = $this->ignoreErrorsTaskWrapper($rollbackTask);
|
||||
return $this->wrapAndRegisterRollback($rollbackTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollbackCode(callable $rollbackCode)
|
||||
{
|
||||
// Rollback tasks always try as hard as they can, and never report failures.
|
||||
$rollbackTask = $this->ignoreErrorsCodeWrapper($rollbackCode);
|
||||
return $this->wrapAndRegisterRollback($rollbackTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function completion(TaskInterface $completionTask)
|
||||
{
|
||||
$collection = $this;
|
||||
$completionRegistrationTask = new CallableTask(
|
||||
function () use ($collection, $completionTask) {
|
||||
|
||||
$collection->registerCompletion($completionTask);
|
||||
},
|
||||
$this
|
||||
);
|
||||
$this->addToTaskList(self::UNNAMEDTASK, $completionRegistrationTask);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function completionCode(callable $completionTask)
|
||||
{
|
||||
$completionTask = new CallableTask($completionTask, $this);
|
||||
return $this->completion($completionTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function before($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK)
|
||||
{
|
||||
return $this->addBeforeOrAfter(__FUNCTION__, $name, $task, $nameOfTaskToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function after($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK)
|
||||
{
|
||||
return $this->addBeforeOrAfter(__FUNCTION__, $name, $task, $nameOfTaskToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function progressMessage($text, $context = [], $level = LogLevel::NOTICE)
|
||||
{
|
||||
$context += ['name' => 'Progress'];
|
||||
$context += TaskInfo::getTaskContext($this);
|
||||
return $this->addCode(
|
||||
function () use ($level, $text, $context) {
|
||||
$context += $this->getState()->getData();
|
||||
$this->printTaskOutput($level, $text, $context);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $rollbackTask
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function wrapAndRegisterRollback(TaskInterface $rollbackTask)
|
||||
{
|
||||
$collection = $this;
|
||||
$rollbackRegistrationTask = new CallableTask(
|
||||
function () use ($collection, $rollbackTask) {
|
||||
$collection->registerRollback($rollbackTask);
|
||||
},
|
||||
$this
|
||||
);
|
||||
$this->addToTaskList(self::UNNAMEDTASK, $rollbackRegistrationTask);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add either a 'before' or 'after' function or task.
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $name
|
||||
* @param callable|\Robo\Contract\TaskInterface $task
|
||||
* @param string $nameOfTaskToAdd
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addBeforeOrAfter($method, $name, $task, $nameOfTaskToAdd)
|
||||
{
|
||||
if (is_callable($task)) {
|
||||
$task = new CallableTask($task, $this);
|
||||
}
|
||||
$existingTask = $this->namedTask($name);
|
||||
$fn = [$existingTask, $method];
|
||||
call_user_func($fn, $task, $nameOfTaskToAdd);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the provided task in a wrapper that will ignore
|
||||
* any errors or exceptions that may be produced. This
|
||||
* is useful, for example, in adding optional cleanup tasks
|
||||
* at the beginning of a task collection, to remove previous
|
||||
* results which may or may not exist.
|
||||
*
|
||||
* TODO: Provide some way to specify which sort of errors
|
||||
* are ignored, so that 'file not found' may be ignored,
|
||||
* but 'permission denied' reported?
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
*
|
||||
* @return \Robo\Collection\CallableTask
|
||||
*/
|
||||
public function ignoreErrorsTaskWrapper(TaskInterface $task)
|
||||
{
|
||||
// If the task is a stack-based task, then tell it
|
||||
// to try to run all of its operations, even if some
|
||||
// of them fail.
|
||||
if ($task instanceof StackBasedTask) {
|
||||
$task->stopOnFail(false);
|
||||
}
|
||||
$ignoreErrorsInTask = function () use ($task) {
|
||||
$data = [];
|
||||
try {
|
||||
$result = $this->runSubtask($task);
|
||||
$message = $result->getMessage();
|
||||
$data = $result->getData();
|
||||
$data['exitcode'] = $result->getExitCode();
|
||||
} catch (AbortTasksException $abortTasksException) {
|
||||
throw $abortTasksException;
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
return Result::success($task, $message, $data);
|
||||
};
|
||||
// Wrap our ignore errors callable in a task.
|
||||
return new CallableTask($ignoreErrorsInTask, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $task
|
||||
*
|
||||
* @return \Robo\Collection\CallableTask
|
||||
*/
|
||||
public function ignoreErrorsCodeWrapper(callable $task)
|
||||
{
|
||||
return $this->ignoreErrorsTaskWrapper(new CallableTask($task, $this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of task names added to this collection.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function taskNames()
|
||||
{
|
||||
return array_keys($this->taskList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if a specified task name exists.
|
||||
* n.b. before() and after() require that the named
|
||||
* task exist; use this function to test first, if
|
||||
* unsure.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTask($name)
|
||||
{
|
||||
return array_key_exists($name, $this->taskList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an existing named task.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the task to insert before. The named task MUST exist.
|
||||
*
|
||||
* @return \Robo\Collection\Element
|
||||
* The task group for the named task. Generally this is only
|
||||
* used to call 'before()' and 'after()'.
|
||||
*/
|
||||
protected function namedTask($name)
|
||||
{
|
||||
if (!$this->hasTask($name)) {
|
||||
throw new \RuntimeException("Could not find task named $name");
|
||||
}
|
||||
return $this->taskList[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of tasks to our task collection.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface[] $tasks
|
||||
* An array of tasks to run with rollback protection
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addTaskList(array $tasks)
|
||||
{
|
||||
foreach ($tasks as $name => $task) {
|
||||
$this->add($task, $name);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the provided task to our task list.
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addToTaskList($name, TaskInterface $task)
|
||||
{
|
||||
// All tasks are stored in a task group so that we have a place
|
||||
// to hang 'before' and 'after' tasks.
|
||||
$taskGroup = new Element($task);
|
||||
return $this->addCollectionElementToTaskList($name, $taskGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $name
|
||||
* @param \Robo\Collection\Element $taskGroup
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addCollectionElementToTaskList($name, Element $taskGroup)
|
||||
{
|
||||
// If a task name is not provided, then we'll let php pick
|
||||
// the array index.
|
||||
if (Result::isUnnamed($name)) {
|
||||
$this->taskList[] = $taskGroup;
|
||||
return $this;
|
||||
}
|
||||
// If we are replacing an existing task with the
|
||||
// same name, ensure that our new task is added to
|
||||
// the end.
|
||||
$this->taskList[$name] = $taskGroup;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent collection. This is necessary so that nested
|
||||
* collections' rollback and completion tasks can be added to the
|
||||
* top-level collection, ensuring that the rollbacks for a collection
|
||||
* will run if any later task fails.
|
||||
*
|
||||
* @param \Robo\Collection\NestedCollectionInterface $parentCollection
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParentCollection(NestedCollectionInterface $parentCollection)
|
||||
{
|
||||
$this->parentCollection = $parentCollection;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate parent collection to use
|
||||
*
|
||||
* @return \Robo\Collection\CollectionInterface|$this
|
||||
*/
|
||||
public function getParentCollection()
|
||||
{
|
||||
return $this->parentCollection ? $this->parentCollection : $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a rollback task to run if there is any failure.
|
||||
*
|
||||
* Clients are free to add tasks to the rollback stack as
|
||||
* desired; however, usually it is preferable to call
|
||||
* Collection::rollback() instead. With that function,
|
||||
* the rollback function will only be called if all of the
|
||||
* tasks added before it complete successfully, AND some later
|
||||
* task fails.
|
||||
*
|
||||
* One example of a good use-case for registering a callback
|
||||
* function directly is to add a task that sends notification
|
||||
* when a task fails.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $rollbackTask
|
||||
* The rollback task to run on failure.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function registerRollback(TaskInterface $rollbackTask)
|
||||
{
|
||||
if ($this->parentCollection) {
|
||||
return $this->parentCollection->registerRollback($rollbackTask);
|
||||
}
|
||||
if ($rollbackTask) {
|
||||
array_unshift($this->rollbackStack, $rollbackTask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a completion task to run once all other tasks finish.
|
||||
* Completion tasks run whether or not a rollback operation was
|
||||
* triggered. They do not trigger rollbacks if they fail.
|
||||
*
|
||||
* The typical use-case for a completion function is to clean up
|
||||
* temporary objects (e.g. temporary folders). The preferred
|
||||
* way to do that, though, is to use Temporary::wrap().
|
||||
*
|
||||
* On failures, completion tasks will run after all rollback tasks.
|
||||
* If one task collection is nested inside another task collection,
|
||||
* then the nested collection's completion tasks will run as soon as
|
||||
* the nested task completes; they are not deferred to the end of
|
||||
* the containing collection's execution.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $completionTask
|
||||
* The completion task to run at the end of all other operations.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function registerCompletion(TaskInterface $completionTask)
|
||||
{
|
||||
if ($this->parentCollection) {
|
||||
return $this->parentCollection->registerCompletion($completionTask);
|
||||
}
|
||||
if ($completionTask) {
|
||||
// Completion tasks always try as hard as they can, and never report failures.
|
||||
$completionTask = $this->ignoreErrorsTaskWrapper($completionTask);
|
||||
$this->completionStack[] = $completionTask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of steps in this collection
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function progressIndicatorSteps()
|
||||
{
|
||||
$steps = 0;
|
||||
foreach ($this->taskList as $name => $taskGroup) {
|
||||
$steps += $taskGroup->progressIndicatorSteps();
|
||||
}
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Collection of tasks can provide a command via `getCommand()`
|
||||
* if it contains a single task, and that task implements CommandInterface.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Robo\Exception\TaskException
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
if (empty($this->taskList)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (count($this->taskList) > 1) {
|
||||
// TODO: We could potentially iterate over the items in the collection
|
||||
// and concatenate the result of getCommand() from each one, and fail
|
||||
// only if we encounter a command that is not a CommandInterface.
|
||||
throw new TaskException($this, "getCommand() does not work on arbitrary collections of tasks.");
|
||||
}
|
||||
|
||||
$taskElement = reset($this->taskList);
|
||||
$task = $taskElement->getTask();
|
||||
$task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task;
|
||||
if ($task instanceof CommandInterface) {
|
||||
return $task->getCommand();
|
||||
}
|
||||
|
||||
throw new TaskException($task, get_class($task) . " does not implement CommandInterface, so can't be used to provide a command");
|
||||
}
|
||||
|
||||
/**
|
||||
* Run our tasks, and roll back if necessary.
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$result = $this->runWithoutCompletion();
|
||||
$this->complete();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
private function runWithoutCompletion()
|
||||
{
|
||||
$result = Result::success($this);
|
||||
|
||||
if (empty($this->taskList)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$this->startProgressIndicator();
|
||||
if ($result->wasSuccessful()) {
|
||||
foreach ($this->taskList as $name => $taskGroup) {
|
||||
$taskList = $taskGroup->getTaskList();
|
||||
$result = $this->runTaskList($name, $taskList, $result);
|
||||
if (!$result->wasSuccessful()) {
|
||||
$this->fail();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
$this->taskList = [];
|
||||
}
|
||||
$this->stopProgressIndicator();
|
||||
$result['time'] = $this->getExecutionTime();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run every task in a list, but only up to the first failure.
|
||||
* Return the failing result, or success if all tasks run.
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Robo\Contract\TaskInterface[] $taskList
|
||||
* @param \Robo\Result $result
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*
|
||||
* @throws \Robo\Exception\TaskExitException
|
||||
*/
|
||||
private function runTaskList($name, array $taskList, Result $result)
|
||||
{
|
||||
try {
|
||||
foreach ($taskList as $taskName => $task) {
|
||||
$taskResult = $this->runSubtask($task);
|
||||
$this->advanceProgressIndicator();
|
||||
// If the current task returns an error code, then stop
|
||||
// execution and signal a rollback.
|
||||
if (!$taskResult->wasSuccessful()) {
|
||||
return $taskResult;
|
||||
}
|
||||
// We accumulate our results into a field so that tasks that
|
||||
// have a reference to the collection may examine and modify
|
||||
// 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();
|
||||
throw $exitException;
|
||||
} catch (\Exception $e) {
|
||||
// Tasks typically should not throw, but if one does, we will
|
||||
// convert it into an error and roll back.
|
||||
return Result::fromException($task, $e, $result->getData());
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the rollback functions to run
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function fail()
|
||||
{
|
||||
$this->disableProgressIndicator();
|
||||
$this->runRollbackTasks();
|
||||
$this->complete();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the completion functions to run
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function complete()
|
||||
{
|
||||
$this->detatchProgressIndicator();
|
||||
$this->runTaskListIgnoringFailures($this->completionStack);
|
||||
$this->reset();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this collection, removing all tasks.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->taskList = [];
|
||||
$this->completionStack = [];
|
||||
$this->rollbackStack = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all of our rollback tasks.
|
||||
*
|
||||
* Note that Collection does not implement RollbackInterface, but
|
||||
* it may still be used as a task inside another task collection
|
||||
* (i.e. you can nest task collections, if desired).
|
||||
*/
|
||||
protected function runRollbackTasks()
|
||||
{
|
||||
$this->runTaskListIgnoringFailures($this->rollbackStack);
|
||||
// Erase our rollback stack once we have finished rolling
|
||||
// everything back. This will allow us to potentially use
|
||||
// a command collection more than once (e.g. to retry a
|
||||
// failed operation after doing some error recovery).
|
||||
$this->rollbackStack = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface|\Robo\Collection\NestedCollectionInterface|\Robo\Contract\WrappedTaskInterface $task
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function runSubtask($task)
|
||||
{
|
||||
$original = ($task instanceof WrappedTaskInterface) ? $task->original() : $task;
|
||||
$this->setParentCollectionForTask($original, $this->getParentCollection());
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param \Robo\State\Data $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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param string $key
|
||||
* @param string $source
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function storeState($task, $key, $source = '')
|
||||
{
|
||||
$this->messageStoreKeys[spl_object_hash($task)] = [$key, $source];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param string $functionName
|
||||
* @param string $stateKey
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function defer($task, $callback)
|
||||
{
|
||||
$this->deferredCallbacks[spl_object_hash($task)][] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
*/
|
||||
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 \Robo\Collection\CollectionInterface $parentCollection
|
||||
*/
|
||||
protected function setParentCollectionForTask($task, $parentCollection)
|
||||
{
|
||||
if ($task instanceof NestedCollectionInterface) {
|
||||
$task->setParentCollection($parentCollection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all of the tasks in a provided list, ignoring failures.
|
||||
*
|
||||
* You may force a failure by throwing a ForcedException in your rollback or
|
||||
* completion task or callback.
|
||||
*
|
||||
* This is used to roll back or complete.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface[] $taskList
|
||||
*/
|
||||
protected function runTaskListIgnoringFailures(array $taskList)
|
||||
{
|
||||
foreach ($taskList as $task) {
|
||||
try {
|
||||
$this->runSubtask($task);
|
||||
} catch (AbortTasksException $abortTasksException) {
|
||||
// If there's a forced exception, end the loop of tasks.
|
||||
if ($message = $abortTasksException->getMessage()) {
|
||||
$this->printTaskInfo($message, ['name' => 'Exception']);
|
||||
}
|
||||
break;
|
||||
} catch (\Exception $e) {
|
||||
// Ignore rollback failures.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Give all of our tasks to the provided collection builder.
|
||||
*
|
||||
* @param \Robo\Collection\CollectionBuilder $builder
|
||||
*/
|
||||
public function transferTasks($builder)
|
||||
{
|
||||
foreach ($this->taskList as $name => $taskGroup) {
|
||||
// TODO: We are abandoning all of our before and after tasks here.
|
||||
// At the moment, transferTasks is only called under conditions where
|
||||
// there will be none of these, but care should be taken if that changes.
|
||||
$task = $taskGroup->getTask();
|
||||
$builder->addTaskToCollection($task);
|
||||
}
|
||||
$this->reset();
|
||||
}
|
||||
}
|
||||
655
vendor/consolidation/robo/src/Collection/CollectionBuilder.php
vendored
Normal file
655
vendor/consolidation/robo/src/Collection/CollectionBuilder.php
vendored
Normal file
@ -0,0 +1,655 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Consolidation\Config\Inject\ConfigForSetters;
|
||||
use Psr\Log\LogLevel;
|
||||
use ReflectionClass;
|
||||
use Robo\Common\InputAwareTrait;
|
||||
use Robo\Config\Config;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Contract\CompletionInterface;
|
||||
use Robo\Contract\InflectionInterface;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Robo\Contract\WrappedTaskInterface;
|
||||
use Robo\Result;
|
||||
use Robo\State\StateAwareInterface;
|
||||
use Robo\State\StateAwareTrait;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Task\Simulator;
|
||||
use Symfony\Component\Console\Input\InputAwareInterface;
|
||||
|
||||
/**
|
||||
* Creates a collection, and adds tasks to it. The collection builder
|
||||
* offers a streamlined chained-initialization mechanism for easily
|
||||
* creating task groups. Facilities for creating working and temporary
|
||||
* directories are also provided.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $result = $this->collectionBuilder()
|
||||
* ->taskFilesystemStack()
|
||||
* ->mkdir('g')
|
||||
* ->touch('g/g.txt')
|
||||
* ->rollback(
|
||||
* $this->taskDeleteDir('g')
|
||||
* )
|
||||
* ->taskFilesystemStack()
|
||||
* ->mkdir('g/h')
|
||||
* ->touch('g/h/h.txt')
|
||||
* ->taskFilesystemStack()
|
||||
* ->mkdir('g/h/i/c')
|
||||
* ->touch('g/h/i/i.txt')
|
||||
* ->run()
|
||||
* ?>
|
||||
*
|
||||
* In the example above, the `taskDeleteDir` will be called if
|
||||
* ```
|
||||
*/
|
||||
class CollectionBuilder extends BaseTask implements NestedCollectionInterface, WrappedTaskInterface, CommandInterface, StateAwareInterface, InputAwareInterface
|
||||
{
|
||||
use StateAwareTrait;
|
||||
use InputAwareTrait; // BaseTask has OutputAwareTrait
|
||||
|
||||
/**
|
||||
* @var \Robo\Tasks
|
||||
*/
|
||||
protected $commandFile;
|
||||
|
||||
/**
|
||||
* @var \Robo\Collection\CollectionInterface
|
||||
*/
|
||||
protected $collection;
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface
|
||||
*/
|
||||
protected $currentTask;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $simulated;
|
||||
|
||||
/**
|
||||
* @param \Robo\Tasks $commandFile
|
||||
*/
|
||||
public function __construct($commandFile)
|
||||
{
|
||||
$this->commandFile = $commandFile;
|
||||
$this->resetState();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
* @param \Robo\Tasks $commandFile
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $simulated
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function simulated($simulated = true)
|
||||
{
|
||||
$this->simulated = $simulated;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSimulated()
|
||||
{
|
||||
if (!isset($this->simulated)) {
|
||||
$this->simulated = $this->getConfig()->get(Config::SIMULATE);
|
||||
}
|
||||
return $this->simulated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a temporary directory to work in. When the collection
|
||||
* completes or rolls back, the temporary directory will be deleted.
|
||||
* Returns the path to the location where the directory will be
|
||||
* created.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param string $base
|
||||
* @param bool $includeRandomPart
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true)
|
||||
{
|
||||
// n.b. Any task that the builder is asked to create is
|
||||
// automatically added to the builder's collection, and
|
||||
// wrapped in the builder object. Therefore, the result
|
||||
// of any call to `taskFoo()` from within the builder will
|
||||
// always be `$this`.
|
||||
return $this->taskTmpDir($prefix, $base, $includeRandomPart)->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a working directory to hold results. A temporary directory
|
||||
* is first created to hold the intermediate results. After the
|
||||
* builder finishes, the work directory is moved into its final location;
|
||||
* any results already in place will be moved out of the way and
|
||||
* then deleted.
|
||||
*
|
||||
* @param string $finalDestination
|
||||
* The path where the working directory will be moved once the task
|
||||
* collection completes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function workDir($finalDestination)
|
||||
{
|
||||
// Creating the work dir task in this context adds it to our task collection.
|
||||
return $this->taskWorkDir($finalDestination)->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function addTask(TaskInterface $task)
|
||||
{
|
||||
$this->getCollection()->add($task);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, $name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of tasks to our task collection.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface[] $tasks
|
||||
* An array of tasks to run with rollback protection
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addTaskList(array $tasks)
|
||||
{
|
||||
$this->getCollection()->addTaskList($tasks);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function rollback(TaskInterface $task)
|
||||
{
|
||||
// Ensure that we have a collection if we are going to add
|
||||
// a rollback function.
|
||||
$this->getCollection()->rollback($task);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function rollbackCode(callable $rollbackCode)
|
||||
{
|
||||
$this->getCollection()->rollbackCode($rollbackCode);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function completion(TaskInterface $task)
|
||||
{
|
||||
$this->getCollection()->completion($task);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function completionCode(callable $completionCode)
|
||||
{
|
||||
$this->getCollection()->completionCode($completionCode);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param array $context
|
||||
* @param string $level
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function progressMessage($text, $context = [], $level = LogLevel::NOTICE)
|
||||
{
|
||||
$this->getCollection()->progressMessage($text, $context, $level);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setParentCollection(NestedCollectionInterface $parentCollection)
|
||||
{
|
||||
$this->getCollection()->setParentCollection($parentCollection);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the factory method of each task; adds the current
|
||||
* task to the task builder.
|
||||
*
|
||||
* TODO: protected
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addTaskToCollection($task)
|
||||
{
|
||||
// Postpone creation of the collection until the second time
|
||||
// we are called. At that time, $this->currentTask will already
|
||||
// be populated. We call 'getCollection()' so that it will
|
||||
// create the collection and add the current task to it.
|
||||
// Note, however, that if our only tasks implements NestedCollectionInterface,
|
||||
// then we should force this builder to use a collection.
|
||||
if (!$this->collection && (isset($this->currentTask) || ($task instanceof NestedCollectionInterface))) {
|
||||
$this->getCollection();
|
||||
}
|
||||
$this->currentTask = $task;
|
||||
if ($this->collection) {
|
||||
$this->collection->add($task);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\State\Data
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
$collection = $this->getCollection();
|
||||
return $collection->getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $key
|
||||
* @param mixed $source
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function storeState($key, $source = '')
|
||||
{
|
||||
return $this->callCollectionStateFunction(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $functionName
|
||||
* @param int|string $stateKey
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function deferTaskConfiguration($functionName, $stateKey)
|
||||
{
|
||||
return $this->callCollectionStateFunction(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable$callback
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function defer($callback)
|
||||
{
|
||||
return $this->callCollectionStateFunction(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $functionName
|
||||
* @param array $args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function callCollectionStateFunction($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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $functionName
|
||||
* @param array $args
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated Use ::callCollectionStateFunction() instead.
|
||||
*/
|
||||
protected function callCollectionStateFuntion($functionName, $args)
|
||||
{
|
||||
return $this->callCollectionStateFunction($functionName, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $verbosityThreshold
|
||||
*
|
||||
* @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?
|
||||
*
|
||||
* @return \Robo\Contract\TaskInterface
|
||||
*/
|
||||
public function getCollectionBuilderCurrentTask()
|
||||
{
|
||||
return $this->currentTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new builder with its own task collection
|
||||
*
|
||||
* @return \Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
public function newBuilder()
|
||||
{
|
||||
$collectionBuilder = new self($this->commandFile);
|
||||
$collectionBuilder->inflect($this);
|
||||
$collectionBuilder->simulated($this->isSimulated());
|
||||
$collectionBuilder->setVerbosityThreshold($this->verbosityThreshold());
|
||||
$collectionBuilder->setState($this->getState());
|
||||
|
||||
return $collectionBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling the task builder with methods of the current
|
||||
* task calls through to that method of the task.
|
||||
*
|
||||
* There is extra complexity in this function that could be
|
||||
* simplified if we attached the 'LoadAllTasks' and custom tasks
|
||||
* to the collection builder instead of the RoboFile. While that
|
||||
* change would be a better design overall, it would require that
|
||||
* the user do a lot more work to set up and use custom tasks.
|
||||
* We therefore take on some additional complexity here in order
|
||||
* to allow users to maintain their tasks in their RoboFile, which
|
||||
* is much more convenient.
|
||||
*
|
||||
* Calls to $this->collectionBuilder()->taskFoo() cannot be made
|
||||
* directly because all of the task methods are protected. These
|
||||
* calls will therefore end up here. If the method name begins
|
||||
* with 'task', then it is eligible to be used with the builder.
|
||||
*
|
||||
* When we call getBuiltTask, below, it will use the builder attached
|
||||
* to the commandfile to build the task. However, this is not what we
|
||||
* want: the task needs to be built from THIS collection builder, so that
|
||||
* it will be affected by whatever state is active in this builder.
|
||||
* To do this, we have two choices: 1) save and restore the builder
|
||||
* in the commandfile, or 2) clone the commandfile and set this builder
|
||||
* on the copy. 1) is vulnerable to failure in multithreaded environments
|
||||
* (currently not supported), while 2) might cause confusion if there
|
||||
* is shared state maintained in the commandfile, which is in the
|
||||
* domain of the user.
|
||||
*
|
||||
* Note that even though we are setting up the commandFile to
|
||||
* use this builder, getBuiltTask always creates a new builder
|
||||
* (which is constructed using all of the settings from the
|
||||
* commandFile's builder), and the new task is added to that.
|
||||
* We therefore need to transfer the newly built task into this
|
||||
* builder. The temporary builder is discarded.
|
||||
*
|
||||
* @param string $fn
|
||||
* @param array $args
|
||||
*
|
||||
* @return $this|mixed
|
||||
*/
|
||||
public function __call($fn, $args)
|
||||
{
|
||||
if (preg_match('#^task[A-Z]#', $fn) && (method_exists($this->commandFile, 'getBuiltTask'))) {
|
||||
$saveBuilder = $this->commandFile->getBuilder();
|
||||
$this->commandFile->setBuilder($this);
|
||||
$temporaryBuilder = $this->commandFile->getBuiltTask($fn, $args);
|
||||
$this->commandFile->setBuilder($saveBuilder);
|
||||
if (!$temporaryBuilder) {
|
||||
throw new \BadMethodCallException("No such method $fn: task does not exist in " . get_class($this->commandFile));
|
||||
}
|
||||
$temporaryBuilder->getCollection()->transferTasks($this);
|
||||
return $this;
|
||||
}
|
||||
if (!isset($this->currentTask)) {
|
||||
throw new \BadMethodCallException("No such method $fn: current task undefined in collection builder.");
|
||||
}
|
||||
// If the method called is a method of the current task,
|
||||
// then call through to the current task's setter method.
|
||||
$result = call_user_func_array([$this->currentTask, $fn], $args);
|
||||
|
||||
// If something other than a setter method is called, then return its result.
|
||||
$currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask;
|
||||
if (isset($result) && ($result !== $currentTask)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the desired task and add it to this builder.
|
||||
*
|
||||
* @param string|object $name
|
||||
* @param array $args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build($name, $args)
|
||||
{
|
||||
$reflection = new ReflectionClass($name);
|
||||
$task = $reflection->newInstanceArgs($args);
|
||||
if (!$task) {
|
||||
throw new \RuntimeException("Can not construct task $name");
|
||||
}
|
||||
$task = $this->fixTask($task, $args);
|
||||
$this->configureTask($name, $task);
|
||||
return $this->addTaskToCollection($task);
|
||||
}
|
||||
|
||||
public function injectDependencies($child)
|
||||
{
|
||||
parent::injectDependencies($child);
|
||||
|
||||
if ($child instanceof InputAwareInterface) {
|
||||
$child->setInput($this->input());
|
||||
}
|
||||
if ($child instanceof OutputAwareInterface) {
|
||||
$child->setOutput($this->output());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param array $args
|
||||
*
|
||||
* @return \Robo\Collection\CompletionWrapper|\Robo\Task\Simulator
|
||||
*/
|
||||
protected function fixTask($task, $args)
|
||||
{
|
||||
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) {
|
||||
return $task;
|
||||
}
|
||||
|
||||
// Remember whether or not this is a task before
|
||||
// it gets wrapped in any decorator.
|
||||
$isTask = $task instanceof TaskInterface;
|
||||
$isCollection = $task instanceof NestedCollectionInterface;
|
||||
|
||||
// If the task implements CompletionInterface, ensure
|
||||
// that its 'complete' method is called when the application
|
||||
// terminates -- but only if its 'run' method is called
|
||||
// first. If the task is added to a collection, then the
|
||||
// task will be unwrapped via its `original` method, and
|
||||
// it will be re-wrapped with a new completion wrapper for
|
||||
// its new collection.
|
||||
if ($task instanceof CompletionInterface) {
|
||||
$task = new CompletionWrapper(Temporary::getCollection(), $task);
|
||||
}
|
||||
|
||||
// If we are in simulated mode, then wrap any task in
|
||||
// a TaskSimulator.
|
||||
if ($isTask && !$isCollection && ($this->isSimulated())) {
|
||||
$task = new \Robo\Task\Simulator($task, $args);
|
||||
$task->inflect($this);
|
||||
}
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if there are any setter methods defined in configuration
|
||||
* for this task.
|
||||
*
|
||||
* @param string $taskClass
|
||||
* @param \Robo\Contract\TaskInterface $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.
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->startTimer();
|
||||
$result = $this->runTasks();
|
||||
$this->stopTimer();
|
||||
$result['time'] = $this->getExecutionTime();
|
||||
$result->mergeData($this->getState()->getData());
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is a single task, run it; if there is a collection, run
|
||||
* all of its tasks.
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function runTasks()
|
||||
{
|
||||
if (!$this->collection && $this->currentTask) {
|
||||
$result = $this->currentTask->run();
|
||||
return Result::ensureResult($this->currentTask, $result);
|
||||
}
|
||||
return $this->getCollection()->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
if (!$this->collection && $this->currentTask) {
|
||||
$task = $this->currentTask;
|
||||
$task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task;
|
||||
if ($task instanceof CommandInterface) {
|
||||
return $task->getCommand();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->getCollection()->getCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Collection\CollectionInterface
|
||||
*/
|
||||
public function original()
|
||||
{
|
||||
return $this->getCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the collection of tasks associated with this builder.
|
||||
*
|
||||
* @return \Robo\Collection\CollectionInterface
|
||||
*/
|
||||
public function getCollection()
|
||||
{
|
||||
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)) {
|
||||
$this->collection->add($this->currentTask);
|
||||
}
|
||||
}
|
||||
return $this->collection;
|
||||
}
|
||||
}
|
||||
160
vendor/consolidation/robo/src/Collection/CollectionInterface.php
vendored
Normal file
160
vendor/consolidation/robo/src/Collection/CollectionInterface.php
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Contract\TaskInterface;
|
||||
|
||||
interface CollectionInterface extends NestedCollectionInterface
|
||||
{
|
||||
/**
|
||||
* Unnamed tasks are assigned an arbitrary numeric index
|
||||
* in the task list. Any numeric value may be used, but the
|
||||
* UNNAMEDTASK constant is recommended for clarity.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const UNNAMEDTASK = 0;
|
||||
|
||||
/**
|
||||
* Add a task or a list of tasks to our task collection. Each task
|
||||
* will run via its 'run()' method once (and if) all of the tasks
|
||||
* added before it complete successfully. If the task also implements
|
||||
* RollbackInterface, then it will be rolled back via its 'rollback()'
|
||||
* method ONLY if its 'run()' method completes successfully, and some
|
||||
* task added after it fails.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* The task to add to our collection.
|
||||
* @param int|string $name
|
||||
* An optional name for the task -- missing or UNNAMEDTASK for unnamed tasks.
|
||||
* Names are used for positioning before and after tasks.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add(TaskInterface $task, $name = self::UNNAMEDTASK);
|
||||
|
||||
/**
|
||||
* Add arbitrary code to execute as a task.
|
||||
*
|
||||
* @param callable $code
|
||||
* Code to execute as a task
|
||||
* @param int|string $name
|
||||
* An optional name for the task -- missing or UNNAMEDTASK for unnamed tasks.
|
||||
* Names are used for positioning before and after tasks.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCode(callable $code, $name = self::UNNAMEDTASK);
|
||||
|
||||
/**
|
||||
* Add arbitrary code that will be called once for every item in the
|
||||
* provided array or iterable object. If the function result of the
|
||||
* provided callback is a TaskInterface or Collection, then it will be
|
||||
* executed.
|
||||
*
|
||||
* @param static|array $iterable
|
||||
* A collection of things to iterate.
|
||||
* @param callable $code
|
||||
* A callback function to call for each item in the collection.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addIterable($iterable, callable $code);
|
||||
|
||||
/**
|
||||
* Add a rollback task to our task collection. A rollback task
|
||||
* will execute ONLY if all of the tasks added before it complete
|
||||
* successfully, AND some task added after it fails.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $rollbackTask
|
||||
* The rollback task to add. Note that the 'run()' method of the
|
||||
* task executes, not its 'rollback()' method. To use the 'rollback()'
|
||||
* method, add the task via 'Collection::add()' instead.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function rollback(TaskInterface $rollbackTask);
|
||||
|
||||
/**
|
||||
* Add arbitrary code to execute as a rollback.
|
||||
*
|
||||
* @param callable $rollbackTask
|
||||
* Code to execute during rollback processing.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function rollbackCode(callable $rollbackTask);
|
||||
|
||||
/**
|
||||
* Add a completion task to our task collection. A completion task
|
||||
* will execute EITHER after all tasks succeed, OR immediatley after
|
||||
* any task fails. Completion tasks never cause errors to be returned
|
||||
* from Collection::run(), even if they fail.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $completionTask
|
||||
* The completion task to add. Note that the 'run()' method of the
|
||||
* task executes, just as if the task was added normally.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function completion(TaskInterface $completionTask);
|
||||
|
||||
/**
|
||||
* Add arbitrary code to execute as a completion.
|
||||
*
|
||||
* @param callable $completionTask
|
||||
* Code to execute after collection completes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function completionCode(callable $completionTask);
|
||||
|
||||
/**
|
||||
* Add a task before an existing named task.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the task to insert before. The named task MUST exist.
|
||||
* @param callable|\Robo\Contract\TaskInterface $task
|
||||
* The task to add.
|
||||
* @param int|string $nameOfTaskToAdd
|
||||
* The name of the task to add. If not provided, will be associated
|
||||
* with the named task it was added before.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function before($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK);
|
||||
|
||||
/**
|
||||
* Add a task after an existing named task.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the task to insert before. The named task MUST exist.
|
||||
* @param callable|\Robo\Contract\TaskInterface $task
|
||||
* The task to add.
|
||||
* @param int|string $nameOfTaskToAdd
|
||||
* The name of the task to add. If not provided, will be associated
|
||||
* with the named task it was added after.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function after($name, $task, $nameOfTaskToAdd = self::UNNAMEDTASK);
|
||||
|
||||
/**
|
||||
* Print a progress message after Collection::run() has executed
|
||||
* all of the tasks that were added prior to the point when this
|
||||
* method was called. If one of the previous tasks fail, then this
|
||||
* message will not be printed.
|
||||
*
|
||||
* @param string $text
|
||||
* Message to print.
|
||||
* @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
|
||||
*/
|
||||
public function progressMessage($text, $context = [], $level = LogLevel::NOTICE);
|
||||
}
|
||||
36
vendor/consolidation/robo/src/Collection/CollectionProcessHook.php
vendored
Normal file
36
vendor/consolidation/robo/src/Collection/CollectionProcessHook.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Consolidation\AnnotatedCommand\Hooks\ProcessResultInterface;
|
||||
use Consolidation\AnnotatedCommand\CommandData;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Result;
|
||||
|
||||
/**
|
||||
* The collection process hook is added to the annotation command
|
||||
* hook manager in Runner::configureContainer(). This hook will be
|
||||
* called every time a command runs. If the command result is a
|
||||
* \Robo\Contract\TaskInterface (in particular, \Robo\Collection\Collection),
|
||||
* then we run the collection, and return the result. We ignore results
|
||||
* of any other type.
|
||||
*/
|
||||
class CollectionProcessHook implements ProcessResultInterface
|
||||
{
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface|mixed $result
|
||||
* @param \Consolidation\AnnotatedCommand\CommandData $commandData
|
||||
*
|
||||
* @return null|\Robo\Result
|
||||
*/
|
||||
public function process($result, CommandData $commandData)
|
||||
{
|
||||
if ($result instanceof TaskInterface) {
|
||||
try {
|
||||
return $result->run();
|
||||
} catch (\Exception $e) {
|
||||
return Result::fromException($result, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
vendor/consolidation/robo/src/Collection/CompletionWrapper.php
vendored
Normal file
106
vendor/consolidation/robo/src/Collection/CompletionWrapper.php
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\RollbackInterface;
|
||||
use Robo\Contract\CompletionInterface;
|
||||
use Robo\Contract\WrappedTaskInterface;
|
||||
|
||||
/**
|
||||
* Creates a task wrapper that will manage rollback and collection
|
||||
* management to a task when it runs. Tasks are automatically
|
||||
* wrapped in a CompletionWrapper when added to a task collection.
|
||||
*
|
||||
* Clients may need to wrap their task in a CompletionWrapper if it
|
||||
* creates temporary objects.
|
||||
*
|
||||
* @see \Robo\Task\Filesystem\Tasks::taskTmpDir
|
||||
*/
|
||||
class CompletionWrapper extends BaseTask implements WrappedTaskInterface
|
||||
{
|
||||
/**
|
||||
* @var \Robo\Collection\Collection
|
||||
*/
|
||||
private $collection;
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface
|
||||
*/
|
||||
private $task;
|
||||
|
||||
/**
|
||||
* @var NULL|\Robo\Contract\TaskInterface
|
||||
*/
|
||||
private $rollbackTask;
|
||||
|
||||
/**
|
||||
* Create a CompletionWrapper.
|
||||
*
|
||||
* Temporary tasks are always wrapped in a CompletionWrapper, as are
|
||||
* any tasks that are added to a collection. If a temporary task
|
||||
* is added to a collection, then it is first unwrapped from its
|
||||
* CompletionWrapper (via its original() method), and then added to a
|
||||
* new CompletionWrapper for the collection it is added to.
|
||||
*
|
||||
* In this way, when the CompletionWrapper is finally executed, the
|
||||
* task's rollback and completion handlers will be registered on
|
||||
* whichever collection it was registered on.
|
||||
*
|
||||
* @todo Why not CollectionInterface the type of the $collection argument?
|
||||
*
|
||||
* @param \Robo\Collection\Collection $collection
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param \Robo\Contract\TaskInterface|null $rollbackTask
|
||||
*/
|
||||
public function __construct(Collection $collection, TaskInterface $task, ?TaskInterface $rollbackTask = null)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task;
|
||||
$this->rollbackTask = $rollbackTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function original()
|
||||
{
|
||||
return $this->task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before running this task, register its rollback and completion
|
||||
* handlers on its collection. The reason this class exists is to
|
||||
* defer registration of rollback and completion tasks until 'run()' time.
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if ($this->rollbackTask) {
|
||||
$this->collection->registerRollback($this->rollbackTask);
|
||||
}
|
||||
if ($this->task instanceof RollbackInterface) {
|
||||
$this->collection->registerRollback(new CallableTask([$this->task, 'rollback'], $this->task));
|
||||
}
|
||||
if ($this->task instanceof CompletionInterface) {
|
||||
$this->collection->registerCompletion(new CallableTask([$this->task, 'complete'], $this->task));
|
||||
}
|
||||
|
||||
return $this->task->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this wrapper object act like the class it wraps.
|
||||
*
|
||||
* @param string $function
|
||||
* @param array $args
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($function, $args)
|
||||
{
|
||||
return call_user_func_array(array($this->task, $function), $args);
|
||||
}
|
||||
}
|
||||
116
vendor/consolidation/robo/src/Collection/Element.php
vendored
Normal file
116
vendor/consolidation/robo/src/Collection/Element.php
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Contract\WrappedTaskInterface;
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
|
||||
/**
|
||||
* One element in a collection. Each element consists of a task
|
||||
* all of its before tasks, and all of its after tasks.
|
||||
*
|
||||
* This class is internal to Collection; it should not be used directly.
|
||||
*/
|
||||
class Element
|
||||
{
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface
|
||||
*/
|
||||
protected $task;
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface[]|callable[]
|
||||
*/
|
||||
protected $before = [];
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface[]|callable[]
|
||||
*/
|
||||
protected $after = [];
|
||||
|
||||
public function __construct(TaskInterface $task)
|
||||
{
|
||||
$this->task = $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface|callable $before
|
||||
* @param string $name
|
||||
*/
|
||||
public function before($before, $name)
|
||||
{
|
||||
if ($name) {
|
||||
$this->before[$name] = $before;
|
||||
} else {
|
||||
$this->before[] = $before;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface|callable $after
|
||||
* @param string $name
|
||||
*/
|
||||
public function after($after, $name)
|
||||
{
|
||||
if ($name) {
|
||||
$this->after[$name] = $after;
|
||||
} else {
|
||||
$this->after[] = $after;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\TaskInterface[]|callable[]
|
||||
*/
|
||||
public function getBefore()
|
||||
{
|
||||
return $this->before;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\TaskInterface[]|callable[]
|
||||
*/
|
||||
public function getAfter()
|
||||
{
|
||||
return $this->after;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\TaskInterface
|
||||
*/
|
||||
public function getTask()
|
||||
{
|
||||
return $this->task;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\TaskInterface[]|callable[]
|
||||
*/
|
||||
public function getTaskList()
|
||||
{
|
||||
return array_merge($this->getBefore(), [$this->getTask()], $this->getAfter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function progressIndicatorSteps()
|
||||
{
|
||||
$steps = 0;
|
||||
foreach ($this->getTaskList() as $task) {
|
||||
if ($task instanceof WrappedTaskInterface) {
|
||||
$task = $task->original();
|
||||
}
|
||||
// If the task is a ProgressIndicatorAwareInterface, then it
|
||||
// will advance the progress indicator a number of times.
|
||||
if ($task instanceof ProgressIndicatorAwareInterface) {
|
||||
$steps += $task->progressIndicatorSteps();
|
||||
}
|
||||
// We also advance the progress indicator once regardless
|
||||
// of whether it is progress-indicator aware or not.
|
||||
$steps++;
|
||||
}
|
||||
return $steps;
|
||||
}
|
||||
}
|
||||
13
vendor/consolidation/robo/src/Collection/NestedCollectionInterface.php
vendored
Normal file
13
vendor/consolidation/robo/src/Collection/NestedCollectionInterface.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
interface NestedCollectionInterface
|
||||
{
|
||||
/**
|
||||
* @param \Robo\Collection\NestedCollectionInterface $parentCollection
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParentCollection(NestedCollectionInterface $parentCollection);
|
||||
}
|
||||
215
vendor/consolidation/robo/src/Collection/TaskForEach.php
vendored
Normal file
215
vendor/consolidation/robo/src/Collection/TaskForEach.php
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Common\BuilderAwareTrait;
|
||||
|
||||
/**
|
||||
* Creates a task wrapper that converts any Callable into an
|
||||
* object that will execute the callback once for each item in the
|
||||
* provided collection.
|
||||
*
|
||||
* It is not necessary to use this class directly; Collection::addIterable
|
||||
* will automatically create one when it is called.
|
||||
*/
|
||||
class TaskForEach extends BaseTask implements NestedCollectionInterface, BuilderAwareInterface
|
||||
{
|
||||
use BuilderAwareTrait;
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $functionStack = [];
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $countingStack = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $context = [];
|
||||
|
||||
/**
|
||||
* @var array $iterable
|
||||
*/
|
||||
protected $iterable = [];
|
||||
|
||||
/**
|
||||
* @var \Robo\Collection\NestedCollectionInterface
|
||||
*/
|
||||
protected $parentCollection;
|
||||
|
||||
/**
|
||||
* @var array $iterable
|
||||
*/
|
||||
public function __construct($iterable = [])
|
||||
{
|
||||
$this->setIterable($iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $iterable
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setIterable($iterable)
|
||||
{
|
||||
$this->iterable = $iterable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function iterationMessage($message, $context = [])
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->context = $context + ['name' => 'Progress'];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
protected function showIterationMessage($key, $value)
|
||||
{
|
||||
if ($this->message) {
|
||||
$context = ['key' => $key, 'value' => $value];
|
||||
$context += $this->context;
|
||||
$context += TaskInfo::getTaskContext($this);
|
||||
$this->printTaskInfo($this->message, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $fn
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withEachKeyValueCall(callable $fn)
|
||||
{
|
||||
$this->functionStack[] = $fn;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $fn
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function call(callable $fn)
|
||||
{
|
||||
return $this->withEachKeyValueCall(
|
||||
function ($key, $value) use ($fn) {
|
||||
return call_user_func($fn, $value);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $fn
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withBuilder(callable $fn)
|
||||
{
|
||||
$this->countingStack[] =
|
||||
function ($key, $value) use ($fn) {
|
||||
// Create a new builder for every iteration
|
||||
$builder = $this->collectionBuilder();
|
||||
// The user function should build task operations using
|
||||
// the $key / $value parameters; we will call run() on
|
||||
// the builder thus constructed.
|
||||
call_user_func($fn, $builder, $key, $value);
|
||||
return $builder->getCollection()->progressIndicatorSteps();
|
||||
};
|
||||
return $this->withEachKeyValueCall(
|
||||
function ($key, $value) use ($fn) {
|
||||
// Create a new builder for every iteration
|
||||
$builder = $this->collectionBuilder()
|
||||
->setParentCollection($this->parentCollection);
|
||||
// The user function should build task operations using
|
||||
// the $key / $value parameters; we will call run() on
|
||||
// the builder thus constructed.
|
||||
call_user_func($fn, $builder, $key, $value);
|
||||
return $builder->run();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setParentCollection(NestedCollectionInterface $parentCollection)
|
||||
{
|
||||
$this->parentCollection = $parentCollection;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function progressIndicatorSteps()
|
||||
{
|
||||
$multiplier = count($this->functionStack);
|
||||
if (!empty($this->countingStack) && count($this->iterable)) {
|
||||
$value = reset($this->iterable);
|
||||
$key = key($this->iterable);
|
||||
foreach ($this->countingStack as $fn) {
|
||||
$multiplier += call_user_func($fn, $key, $value);
|
||||
}
|
||||
}
|
||||
return count($this->iterable) * $multiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$finalResult = Result::success($this);
|
||||
$this->startProgressIndicator();
|
||||
foreach ($this->iterable as $key => $value) {
|
||||
$this->showIterationMessage($key, $value);
|
||||
try {
|
||||
foreach ($this->functionStack as $fn) {
|
||||
$result = call_user_func($fn, $key, $value);
|
||||
$this->advanceProgressIndicator();
|
||||
if (!isset($result)) {
|
||||
$result = Result::success($this);
|
||||
}
|
||||
// If the function returns a result, it must either return
|
||||
// a \Robo\Result or an exit code. In the later case, we
|
||||
// convert it to a \Robo\Result.
|
||||
if (!$result instanceof Result) {
|
||||
$result = new Result($this, $result);
|
||||
}
|
||||
if (!$result->wasSuccessful()) {
|
||||
return $result;
|
||||
}
|
||||
$finalResult = $result->merge($finalResult);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return Result::fromException($result, $e);
|
||||
}
|
||||
}
|
||||
$this->stopProgressIndicator();
|
||||
return $finalResult;
|
||||
}
|
||||
}
|
||||
18
vendor/consolidation/robo/src/Collection/Tasks.php
vendored
Normal file
18
vendor/consolidation/robo/src/Collection/Tasks.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
trait Tasks
|
||||
{
|
||||
/**
|
||||
* Run a callback function on each item in a collection
|
||||
*
|
||||
* @param array $collection
|
||||
*
|
||||
* @return \Robo\Collection\TaskForEach|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskForEach($collection = [])
|
||||
{
|
||||
return $this->task(TaskForEach::class, $collection);
|
||||
}
|
||||
}
|
||||
63
vendor/consolidation/robo/src/Collection/Temporary.php
vendored
Normal file
63
vendor/consolidation/robo/src/Collection/Temporary.php
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Collection;
|
||||
|
||||
/**
|
||||
* The temporary collection keeps track of the global collection of
|
||||
* temporary cleanup tasks in instances where temporary-generating
|
||||
* tasks are executed directly via their run() method, rather than
|
||||
* as part of a collection.
|
||||
*
|
||||
* In general, temporary-generating tasks should always be run in
|
||||
* a collection, as the cleanup functions registered with the
|
||||
* Temporary collection will not run until requested.
|
||||
*
|
||||
* Since the results could be undefined if cleanup functions were called
|
||||
* at arbitrary times during a program's execution, cleanup should only
|
||||
* be done immeidately prior to program termination, when there is no
|
||||
* danger of cleaning up after some unrelated task.
|
||||
*
|
||||
* An application need never use Temporary directly, save to
|
||||
* call Temporary::wrap() inside Tasks or Shortcuts, and
|
||||
* to call Temporary::complete() immediately prior to terminating.
|
||||
* This is recommended, but not required; this function will be
|
||||
* registered as a shutdown function, and called on termination.
|
||||
*/
|
||||
class Temporary
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Robo\Collection\Collection
|
||||
*/
|
||||
private static $collection;
|
||||
|
||||
/**
|
||||
* Provides direct access to the collection of temporaries, if necessary.
|
||||
*
|
||||
* @return \Robo\Collection\Collection
|
||||
*/
|
||||
public static function getCollection()
|
||||
{
|
||||
if (!static::$collection) {
|
||||
static::$collection = \Robo\Robo::getContainer()->get('collection');
|
||||
register_shutdown_function(function () {
|
||||
static::complete();
|
||||
});
|
||||
}
|
||||
|
||||
return static::$collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the complete method of all of the registered objects.
|
||||
*/
|
||||
public static function complete()
|
||||
{
|
||||
// Run the collection of tasks. This will also run the
|
||||
// completion tasks.
|
||||
$collection = static::getCollection();
|
||||
$collection->run();
|
||||
// Make sure that our completion functions do not run twice.
|
||||
$collection->reset();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user