Initial Drupal 11 with DDEV setup
This commit is contained in:
76
vendor/consolidation/robo/src/Application.php
vendored
Normal file
76
vendor/consolidation/robo/src/Application.php
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
use Symfony\Component\Console\Application as SymfonyApplication;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Application extends SymfonyApplication
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $version
|
||||
*/
|
||||
public function __construct($name, $version)
|
||||
{
|
||||
parent::__construct($name, $version);
|
||||
|
||||
$this->getDefinition()
|
||||
->addOption(
|
||||
new InputOption('--simulate', null, InputOption::VALUE_NONE, 'Run in simulated mode (show what would have happened).')
|
||||
);
|
||||
$this->getDefinition()
|
||||
->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.', [])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $roboFile
|
||||
* @param string $roboClass
|
||||
*/
|
||||
public function addInitRoboFileCommand($roboFile, $roboClass)
|
||||
{
|
||||
$createRoboFile = new Command('init');
|
||||
$createRoboFile->setDescription("Intitalizes basic RoboFile in current dir");
|
||||
$createRoboFile->setCode(function (InputInterface $input, OutputInterface $output) use ($roboClass, $roboFile) {
|
||||
$output->writeln("<comment> ~~~ Welcome to Robo! ~~~~ </comment>");
|
||||
$output->writeln("<comment> " . basename($roboFile) . " will be created in the current directory </comment>");
|
||||
file_put_contents(
|
||||
$roboFile,
|
||||
'<?php'
|
||||
. "\n/**"
|
||||
. "\n * This is project's console commands configuration for Robo task runner."
|
||||
. "\n *"
|
||||
. "\n * @see https://robo.li/"
|
||||
. "\n */"
|
||||
. "\nclass " . $roboClass . " extends \\Robo\\Tasks\n{\n // define public methods as commands\n}"
|
||||
);
|
||||
$output->writeln("<comment> Edit this file to add your commands! </comment>");
|
||||
});
|
||||
$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 || !class_exists('\SelfUpdate\SelfUpdateCommand') || empty(\Phar::running())) {
|
||||
return;
|
||||
}
|
||||
$selfUpdateCommand = new \SelfUpdate\SelfUpdateCommand($this->getName(), $this->getVersion(), $repository);
|
||||
$this->add($selfUpdateCommand);
|
||||
}
|
||||
}
|
||||
26
vendor/consolidation/robo/src/ClassDiscovery/AbstractClassDiscovery.php
vendored
Normal file
26
vendor/consolidation/robo/src/ClassDiscovery/AbstractClassDiscovery.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\ClassDiscovery;
|
||||
|
||||
/**
|
||||
* Class AbstractClassDiscovery
|
||||
*
|
||||
* @package Robo\ClassDiscovery
|
||||
*/
|
||||
abstract class AbstractClassDiscovery implements ClassDiscoveryInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $searchPattern = '*.php';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSearchPattern($searchPattern)
|
||||
{
|
||||
$this->searchPattern = $searchPattern;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
30
vendor/consolidation/robo/src/ClassDiscovery/ClassDiscoveryInterface.php
vendored
Normal file
30
vendor/consolidation/robo/src/ClassDiscovery/ClassDiscoveryInterface.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\ClassDiscovery;
|
||||
|
||||
/**
|
||||
* Interface ClassDiscoveryInterface
|
||||
*
|
||||
* @package Robo\Plugin\ClassDiscovery
|
||||
*/
|
||||
interface ClassDiscoveryInterface
|
||||
{
|
||||
/**
|
||||
* @param string $searchPattern
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSearchPattern($searchPattern);
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getClasses();
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFile($class);
|
||||
}
|
||||
114
vendor/consolidation/robo/src/ClassDiscovery/RelativeNamespaceDiscovery.php
vendored
Normal file
114
vendor/consolidation/robo/src/ClassDiscovery/RelativeNamespaceDiscovery.php
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\ClassDiscovery;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Composer\Autoload\ClassLoader;
|
||||
|
||||
/**
|
||||
* Class RelativeNamespaceDiscovery
|
||||
*
|
||||
* @package Robo\Plugin\ClassDiscovery
|
||||
*/
|
||||
class RelativeNamespaceDiscovery extends AbstractClassDiscovery
|
||||
{
|
||||
/**
|
||||
* @var \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
protected $classLoader;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $relativeNamespace = '';
|
||||
|
||||
/**
|
||||
* RelativeNamespaceDiscovery constructor.
|
||||
*
|
||||
* @param \Composer\Autoload\ClassLoader $classLoader
|
||||
*/
|
||||
public function __construct(ClassLoader $classLoader)
|
||||
{
|
||||
$this->classLoader = $classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relativeNamespace
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRelativeNamespace($relativeNamespace)
|
||||
{
|
||||
$this->relativeNamespace = $relativeNamespace;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClasses()
|
||||
{
|
||||
$classes = [];
|
||||
$relativePath = $this->convertNamespaceToPath($this->relativeNamespace);
|
||||
|
||||
foreach ($this->classLoader->getPrefixesPsr4() as $baseNamespace => $directories) {
|
||||
$directories = array_filter(array_map(function ($directory) use ($relativePath) {
|
||||
return $directory . $relativePath;
|
||||
}, $directories), 'is_dir');
|
||||
|
||||
if ($directories) {
|
||||
foreach ($this->search($directories, $this->searchPattern) as $file) {
|
||||
$relativePathName = $file->getRelativePathname();
|
||||
$classes[] = $baseNamespace . $this->convertPathToNamespace($relativePath . '/' . $relativePathName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFile($class)
|
||||
{
|
||||
return $this->classLoader->findFile($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $directories
|
||||
* @param string $pattern
|
||||
*
|
||||
* @return \Symfony\Component\Finder\Finder
|
||||
*/
|
||||
protected function search($directories, $pattern)
|
||||
{
|
||||
$finder = new Finder();
|
||||
$finder->files()
|
||||
->name($pattern)
|
||||
->in($directories);
|
||||
|
||||
return $finder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function convertPathToNamespace($path)
|
||||
{
|
||||
return str_replace(['/', '.php'], ['\\', ''], trim($path, '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convertNamespaceToPath($namespace)
|
||||
{
|
||||
return '/' . str_replace("\\", '/', trim($namespace, '\\'));
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
53
vendor/consolidation/robo/src/Common/BuilderAwareTrait.php
vendored
Normal file
53
vendor/consolidation/robo/src/Common/BuilderAwareTrait.php
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Collection\CollectionBuilder;
|
||||
use Robo\Robo;
|
||||
use Robo\Symfony\ConsoleIO;
|
||||
|
||||
trait BuilderAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* @see \Robo\Contract\BuilderAwareInterface::setBuilder()
|
||||
*
|
||||
* @param \Robo\Collection\CollectionBuilder $builder
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBuilder(CollectionBuilder $builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Robo\Contract\BuilderAwareInterface::getBuilder()
|
||||
*
|
||||
* @return \Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
public function getBuilder()
|
||||
{
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Collection\CollectionBuilder
|
||||
*
|
||||
* @param \Robo\Symfony\ConsoleIO $io
|
||||
*/
|
||||
protected function collectionBuilder($io = null)
|
||||
{
|
||||
// TODO: trigger_error if $io is null. Eventually this shim will be removed.
|
||||
if (!$io) {
|
||||
$io = new ConsoleIO(Robo::input(), Robo::output());
|
||||
}
|
||||
return $this->getBuilder()->newBuilder()->inflect($this)->inflect($io);
|
||||
}
|
||||
}
|
||||
137
vendor/consolidation/robo/src/Common/CommandArguments.php
vendored
Normal file
137
vendor/consolidation/robo/src/Common/CommandArguments.php
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Common\ProcessUtils;
|
||||
|
||||
/**
|
||||
* Use this to add arguments and options to the $arguments property.
|
||||
*/
|
||||
trait CommandArguments
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $arguments = '';
|
||||
|
||||
/**
|
||||
* Pass argument to executable. Its value will be automatically escaped.
|
||||
*
|
||||
* @param string $arg
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function arg($arg)
|
||||
{
|
||||
return $this->args($arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass methods parameters as arguments to executable. Argument values
|
||||
* are automatically escaped.
|
||||
*
|
||||
* @param string|string[] $args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function args($args)
|
||||
{
|
||||
$func_args = func_get_args();
|
||||
if (!is_array($args)) {
|
||||
$args = $func_args;
|
||||
}
|
||||
$this->arguments .= ' ' . implode(' ', array_map([static::class, 'escape'], $args));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape the provided value, unless it contains only alphanumeric
|
||||
* plus a few other basic characters.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function escape($value)
|
||||
{
|
||||
if (preg_match('/^[a-zA-Z0-9\/\.@~_-]+$/', $value)) {
|
||||
return $value;
|
||||
}
|
||||
return ProcessUtils::escapeArgument($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass option to executable. Options are prefixed with `--` , value can be provided in second parameter.
|
||||
* Option values are automatically escaped.
|
||||
*
|
||||
* @param string $option
|
||||
* @param string $value
|
||||
* @param string $separator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 ? '' : $separator . static::escape($value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param array $options
|
||||
* @param string $separator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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(), $separator = ' ')
|
||||
{
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
$this->optionList($option, $item, $separator);
|
||||
}
|
||||
} else {
|
||||
$this->option($option, $value, $separator);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
31
vendor/consolidation/robo/src/Common/CommandReceiver.php
vendored
Normal file
31
vendor/consolidation/robo/src/Common/CommandReceiver.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Exception\TaskException;
|
||||
|
||||
/**
|
||||
* This task can receive commands from task implementing CommandInterface.
|
||||
*/
|
||||
trait CommandReceiver
|
||||
{
|
||||
/**
|
||||
* @param string|\Robo\Contract\CommandInterface $command
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Robo\Exception\TaskException
|
||||
*/
|
||||
protected function receiveCommand($command)
|
||||
{
|
||||
if (!is_object($command)) {
|
||||
return $command;
|
||||
}
|
||||
if ($command instanceof CommandInterface) {
|
||||
return $command->getCommand();
|
||||
} else {
|
||||
throw new TaskException($this, get_class($command) . " does not implement CommandInterface, so can't be passed into this task");
|
||||
}
|
||||
}
|
||||
}
|
||||
105
vendor/consolidation/robo/src/Common/ConfigAwareTrait.php
vendored
Normal file
105
vendor/consolidation/robo/src/Common/ConfigAwareTrait.php
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Robo;
|
||||
use Consolidation\Config\ConfigInterface;
|
||||
|
||||
trait ConfigAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \Consolidation\Config\ConfigInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Set the config management object.
|
||||
*
|
||||
* @param \Consolidation\Config\ConfigInterface $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfig(ConfigInterface $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config management object.
|
||||
*
|
||||
* @return \Consolidation\Config\ConfigInterface
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
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
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function getClassKey($key)
|
||||
{
|
||||
$configPrefix = static::configPrefix(); // task.
|
||||
$configClass = static::configClassIdentifier(static::class); // PARTIAL_NAMESPACE.CLASSNAME
|
||||
$configPostFix = static::configPostfix(); // .settings
|
||||
|
||||
return sprintf('%s%s%s.%s', $configPrefix, $configClass, $configPostFix, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param \Consolidation\Config\ConfigInterface|null $config
|
||||
*/
|
||||
public static function configure($key, $value, $config = null)
|
||||
{
|
||||
if (!$config) {
|
||||
$config = Robo::config();
|
||||
}
|
||||
$config->setDefault(static::getClassKey($key), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
protected function getConfigValue($key, $default = null)
|
||||
{
|
||||
if (!$this->getConfig()) {
|
||||
return $default;
|
||||
}
|
||||
return $this->getConfig()->get(static::getClassKey($key), $default);
|
||||
}
|
||||
}
|
||||
46
vendor/consolidation/robo/src/Common/DynamicParams.php
vendored
Normal file
46
vendor/consolidation/robo/src/Common/DynamicParams.php
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
/**
|
||||
* Simplifies generating of configuration chanined methods.
|
||||
* You can only define configuration properties and use magic methods to set them.
|
||||
* Methods will be named the same way as properties.
|
||||
* * Boolean properties are switched on/off if no values is provided.
|
||||
* * Array properties can accept non-array values, in this case value will be appended to array.
|
||||
* You should also define phpdoc for methods.
|
||||
*/
|
||||
trait DynamicParams
|
||||
{
|
||||
/**
|
||||
* @param string $property
|
||||
* @param array $args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($property, $args)
|
||||
{
|
||||
if (!property_exists($this, $property)) {
|
||||
throw new \RuntimeException("Property $property in task " . get_class($this) . ' does not exists');
|
||||
}
|
||||
|
||||
// toggle boolean values
|
||||
if (!isset($args[0]) and (is_bool($this->$property))) {
|
||||
$this->$property = !$this->$property;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// append item to array
|
||||
if (is_array($this->$property)) {
|
||||
if (is_array($args[0])) {
|
||||
$this->$property = $args[0];
|
||||
} else {
|
||||
array_push($this->$property, $args[0]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->$property = $args[0];
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
152
vendor/consolidation/robo/src/Common/ExecCommand.php
vendored
Normal file
152
vendor/consolidation/robo/src/Common/ExecCommand.php
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Result;
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* This task is supposed to be executed as shell command.
|
||||
* You can specify working directory and if output is printed.
|
||||
*/
|
||||
trait ExecCommand
|
||||
{
|
||||
use ExecTrait;
|
||||
|
||||
/**
|
||||
* @var \Robo\Common\TimeKeeper
|
||||
*/
|
||||
protected $execTimer;
|
||||
|
||||
/**
|
||||
* @return \Robo\Common\TimeKeeper
|
||||
*/
|
||||
protected function getExecTimer()
|
||||
{
|
||||
if (!isset($this->execTimer)) {
|
||||
$this->execTimer = new TimeKeeper();
|
||||
}
|
||||
return $this->execTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a "{$cmd}.phar" in the current working
|
||||
* directory; return a string to exec it if it is
|
||||
* found. Otherwise, look for an executable command
|
||||
* of the same name via findExecutable.
|
||||
*
|
||||
* @param string $cmd
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function findExecutablePhar($cmd)
|
||||
{
|
||||
if (file_exists("{$cmd}.phar")) {
|
||||
return "php {$cmd}.phar";
|
||||
}
|
||||
return $this->findExecutable($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the best path to the executable program
|
||||
* with the provided name. Favor vendor/bin in the
|
||||
* current project. If not found there, use
|
||||
* whatever is on the $PATH.
|
||||
*
|
||||
* @param string $cmd
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function findExecutable($cmd)
|
||||
{
|
||||
$pathToCmd = $this->searchForExecutable($cmd);
|
||||
if ($pathToCmd) {
|
||||
return $this->useCallOnWindows($pathToCmd);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cmd
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function searchForExecutable($cmd)
|
||||
{
|
||||
$projectBin = $this->findProjectBin();
|
||||
|
||||
$localComposerInstallation = $projectBin . DIRECTORY_SEPARATOR . $cmd;
|
||||
if (file_exists($localComposerInstallation)) {
|
||||
return $localComposerInstallation;
|
||||
}
|
||||
$finder = new ExecutableFinder();
|
||||
return $finder->find($cmd, null, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function findProjectBin()
|
||||
{
|
||||
$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.
|
||||
$vendorDirContainingUs = realpath(__DIR__ . '/../../../..');
|
||||
if (is_dir($vendorDirContainingUs) && (basename($vendorDirContainingUs) == 'vendor')) {
|
||||
array_unshift($candidates, $vendorDirContainingUs . '/bin');
|
||||
}
|
||||
|
||||
foreach ($candidates as $dir) {
|
||||
if (is_dir("$dir")) {
|
||||
return realpath($dir);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap Windows executables in 'call' per 7a88757d
|
||||
*
|
||||
* @param string $cmd
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function useCallOnWindows($cmd)
|
||||
{
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
if (file_exists("{$cmd}.bat")) {
|
||||
$cmd = "{$cmd}.bat";
|
||||
}
|
||||
return "call $cmd";
|
||||
}
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCommandDescription()
|
||||
{
|
||||
return $this->process->getCommandLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $command
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function executeCommand($command)
|
||||
{
|
||||
// TODO: Symfony 4 requires that we supply the working directory.
|
||||
$result_data = $this->execute(Process::fromShellCommandline($command, getcwd()));
|
||||
return new Result(
|
||||
$this,
|
||||
$result_data->getExitCode(),
|
||||
$result_data->getMessage(),
|
||||
$result_data->getData()
|
||||
);
|
||||
}
|
||||
}
|
||||
13
vendor/consolidation/robo/src/Common/ExecOneCommand.php
vendored
Normal file
13
vendor/consolidation/robo/src/Common/ExecOneCommand.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
/**
|
||||
* This task specifies exactly one shell command.
|
||||
* It can take additional arguments and options as config parameters.
|
||||
*/
|
||||
trait ExecOneCommand
|
||||
{
|
||||
use ExecCommand;
|
||||
use CommandArguments;
|
||||
}
|
||||
470
vendor/consolidation/robo/src/Common/ExecTrait.php
vendored
Normal file
470
vendor/consolidation/robo/src/Common/ExecTrait.php
vendored
Normal file
@ -0,0 +1,470 @@
|
||||
<?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();
|
||||
|
||||
/**
|
||||
* @see \Robo\Common\ProgressIndicatorAwareTrait
|
||||
* @see \Robo\Common\Timer
|
||||
*/
|
||||
abstract protected function startTimer();
|
||||
|
||||
/**
|
||||
* @see \Robo\Common\ProgressIndicatorAwareTrait
|
||||
* @see \Robo\Common\Timer
|
||||
*/
|
||||
abstract protected function stopTimer();
|
||||
|
||||
/**
|
||||
* @return null|float
|
||||
*
|
||||
* @see \Robo\Common\ProgressIndicatorAwareTrait
|
||||
* @see \Robo\Common\Timer
|
||||
*/
|
||||
abstract protected function getExecutionTime();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @see \Robo\Common\TaskIO
|
||||
*/
|
||||
abstract protected function hideTaskProgress();
|
||||
|
||||
/**
|
||||
* @param bool $inProgress
|
||||
*
|
||||
* @see \Robo\Common\TaskIO
|
||||
*/
|
||||
abstract protected function showTaskProgress($inProgress);
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param null|array $context
|
||||
*
|
||||
* @see \Robo\Common\TaskIO
|
||||
*/
|
||||
abstract protected function printTaskInfo($text, $context = null);
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @see \Robo\Common\VerbosityThresholdTrait
|
||||
*/
|
||||
abstract public function verbosityMeetsThreshold();
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*
|
||||
* @see \Robo\Common\VerbosityThresholdTrait
|
||||
*/
|
||||
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)
|
||||
*
|
||||
* @param bool $arg
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param string|array $env
|
||||
* @param bool|string $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 = $this->env ? $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 setProcessInput($input)
|
||||
{
|
||||
$this->input = $input;
|
||||
// A tty should not be allocated when the input is provided.
|
||||
$this->interactive(false);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass an input to the process. Can be resource created with fopen() or string
|
||||
*
|
||||
* @param resource|string $input
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
trigger_error('setInput() is deprecated. Please use setProcessInput(().', E_USER_DEPRECATED);
|
||||
$this->input = $input;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach tty to process for interactive input
|
||||
*
|
||||
* @param bool $interactive
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
trigger_error('printed() is deprecated. Please use printOutput().', E_USER_DEPRECATED);
|
||||
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 \Symfony\Component\Process\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());
|
||||
$result = new ResultData(
|
||||
$this->process->getExitCode(),
|
||||
$output,
|
||||
$this->getResultData()
|
||||
);
|
||||
$result->provideOutputdata();
|
||||
return $result;
|
||||
}
|
||||
|
||||
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 string $command
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
230
vendor/consolidation/robo/src/Common/IO.php
vendored
Normal file
230
vendor/consolidation/robo/src/Common/IO.php
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Symfony\ConsoleIO;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Consolidation\AnnotatedCommand\State\State;
|
||||
|
||||
trait IO
|
||||
{
|
||||
use InputAwareTrait;
|
||||
use OutputAwareTrait;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Style\SymfonyStyle
|
||||
*/
|
||||
protected $io;
|
||||
|
||||
public function currentState()
|
||||
{
|
||||
return new class($this, $this->input, $this->output, $this->io) implements State {
|
||||
protected $obj;
|
||||
protected $input;
|
||||
protected $output;
|
||||
protected $io;
|
||||
|
||||
public function __construct($obj, $input, $output, $io)
|
||||
{
|
||||
$this->obj = $obj;
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->io = $io;
|
||||
}
|
||||
|
||||
public function restore()
|
||||
{
|
||||
$this->obj->restoreState($this->input, $this->output, $this->io);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// This should typically only be called by State::restore()
|
||||
public function restoreState(?InputInterface $input = null, ?OutputInterface $output = null, ?SymfonyStyle $io = null)
|
||||
{
|
||||
$this->setInput($input);
|
||||
$this->setOutput($output);
|
||||
$this->io = $io;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setInput(InputInterface $input): void
|
||||
{
|
||||
if ($input != $this->input) {
|
||||
$this->io = null;
|
||||
}
|
||||
$this->input = $input;
|
||||
}
|
||||
|
||||
public function setOutput(OutputInterface $output)
|
||||
{
|
||||
if ($output != $this->output) {
|
||||
$this->io = null;
|
||||
}
|
||||
$this->output = $output;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to SymfonyStyle object.
|
||||
*
|
||||
* @deprecated Use a style injector instead
|
||||
*
|
||||
* @return \Symfony\Component\Console\Style\SymfonyStyle
|
||||
*
|
||||
* @see https://symfony.com/blog/new-in-symfony-2-8-console-style-guide
|
||||
*/
|
||||
protected function io()
|
||||
{
|
||||
if (!$this->io) {
|
||||
$this->io = new ConsoleIO($this->input(), $this->output());
|
||||
}
|
||||
return $this->io;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nonDecorated
|
||||
* @param string $decorated
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function decorationCharacter($nonDecorated, $decorated)
|
||||
{
|
||||
if (!$this->output()->isDecorated() || (strncasecmp(PHP_OS, 'WIN', 3) == 0)) {
|
||||
return $nonDecorated;
|
||||
}
|
||||
return $decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*/
|
||||
protected function say($text)
|
||||
{
|
||||
$char = $this->decorationCharacter('>', '➜');
|
||||
$this->writeln("$char $text");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param int $length
|
||||
* @param string $color
|
||||
*/
|
||||
protected function yell($text, $length = 40, $color = 'green')
|
||||
{
|
||||
$char = $this->decorationCharacter(' ', '➜');
|
||||
$format = "$char <fg=white;bg=$color;options=bold>%s</fg=white;bg=$color;options=bold>";
|
||||
$this->formattedOutput($text, $length, $format);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param int $length
|
||||
* @param string $format
|
||||
*/
|
||||
protected function formattedOutput($text, $length, $format)
|
||||
{
|
||||
$lines = explode("\n", trim($text, "\n"));
|
||||
$maxLineLength = array_reduce(array_map('strlen', $lines), 'max');
|
||||
$length = max($length, $maxLineLength);
|
||||
$len = $length + 2;
|
||||
$space = str_repeat(' ', $len);
|
||||
$this->writeln(sprintf($format, $space));
|
||||
foreach ($lines as $line) {
|
||||
$line = str_pad($line, $length, ' ', STR_PAD_BOTH);
|
||||
$this->writeln(sprintf($format, " $line "));
|
||||
}
|
||||
$this->writeln(sprintf($format, $space));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $question
|
||||
* @param bool $hideAnswer
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function ask($question, $hideAnswer = false)
|
||||
{
|
||||
if ($hideAnswer) {
|
||||
return $this->askHidden($question);
|
||||
}
|
||||
return $this->doAsk(new Question($this->formatQuestion($question)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $question
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function askHidden($question)
|
||||
{
|
||||
$question = new Question($this->formatQuestion($question));
|
||||
$question->setHidden(true);
|
||||
return $this->doAsk($question);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $question
|
||||
* @param string $default
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function askDefault($question, $default)
|
||||
{
|
||||
return $this->doAsk(new Question($this->formatQuestion("$question [$default]"), $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $question
|
||||
* @param bool $default
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function confirm($question, $default = false)
|
||||
{
|
||||
return $this->doAsk(new ConfirmationQuestion($this->formatQuestion($question . ' (y/n)'), $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Question\Question $question
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function doAsk(Question $question)
|
||||
{
|
||||
return $this->getDialog()->ask($this->input(), $this->output(), $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatQuestion($message)
|
||||
{
|
||||
return "<question>? $message</question> ";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\Console\Helper\QuestionHelper
|
||||
*/
|
||||
protected function getDialog()
|
||||
{
|
||||
return new QuestionHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
*/
|
||||
protected function writeln($text)
|
||||
{
|
||||
$this->output()->writeln($text);
|
||||
}
|
||||
}
|
||||
24
vendor/consolidation/robo/src/Common/InflectionTrait.php
vendored
Normal file
24
vendor/consolidation/robo/src/Common/InflectionTrait.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Contract\InflectionInterface;
|
||||
|
||||
trait InflectionTrait
|
||||
{
|
||||
/**
|
||||
* Ask the provided parent class to inject all of the dependencies
|
||||
* that it has and we need.
|
||||
*
|
||||
* @param \Robo\Contract\InflectionInterface|mixed $parent
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function inflect($parent)
|
||||
{
|
||||
if (isset($parent) && ($parent instanceof InflectionInterface)) {
|
||||
$parent->injectDependencies($this);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
47
vendor/consolidation/robo/src/Common/InputAwareTrait.php
vendored
Normal file
47
vendor/consolidation/robo/src/Common/InputAwareTrait.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
trait InputAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Input\InputInterface
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
*
|
||||
* @see \Symfony\Component\Console\Input\InputAwareInterface::setInput()
|
||||
*/
|
||||
public function setInput(InputInterface $input): void
|
||||
{
|
||||
$this->input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\Console\Input\InputInterface
|
||||
*/
|
||||
protected function input()
|
||||
{
|
||||
if (!isset($this->input)) {
|
||||
$this->setInput(new ArgvInput());
|
||||
}
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards compatibility.
|
||||
*
|
||||
* @return \Symfony\Component\Console\Input\InputInterface
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
protected function getInput()
|
||||
{
|
||||
return $this->input();
|
||||
}
|
||||
}
|
||||
48
vendor/consolidation/robo/src/Common/OutputAdapter.php
vendored
Normal file
48
vendor/consolidation/robo/src/Common/OutputAdapter.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
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,
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function verbosityMeetsThreshold($verbosityThreshold)
|
||||
{
|
||||
if (!isset($this->verbosityMap[$verbosityThreshold])) {
|
||||
return true;
|
||||
}
|
||||
$verbosityThreshold = $this->verbosityMap[$verbosityThreshold];
|
||||
$verbosity = $this->output()->getVerbosity();
|
||||
|
||||
return $verbosity >= $verbosityThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function writeMessage($message)
|
||||
{
|
||||
$this->output()->write($message);
|
||||
}
|
||||
}
|
||||
64
vendor/consolidation/robo/src/Common/OutputAwareTrait.php
vendored
Normal file
64
vendor/consolidation/robo/src/Common/OutputAwareTrait.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
trait OutputAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @see \Robo\Contract\OutputAwareInterface::setOutput()
|
||||
*/
|
||||
public function setOutput(OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
protected function output()
|
||||
{
|
||||
if (!isset($this->output)) {
|
||||
$this->setOutput(new NullOutput());
|
||||
}
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
protected function stderr()
|
||||
{
|
||||
$output = $this->output();
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards compatibility
|
||||
*
|
||||
* @return \Symfony\Component\Console\Output\OutputInterface
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
protected function getOutput()
|
||||
{
|
||||
return $this->output();
|
||||
}
|
||||
}
|
||||
55
vendor/consolidation/robo/src/Common/ProcessExecutor.php
vendored
Normal file
55
vendor/consolidation/robo/src/Common/ProcessExecutor.php
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Process\Process $process
|
||||
*/
|
||||
public function __construct(Process $process)
|
||||
{
|
||||
$this->process = $process;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
* @param \Symfony\Component\Process\Process $process
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCommandDescription()
|
||||
{
|
||||
return $this->process->getCommandLine();
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
return $this->execute($this->process);
|
||||
}
|
||||
}
|
||||
81
vendor/consolidation/robo/src/Common/ProcessUtils.php
vendored
Normal file
81
vendor/consolidation/robo/src/Common/ProcessUtils.php
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
<?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.
|
||||
*
|
||||
* This method is a copy of a method that was deprecated by Symfony 3.3 and
|
||||
* removed in Symfony 4; it will be removed once there is an actual
|
||||
* replacement for escapeArgument.
|
||||
*
|
||||
* @param string $argument
|
||||
* The argument that will be escaped.
|
||||
*
|
||||
* @return string
|
||||
* The escaped argument.
|
||||
*/
|
||||
public static function escapeArgument($argument)
|
||||
{
|
||||
//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];
|
||||
}
|
||||
}
|
||||
206
vendor/consolidation/robo/src/Common/ProgressIndicator.php
vendored
Normal file
206
vendor/consolidation/robo/src/Common/ProgressIndicator.php
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
|
||||
/**
|
||||
* Wrapper around \Symfony\Component\Console\Helper\ProgressBar
|
||||
*/
|
||||
class ProgressIndicator
|
||||
{
|
||||
use Timer;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Helper\ProgressBar
|
||||
*/
|
||||
protected $progressBar;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $progressIndicatorRunning = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $autoDisplayInterval = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $cachedSteps = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $totalSteps = 0;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $progressBarDisplayed = false;
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface
|
||||
*/
|
||||
protected $owner;
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Helper\ProgressBar $progressBar
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*/
|
||||
public function __construct($progressBar, \Symfony\Component\Console\Output\OutputInterface $output)
|
||||
{
|
||||
$this->progressBar = $progressBar;
|
||||
$this->output = $output instanceof ConsoleOutputInterface ?
|
||||
$output->getErrorOutput()
|
||||
: $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $interval
|
||||
*/
|
||||
public function setProgressBarAutoDisplayInterval($interval)
|
||||
{
|
||||
if ($this->progressIndicatorRunning) {
|
||||
return;
|
||||
}
|
||||
$this->autoDisplayInterval = $interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hideProgressIndicator()
|
||||
{
|
||||
$result = $this->progressBarDisplayed;
|
||||
if ($this->progressIndicatorRunning && $this->progressBarDisplayed) {
|
||||
$this->progressBar->clear();
|
||||
// Hack: progress indicator does not reset cursor to beginning of line on 'clear'
|
||||
$this->output->write("\x0D");
|
||||
$this->progressBarDisplayed = false;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function showProgressIndicator()
|
||||
{
|
||||
if ($this->progressIndicatorRunning && !$this->progressBarDisplayed && isset($this->progressBar)) {
|
||||
$this->progressBar->display();
|
||||
$this->progressBarDisplayed = true;
|
||||
$this->advanceProgressIndicatorCachedSteps();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $visible
|
||||
*/
|
||||
public function restoreProgressIndicator($visible)
|
||||
{
|
||||
if ($visible) {
|
||||
$this->showProgressIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $totalSteps
|
||||
* @param \Robo\Contract\TaskInterface $owner
|
||||
*/
|
||||
public function startProgressIndicator($totalSteps, $owner)
|
||||
{
|
||||
if (!isset($this->progressBar)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->progressIndicatorRunning = true;
|
||||
if (!isset($this->owner)) {
|
||||
$this->owner = $owner;
|
||||
$this->startTimer();
|
||||
$this->totalSteps = $totalSteps;
|
||||
$this->autoShowProgressIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
public function autoShowProgressIndicator()
|
||||
{
|
||||
if (($this->autoDisplayInterval < 0) || !isset($this->progressBar) || !$this->output->isDecorated()) {
|
||||
return;
|
||||
}
|
||||
if ($this->autoDisplayInterval <= $this->getExecutionTime()) {
|
||||
$this->autoDisplayInterval = -1;
|
||||
$this->progressBar->start($this->totalSteps);
|
||||
$this->showProgressIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function inProgress()
|
||||
{
|
||||
return $this->progressIndicatorRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $owner
|
||||
*/
|
||||
public function stopProgressIndicator($owner)
|
||||
{
|
||||
if ($this->progressIndicatorRunning && ($this->owner === $owner)) {
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanup()
|
||||
{
|
||||
$this->progressIndicatorRunning = false;
|
||||
$this->owner = null;
|
||||
if ($this->progressBarDisplayed) {
|
||||
$this->progressBar->finish();
|
||||
// Hack: progress indicator does not always finish cleanly
|
||||
$this->output->writeln('');
|
||||
$this->progressBarDisplayed = false;
|
||||
}
|
||||
$this->stopTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase progress indicator and ensure it never returns. Used
|
||||
* only during error handlers or to permanently remove the progress bar.
|
||||
*/
|
||||
public function disableProgressIndicator()
|
||||
{
|
||||
$this->cleanup();
|
||||
// ProgressIndicator is shared, so this permanently removes
|
||||
// the program's ability to display progress bars.
|
||||
$this->progressBar = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $steps
|
||||
*/
|
||||
public function advanceProgressIndicator($steps = 1)
|
||||
{
|
||||
$this->cachedSteps += $steps;
|
||||
if ($this->progressIndicatorRunning) {
|
||||
$this->autoShowProgressIndicator();
|
||||
// We only want to call `advance` if the progress bar is visible,
|
||||
// because it always displays itself when it is advanced.
|
||||
if ($this->progressBarDisplayed) {
|
||||
return $this->advanceProgressIndicatorCachedSteps();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function advanceProgressIndicatorCachedSteps()
|
||||
{
|
||||
$this->progressBar->advance($this->cachedSteps);
|
||||
$this->cachedSteps = 0;
|
||||
}
|
||||
}
|
||||
137
vendor/consolidation/robo/src/Common/ProgressIndicatorAwareTrait.php
vendored
Normal file
137
vendor/consolidation/robo/src/Common/ProgressIndicatorAwareTrait.php
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
|
||||
trait ProgressIndicatorAwareTrait
|
||||
{
|
||||
use Timer;
|
||||
|
||||
/**
|
||||
* @var null|\Robo\Common\ProgressIndicator
|
||||
*/
|
||||
protected $progressIndicator;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function progressIndicatorSteps()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|\Robo\Common\ProgressIndicator $progressIndicator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProgressIndicator($progressIndicator)
|
||||
{
|
||||
$this->progressIndicator = $progressIndicator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|bool
|
||||
*/
|
||||
protected function hideProgressIndicator()
|
||||
{
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
return $this->progressIndicator->hideProgressIndicator();
|
||||
}
|
||||
|
||||
protected function showProgressIndicator()
|
||||
{
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
$this->progressIndicator->showProgressIndicator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $visible
|
||||
*/
|
||||
protected function restoreProgressIndicator($visible)
|
||||
{
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
$this->progressIndicator->restoreProgressIndicator($visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function getTotalExecutionTime()
|
||||
{
|
||||
if (!$this->progressIndicator) {
|
||||
return 0;
|
||||
}
|
||||
return $this->progressIndicator->getExecutionTime();
|
||||
}
|
||||
|
||||
protected function startProgressIndicator()
|
||||
{
|
||||
$this->startTimer();
|
||||
if ($this instanceof VerbosityThresholdInterface
|
||||
&& !$this->verbosityMeetsThreshold()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
$totalSteps = $this->progressIndicatorSteps();
|
||||
$this->progressIndicator->startProgressIndicator($totalSteps, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function inProgress()
|
||||
{
|
||||
if (!$this->progressIndicator) {
|
||||
return false;
|
||||
}
|
||||
return $this->progressIndicator->inProgress();
|
||||
}
|
||||
|
||||
protected function stopProgressIndicator()
|
||||
{
|
||||
$this->stopTimer();
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
$this->progressIndicator->stopProgressIndicator($this);
|
||||
}
|
||||
|
||||
protected function disableProgressIndicator()
|
||||
{
|
||||
$this->stopTimer();
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
$this->progressIndicator->disableProgressIndicator();
|
||||
}
|
||||
|
||||
protected function detatchProgressIndicator()
|
||||
{
|
||||
$this->setProgressIndicator(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $steps
|
||||
*/
|
||||
protected function advanceProgressIndicator($steps = 1)
|
||||
{
|
||||
if (!$this->progressIndicator) {
|
||||
return;
|
||||
}
|
||||
$this->progressIndicator->advanceProgressIndicator($steps);
|
||||
}
|
||||
}
|
||||
121
vendor/consolidation/robo/src/Common/ResourceExistenceChecker.php
vendored
Normal file
121
vendor/consolidation/robo/src/Common/ResourceExistenceChecker.php
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
trait ResourceExistenceChecker
|
||||
{
|
||||
/**
|
||||
* Checks if the given input is a file or folder.
|
||||
*
|
||||
* @param string|string[] $resources
|
||||
* @param string $type
|
||||
* Allowed values: "file", "dir", "fileAndDir"
|
||||
*
|
||||
* @return bool
|
||||
* True if no errors were encountered otherwise false.
|
||||
*/
|
||||
protected function checkResources($resources, $type = 'fileAndDir')
|
||||
{
|
||||
if (!in_array($type, ['file', 'dir', 'fileAndDir'])) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid resource check of type "%s" used!', $type));
|
||||
}
|
||||
if (is_string($resources)) {
|
||||
$resources = [$resources];
|
||||
}
|
||||
$success = true;
|
||||
foreach ($resources as $resource) {
|
||||
$glob = glob($resource);
|
||||
if ($glob === false) {
|
||||
$this->printTaskError(sprintf('Invalid glob "%s"!', $resource), $this);
|
||||
$success = false;
|
||||
continue;
|
||||
}
|
||||
foreach ($glob as $resource) {
|
||||
if (!$this->checkResource($resource, $type)) {
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a single resource, file or directory.
|
||||
*
|
||||
* It will print an error as well on the console.
|
||||
*
|
||||
* @param string $resource
|
||||
* File or folder.
|
||||
* @param string $type
|
||||
* Allowed values: "file", "dir", "fileAndDir".
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkResource($resource, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'file':
|
||||
if (!$this->isFile($resource)) {
|
||||
$this->printTaskError(sprintf('File "%s" does not exist!', $resource), $this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case 'dir':
|
||||
if (!$this->isDir($resource)) {
|
||||
$this->printTaskError(sprintf('Directory "%s" does not exist!', $resource), $this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case 'fileAndDir':
|
||||
if (!$this->isDir($resource) && !$this->isFile($resource)) {
|
||||
$this->printTaskError(sprintf('File or directory "%s" does not exist!', $resource), $this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to check the often uses "source => target" file / folder arrays.
|
||||
*
|
||||
* @param string|array $resources
|
||||
*/
|
||||
protected function checkSourceAndTargetResource($resources)
|
||||
{
|
||||
if (is_string($resources)) {
|
||||
$resources = [$resources];
|
||||
}
|
||||
$sources = [];
|
||||
$targets = [];
|
||||
foreach ($resources as $source => $target) {
|
||||
$sources[] = $source;
|
||||
$target[] = $target;
|
||||
}
|
||||
$this->checkResources($sources);
|
||||
$this->checkResources($targets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method around phps is_dir()
|
||||
*
|
||||
* @param string $directory
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDir($directory)
|
||||
{
|
||||
return is_dir($directory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper method around phps file_exists()
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isFile($file)
|
||||
{
|
||||
return file_exists($file);
|
||||
}
|
||||
}
|
||||
262
vendor/consolidation/robo/src/Common/TaskIO.php
vendored
Normal file
262
vendor/consolidation/robo/src/Common/TaskIO.php
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Robo;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Log\RoboLogLevel;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\LoggerInterface;
|
||||
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 TaskIO
|
||||
{
|
||||
use ConfigAwareTrait;
|
||||
use VerbosityThresholdTrait;
|
||||
use OutputAwareTrait;
|
||||
use LoggerAwareTrait;
|
||||
|
||||
protected $output;
|
||||
|
||||
public function setOutput(OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
$this->resetLoggerOutput();
|
||||
}
|
||||
|
||||
private function resetLoggerOutput()
|
||||
{
|
||||
if (isset($this->output) && isset($this->logger) && ($this->logger instanceof \Robo\Log\Logger)) {
|
||||
$this->logger->setErrorStream(null);
|
||||
$this->logger->setOutputStream($this->output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|\Psr\Log\LoggerInterface
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function logger()
|
||||
{
|
||||
// $this->logger should always be set in Robo core tasks.
|
||||
if ($this->logger) {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
// TODO: Remove call to Robo::logger() once maintaining backwards
|
||||
// compatibility with legacy external Robo tasks is no longer desired.
|
||||
if (!Robo::logger()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static $gaveDeprecationWarning = false;
|
||||
if (!$gaveDeprecationWarning) {
|
||||
trigger_error('No logger set for ' . get_class($this) . '. Use $this->task(Foo::class) rather than new Foo() in Tasks to ensure the builder can initialize task the task, or use $this->collectionBuilder()->taskFoo() if creating one task from within another.', E_USER_DEPRECATED);
|
||||
$gaveDeprecationWarning = true;
|
||||
}
|
||||
return Robo::logger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Print information about a task in progress.
|
||||
*
|
||||
* With the Symfony Console logger, NOTICE is displayed at VERBOSITY_VERBOSE
|
||||
* and INFO is displayed at VERBOSITY_VERY_VERBOSE.
|
||||
*
|
||||
* Robo overrides the default such that NOTICE is displayed at
|
||||
* VERBOSITY_NORMAL and INFO is displayed at VERBOSITY_VERBOSE.
|
||||
*
|
||||
* n.b. We should probably have printTaskNotice for our ordinary
|
||||
* output, and use printTaskInfo for less interesting messages.
|
||||
*
|
||||
* @param string $text
|
||||
* @param null|array $context
|
||||
*/
|
||||
protected function printTaskInfo($text, $context = null)
|
||||
{
|
||||
// The 'note' style is used for both 'notice' and 'info' log levels;
|
||||
// However, 'notice' is printed at VERBOSITY_NORMAL, whereas 'info'
|
||||
// is only printed at VERBOSITY_VERBOSE.
|
||||
$this->printTaskOutput(LogLevel::NOTICE, $text, $this->getTaskContext($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide notification that some part of the task succeeded.
|
||||
*
|
||||
* With the Symfony Console logger, success messages are remapped to NOTICE,
|
||||
* and displayed in VERBOSITY_VERBOSE. When used with the Robo logger,
|
||||
* success messages are displayed at VERBOSITY_NORMAL.
|
||||
*
|
||||
* @param string $text
|
||||
* @param null|array $context
|
||||
*/
|
||||
protected function printTaskSuccess($text, $context = null)
|
||||
{
|
||||
// Not all loggers will recognize RoboLogLevel::SUCCESS.
|
||||
// We therefore log as LogLevel::NOTICE, and apply a '_level'
|
||||
// override in the context so that this message will be
|
||||
// logged as SUCCESS if that log level is recognized.
|
||||
$context['_level'] = RoboLogLevel::SUCCESS;
|
||||
$this->printTaskOutput(LogLevel::NOTICE, $text, $this->getTaskContext($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide notification that there is something wrong, but
|
||||
* execution can continue.
|
||||
*
|
||||
* Warning messages are displayed at VERBOSITY_NORMAL.
|
||||
*
|
||||
* @param string $text
|
||||
* @param null|array $context
|
||||
*/
|
||||
protected function printTaskWarning($text, $context = null)
|
||||
{
|
||||
$this->printTaskOutput(LogLevel::WARNING, $text, $this->getTaskContext($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide notification that some operation in the task failed,
|
||||
* and the task cannot continue.
|
||||
*
|
||||
* Error messages are displayed at VERBOSITY_NORMAL.
|
||||
*
|
||||
* @param string $text
|
||||
* @param null|array $context
|
||||
*/
|
||||
protected function printTaskError($text, $context = null)
|
||||
{
|
||||
$this->printTaskOutput(LogLevel::ERROR, $text, $this->getTaskContext($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide debugging notification. These messages are only
|
||||
* displayed if the log level is VERBOSITY_DEBUG.
|
||||
*
|
||||
* @param string$text
|
||||
* @param null|array $context
|
||||
*/
|
||||
protected function printTaskDebug($text, $context = null)
|
||||
{
|
||||
$this->printTaskOutput(LogLevel::DEBUG, $text, $this->getTaskContext($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $level
|
||||
* One of the \Psr\Log\LogLevel constant
|
||||
* @param string $text
|
||||
* @param null|array $context
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
protected function printTaskOutput($level, $text, $context)
|
||||
{
|
||||
if (!$this->verbosityMeetsThreshold()) {
|
||||
return;
|
||||
}
|
||||
$logger = $this->logger();
|
||||
if (!$logger) {
|
||||
return;
|
||||
}
|
||||
// Hide the progress indicator, if it is visible.
|
||||
$inProgress = $this->hideTaskProgress();
|
||||
$logger->log($level, $text, $this->getTaskContext($context));
|
||||
// After we have printed our log message, redraw the progress indicator.
|
||||
$this->showTaskProgress($inProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function hideTaskProgress()
|
||||
{
|
||||
$inProgress = false;
|
||||
if ($this instanceof ProgressIndicatorAwareInterface) {
|
||||
$inProgress = $this->inProgress();
|
||||
}
|
||||
|
||||
// If a progress indicator is running on this task, then we mush
|
||||
// hide it before we print anything, or its display will be overwritten.
|
||||
if ($inProgress) {
|
||||
$inProgress = $this->hideProgressIndicator();
|
||||
}
|
||||
return $inProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $inProgress
|
||||
*/
|
||||
protected function showTaskProgress($inProgress)
|
||||
{
|
||||
if ($inProgress) {
|
||||
$this->restoreProgressIndicator($inProgress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a quantity of bytes.
|
||||
*
|
||||
* @param int $size
|
||||
* @param int $precision
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatBytes($size, $precision = 2)
|
||||
{
|
||||
if ($size === 0) {
|
||||
return 0;
|
||||
}
|
||||
$base = log($size, 1024);
|
||||
$suffixes = array('', 'k', 'M', 'G', 'T');
|
||||
return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted task name for use in task output.
|
||||
* This is placed in the task context under 'name', and
|
||||
* used as the log label by Robo\Common\RoboLogStyle,
|
||||
* which is inserted at the head of log messages by
|
||||
* Robo\Common\CustomLogStyle::formatMessage().
|
||||
*
|
||||
* @param null|object $task
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getPrintedTaskName($task = null)
|
||||
{
|
||||
if (!$task) {
|
||||
$task = $this;
|
||||
}
|
||||
return TaskInfo::formatTaskName($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|array $context
|
||||
*
|
||||
* @return array
|
||||
* Context information.
|
||||
*/
|
||||
protected function getTaskContext($context = null)
|
||||
{
|
||||
if (!$context) {
|
||||
$context = [];
|
||||
}
|
||||
if (!is_array($context)) {
|
||||
$context = ['task' => $context];
|
||||
}
|
||||
if (!array_key_exists('task', $context)) {
|
||||
$context['task'] = $this;
|
||||
}
|
||||
|
||||
return $context + TaskInfo::getTaskContext($context['task']);
|
||||
}
|
||||
}
|
||||
76
vendor/consolidation/robo/src/Common/TimeKeeper.php
vendored
Normal file
76
vendor/consolidation/robo/src/Common/TimeKeeper.php
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
class TimeKeeper
|
||||
{
|
||||
const MINUTE = 60;
|
||||
const HOUR = 3600;
|
||||
const DAY = 86400;
|
||||
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
protected $startedAt;
|
||||
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
protected $finishedAt;
|
||||
|
||||
public function start()
|
||||
{
|
||||
if ($this->startedAt) {
|
||||
return;
|
||||
}
|
||||
// Get time in seconds as a float, accurate to the microsecond.
|
||||
$this->startedAt = microtime(true);
|
||||
}
|
||||
|
||||
public function stop()
|
||||
{
|
||||
$this->finishedAt = microtime(true);
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->startedAt = $this->finishedAt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|null
|
||||
*/
|
||||
public function elapsed()
|
||||
{
|
||||
$finished = $this->finishedAt ? $this->finishedAt : microtime(true);
|
||||
if ($finished - $this->startedAt <= 0) {
|
||||
return null;
|
||||
}
|
||||
return $finished - $this->startedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a duration into a human-readable time.
|
||||
*
|
||||
* @param float $duration
|
||||
* Duration in seconds, with fractional component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function formatDuration($duration)
|
||||
{
|
||||
if ($duration >= self::DAY * 2) {
|
||||
return gmdate('z \d\a\y\s H:i:s', (int) $duration);
|
||||
}
|
||||
if ($duration >= self::DAY) {
|
||||
return gmdate('\1 \d\a\y H:i:s', (int) $duration);
|
||||
}
|
||||
if ($duration >= self::HOUR) {
|
||||
return gmdate("H:i:s", (int) $duration);
|
||||
}
|
||||
if ($duration >= self::MINUTE) {
|
||||
return gmdate("i:s", (int) $duration);
|
||||
}
|
||||
return round($duration, 3) . 's';
|
||||
}
|
||||
}
|
||||
43
vendor/consolidation/robo/src/Common/Timer.php
vendored
Normal file
43
vendor/consolidation/robo/src/Common/Timer.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
trait Timer
|
||||
{
|
||||
/**
|
||||
* @var \Robo\Common\TimeKeeper|null
|
||||
*/
|
||||
protected $timer;
|
||||
|
||||
protected function startTimer()
|
||||
{
|
||||
if (!isset($this->timer)) {
|
||||
$this->timer = new TimeKeeper();
|
||||
}
|
||||
$this->timer->start();
|
||||
}
|
||||
|
||||
protected function stopTimer()
|
||||
{
|
||||
if (!isset($this->timer)) {
|
||||
return;
|
||||
}
|
||||
$this->timer->stop();
|
||||
}
|
||||
|
||||
protected function resetTimer()
|
||||
{
|
||||
$this->timer->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|null
|
||||
*/
|
||||
protected function getExecutionTime()
|
||||
{
|
||||
if (!isset($this->timer)) {
|
||||
return null;
|
||||
}
|
||||
return $this->timer->elapsed();
|
||||
}
|
||||
}
|
||||
100
vendor/consolidation/robo/src/Common/VerbosityThresholdTrait.php
vendored
Normal file
100
vendor/consolidation/robo/src/Common/VerbosityThresholdTrait.php
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Common;
|
||||
|
||||
use Robo\Robo;
|
||||
use Robo\TaskInfo;
|
||||
use Robo\Contract\OutputAdapterInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
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 \Robo\Contract\OutputAdapterInterface
|
||||
*/
|
||||
protected $outputAdapter;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $verbosityThreshold = 0;
|
||||
|
||||
/**
|
||||
* Required verbosity level before any TaskIO output will be produced.
|
||||
* e.g. OutputInterface::VERBOSITY_VERBOSE
|
||||
*
|
||||
* @param int $verbosityThreshold
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setVerbosityThreshold($verbosityThreshold)
|
||||
{
|
||||
$this->verbosityThreshold = $verbosityThreshold;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function verbosityThreshold()
|
||||
{
|
||||
return $this->verbosityThreshold;
|
||||
}
|
||||
|
||||
public function setOutputAdapter(OutputAdapterInterface $outputAdapter)
|
||||
{
|
||||
$this->outputAdapter = $outputAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\OutputAdapterInterface
|
||||
*/
|
||||
public function outputAdapter()
|
||||
{
|
||||
return $this->outputAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasOutputAdapter()
|
||||
{
|
||||
return isset($this->outputAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
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 threshold.
|
||||
*
|
||||
* @param string $message
|
||||
*/
|
||||
public function writeMessage($message)
|
||||
{
|
||||
if (!$this->verbosityMeetsThreshold()) {
|
||||
return;
|
||||
}
|
||||
$this->outputAdapter()->writeMessage($message);
|
||||
}
|
||||
}
|
||||
10
vendor/consolidation/robo/src/Config.php
vendored
Normal file
10
vendor/consolidation/robo/src/Config.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
/**
|
||||
* @deprecated Use \Robo\Config\Config
|
||||
*/
|
||||
class Config extends \Robo\Config\Config
|
||||
{
|
||||
}
|
||||
171
vendor/consolidation/robo/src/Config/Config.php
vendored
Normal file
171
vendor/consolidation/robo/src/Config/Config.php
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Config;
|
||||
|
||||
use Consolidation\Config\Util\ConfigOverlay;
|
||||
use Consolidation\Config\ConfigInterface;
|
||||
|
||||
class Config extends ConfigOverlay 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';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $defaults;
|
||||
|
||||
/**
|
||||
* Create a new configuration object, and initialize it with
|
||||
* the provided nested array containing configuration data.
|
||||
*/
|
||||
public function __construct(array $data = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->import($data ?: []);
|
||||
$this->defaults = $this->getGlobalOptionDefaultValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import($data)
|
||||
{
|
||||
return $this->replace($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function replace($data)
|
||||
{
|
||||
$this->getContext(ConfigOverlay::DEFAULT_CONTEXT)->replace($data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function combine($data)
|
||||
{
|
||||
$this->getContext(ConfigOverlay::DEFAULT_CONTEXT)->combine($data);
|
||||
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 $this->trimPrefixFromGlobalOptions($globalOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the 'options.' prefix from the global options list.
|
||||
*
|
||||
* @param array $globalOptions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
18
vendor/consolidation/robo/src/Config/GlobalOptionDefaultValuesInterface.php
vendored
Normal file
18
vendor/consolidation/robo/src/Config/GlobalOptionDefaultValuesInterface.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Config;
|
||||
|
||||
/**
|
||||
* @deprecated Use robo.yml instead
|
||||
*
|
||||
* robo.yml:
|
||||
*
|
||||
* options:
|
||||
* simulated: false
|
||||
* progress-delay: 2
|
||||
*
|
||||
* etc.
|
||||
*/
|
||||
interface GlobalOptionDefaultValuesInterface extends \Consolidation\Config\GlobalOptionDefaultValuesInterface
|
||||
{
|
||||
}
|
||||
22
vendor/consolidation/robo/src/Contract/BuilderAwareInterface.php
vendored
Normal file
22
vendor/consolidation/robo/src/Contract/BuilderAwareInterface.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
use Robo\Collection\CollectionBuilder;
|
||||
|
||||
interface BuilderAwareInterface
|
||||
{
|
||||
/**
|
||||
* Set the builder reference
|
||||
*
|
||||
* @param \Robo\Collection\CollectionBuilder $builder
|
||||
*/
|
||||
public function setBuilder(CollectionBuilder $builder);
|
||||
|
||||
/**
|
||||
* Get the builder reference
|
||||
*
|
||||
* @return \Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
public function getBuilder();
|
||||
}
|
||||
21
vendor/consolidation/robo/src/Contract/CommandInterface.php
vendored
Normal file
21
vendor/consolidation/robo/src/Contract/CommandInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Task that implements this interface can be injected as a parameter for other task.
|
||||
* This task can be represented as executable command.
|
||||
*
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface CommandInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns command that can be executed.
|
||||
* This method is used to pass generated command from one task to another.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCommand();
|
||||
}
|
||||
19
vendor/consolidation/robo/src/Contract/CompletionInterface.php
vendored
Normal file
19
vendor/consolidation/robo/src/Contract/CompletionInterface.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Any Robo tasks that implements this interface will
|
||||
* be called when the task collection it is added to
|
||||
* completes.
|
||||
*
|
||||
* Interface CompletionInterface
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface CompletionInterface extends TaskInterface
|
||||
{
|
||||
/**
|
||||
* Revert an operation that can be rolled back
|
||||
*/
|
||||
public function complete();
|
||||
}
|
||||
7
vendor/consolidation/robo/src/Contract/ConfigAwareInterface.php
vendored
Normal file
7
vendor/consolidation/robo/src/Contract/ConfigAwareInterface.php
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
interface ConfigAwareInterface extends \Consolidation\Config\ConfigAwareInterface
|
||||
{
|
||||
}
|
||||
14
vendor/consolidation/robo/src/Contract/IOAwareInterface.php
vendored
Normal file
14
vendor/consolidation/robo/src/Contract/IOAwareInterface.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Marker interface for tasks that use the IO trait
|
||||
*/
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
use Symfony\Component\Console\Input\InputAwareInterface;
|
||||
use Consolidation\AnnotatedCommand\State\SavableState;
|
||||
|
||||
interface IOAwareInterface extends OutputAwareInterface, InputAwareInterface, SavableState
|
||||
{
|
||||
}
|
||||
52
vendor/consolidation/robo/src/Contract/InflectionInterface.php
vendored
Normal file
52
vendor/consolidation/robo/src/Contract/InflectionInterface.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
interface InflectionInterface
|
||||
{
|
||||
/**
|
||||
* Based on league/container inflection: https://container.thephpleague.com/4.x/inflectors/
|
||||
*
|
||||
* This allows us to run:
|
||||
*
|
||||
* (new SomeTask($args))
|
||||
* ->inflect($this)
|
||||
* ->initializer()
|
||||
* ->...
|
||||
*
|
||||
* Instead of:
|
||||
*
|
||||
* (new SomeTask($args))
|
||||
* ->setLogger($this->logger)
|
||||
* ->initializer()
|
||||
* ->...
|
||||
*
|
||||
* The reason `inflect` is better than the more explicit alternative is
|
||||
* that subclasses of BaseTask that implement a new FooAwareInterface
|
||||
* can override injectDependencies() as explained below, and add more
|
||||
* dependencies that can be injected as needed.
|
||||
*
|
||||
* @param \Robo\Contract\InflectionInterface $parent
|
||||
*/
|
||||
public function inflect($parent);
|
||||
|
||||
/**
|
||||
* Take all dependencies availble to this task and inject any that are
|
||||
* needed into the provided task. The general pattern is that, for every
|
||||
* FooAwareInterface that this class implements, it should test to see
|
||||
* if the child also implements the same interface, and if so, should call
|
||||
* $child->setFoo($this->foo).
|
||||
*
|
||||
* The benefits of this are pretty large. Any time an object that implements
|
||||
* InflectionInterface is created, just call `$child->inflect($this)`, and
|
||||
* any available optional dependencies will be hooked up via setter injection.
|
||||
*
|
||||
* The required dependencies of an object should be provided via constructor
|
||||
* injection, not inflection.
|
||||
*
|
||||
* @param mixed $child An object with one or more *AwareInterfaces implemented.
|
||||
*
|
||||
* @see https://mwop.net/blog/2016-04-26-on-locators.html
|
||||
*/
|
||||
public function injectDependencies($child);
|
||||
}
|
||||
21
vendor/consolidation/robo/src/Contract/OutputAdapterInterface.php
vendored
Normal file
21
vendor/consolidation/robo/src/Contract/OutputAdapterInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Adapt OutputInterface or other output function to the VerbosityThresholdInterface.
|
||||
*/
|
||||
interface OutputAdapterInterface
|
||||
{
|
||||
/**
|
||||
* @param int $verbosityThreshold
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verbosityMeetsThreshold($verbosityThreshold);
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function writeMessage($message);
|
||||
}
|
||||
16
vendor/consolidation/robo/src/Contract/OutputAwareInterface.php
vendored
Normal file
16
vendor/consolidation/robo/src/Contract/OutputAwareInterface.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Provide OutputAwareInterface, not present in Symfony Console
|
||||
*/
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @deprecated Use \Consolidation\AnnotatedCommand\Output\OutputAwareInterface directly
|
||||
*/
|
||||
interface OutputAwareInterface extends \Consolidation\AnnotatedCommand\Output\OutputAwareInterface
|
||||
{
|
||||
}
|
||||
17
vendor/consolidation/robo/src/Contract/PrintedInterface.php
vendored
Normal file
17
vendor/consolidation/robo/src/Contract/PrintedInterface.php
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* If task prints anything to console
|
||||
*
|
||||
* Interface PrintedInterface
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface PrintedInterface
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getPrinted();
|
||||
}
|
||||
25
vendor/consolidation/robo/src/Contract/ProgressIndicatorAwareInterface.php
vendored
Normal file
25
vendor/consolidation/robo/src/Contract/ProgressIndicatorAwareInterface.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Any Robo task that uses the Timer trait and
|
||||
* implements ProgressIndicatorAwareInterface will
|
||||
* display a progress bar while the timer is running.
|
||||
* Call advanceProgressIndicator to advance the indicator.
|
||||
*
|
||||
* Interface ProgressIndicatorAwareInterface
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface ProgressIndicatorAwareInterface
|
||||
{
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function progressIndicatorSteps();
|
||||
|
||||
/**
|
||||
* @param \Robo\Common\ProgressIndicator $progressIndicator
|
||||
*/
|
||||
public function setProgressIndicator($progressIndicator);
|
||||
}
|
||||
19
vendor/consolidation/robo/src/Contract/ProgressInterface.php
vendored
Normal file
19
vendor/consolidation/robo/src/Contract/ProgressInterface.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Robo tasks that take multiple steps to complete should
|
||||
* implement this interface.
|
||||
*
|
||||
* Interface ProgressInterface
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface ProgressInterface
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function progressSteps();
|
||||
}
|
||||
19
vendor/consolidation/robo/src/Contract/RollbackInterface.php
vendored
Normal file
19
vendor/consolidation/robo/src/Contract/RollbackInterface.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Any Robo tasks that implements this interface will
|
||||
* be called when the task collection it is added to
|
||||
* fails, and runs its rollback operation.
|
||||
*
|
||||
* Interface RollbackInterface
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface RollbackInterface extends TaskInterface
|
||||
{
|
||||
/**
|
||||
* Revert an operation that can be rolled back
|
||||
*/
|
||||
public function rollback();
|
||||
}
|
||||
19
vendor/consolidation/robo/src/Contract/SimulatedInterface.php
vendored
Normal file
19
vendor/consolidation/robo/src/Contract/SimulatedInterface.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* Task that implements this interface can be injected as a parameter for other task.
|
||||
* This task can be represented as executable command.
|
||||
*
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface SimulatedInterface extends TaskInterface
|
||||
{
|
||||
/**
|
||||
* Called in place of `run()` for simulated tasks.
|
||||
*
|
||||
* @param null|array $context
|
||||
*/
|
||||
public function simulate($context);
|
||||
}
|
||||
18
vendor/consolidation/robo/src/Contract/TaskInterface.php
vendored
Normal file
18
vendor/consolidation/robo/src/Contract/TaskInterface.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
/**
|
||||
* All Robo tasks should implement this interface.
|
||||
* Task should be configured by chained methods.
|
||||
*
|
||||
* Interface TaskInterface
|
||||
* @package Robo\Contract
|
||||
*/
|
||||
interface TaskInterface
|
||||
{
|
||||
/**
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
public function run();
|
||||
}
|
||||
54
vendor/consolidation/robo/src/Contract/VerbosityThresholdInterface.php
vendored
Normal file
54
vendor/consolidation/robo/src/Contract/VerbosityThresholdInterface.php
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @param int $verbosityThreshold
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setVerbosityThreshold($verbosityThreshold);
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function verbosityThreshold();
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\OutputAdapterInterface $outputAdapter
|
||||
*/
|
||||
public function setOutputAdapter(OutputAdapterInterface $outputAdapter);
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\OutputAdapterInterface
|
||||
*/
|
||||
public function outputAdapter();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasOutputAdapter();
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function verbosityMeetsThreshold();
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function writeMessage($message);
|
||||
}
|
||||
11
vendor/consolidation/robo/src/Contract/WrappedTaskInterface.php
vendored
Normal file
11
vendor/consolidation/robo/src/Contract/WrappedTaskInterface.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Contract;
|
||||
|
||||
interface WrappedTaskInterface extends TaskInterface
|
||||
{
|
||||
/**
|
||||
* @return \Robo\Contract\TaskInterface
|
||||
*/
|
||||
public function original();
|
||||
}
|
||||
14
vendor/consolidation/robo/src/Exception/AbortTasksException.php
vendored
Normal file
14
vendor/consolidation/robo/src/Exception/AbortTasksException.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Exception;
|
||||
|
||||
/**
|
||||
* By default, rollbacks and completions tasks or callbacks continue even if
|
||||
* errors occur. If you would like to explicitly cancel or abort the rollback or
|
||||
* completion, you may throw this exception to abort the subsequent tasks in the
|
||||
* rollback or completion task list.
|
||||
*/
|
||||
class AbortTasksException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
21
vendor/consolidation/robo/src/Exception/TaskException.php
vendored
Normal file
21
vendor/consolidation/robo/src/Exception/TaskException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Exception;
|
||||
|
||||
class TaskException extends \Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* TaskException constructor.
|
||||
*
|
||||
* @param string|object $class
|
||||
* @param string $message
|
||||
*/
|
||||
public function __construct($class, $message)
|
||||
{
|
||||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
parent::__construct(" in task $class \n\n $message");
|
||||
}
|
||||
}
|
||||
22
vendor/consolidation/robo/src/Exception/TaskExitException.php
vendored
Normal file
22
vendor/consolidation/robo/src/Exception/TaskExitException.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Exception;
|
||||
|
||||
class TaskExitException extends \Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* TaskExitException constructor.
|
||||
*
|
||||
* @param string|object $class
|
||||
* @param string $message
|
||||
* @param int $status
|
||||
*/
|
||||
public function __construct($class, $message, $status)
|
||||
{
|
||||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
parent::__construct(" in task $class \n\n $message", $status);
|
||||
}
|
||||
}
|
||||
161
vendor/consolidation/robo/src/GlobalOptionsEventListener.php
vendored
Normal file
161
vendor/consolidation/robo/src/GlobalOptionsEventListener.php
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\Event\ConsoleCommandEvent;
|
||||
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 \Robo\Application
|
||||
*/
|
||||
protected $application;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix;
|
||||
|
||||
/**
|
||||
* GlobalOptionsEventListener listener
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->prefix = 'options';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a reference to the Symfony Console application object.
|
||||
*
|
||||
* @param \Robo\Application $application
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setApplication($application)
|
||||
{
|
||||
$this->application = $application;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stipulate the prefix to use for option injection.
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGlobalOptionsPrefix($prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before a Console command runs, examine the global
|
||||
* commandline options from the event Input, and set
|
||||
* configuration values as appropriate.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event
|
||||
*/
|
||||
public function setGlobalOptions(ConsoleCommandEvent $event)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$input = $event->getInput();
|
||||
|
||||
$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($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 `-Dconfig.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.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
42
vendor/consolidation/robo/src/LoadAllTasks.php
vendored
Normal file
42
vendor/consolidation/robo/src/LoadAllTasks.php
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
trait LoadAllTasks
|
||||
{
|
||||
use TaskAccessor;
|
||||
|
||||
use Collection\Tasks;
|
||||
|
||||
// standard tasks
|
||||
use Task\Base\Tasks;
|
||||
use Task\Development\Tasks;
|
||||
use Task\Filesystem\Tasks;
|
||||
use Task\File\Tasks;
|
||||
use Task\Archive\Tasks;
|
||||
use Task\Vcs\Tasks;
|
||||
use Task\Logfile\Tasks;
|
||||
|
||||
// package managers
|
||||
use Task\Composer\Tasks;
|
||||
use Task\Bower\Tasks;
|
||||
use Task\Npm\Tasks;
|
||||
|
||||
// assets
|
||||
use Task\Assets\Tasks;
|
||||
|
||||
// 3rd-party tools
|
||||
use Task\Remote\Tasks;
|
||||
use Task\Testing\Tasks;
|
||||
use Task\ApiGen\Tasks;
|
||||
use Task\Docker\Tasks;
|
||||
|
||||
// task runners
|
||||
use Task\Gulp\Tasks;
|
||||
|
||||
// shortcuts
|
||||
use Task\Base\Shortcuts;
|
||||
use Task\Filesystem\Shortcuts;
|
||||
use Task\Vcs\Shortcuts;
|
||||
use Task\Logfile\Shortcuts;
|
||||
}
|
||||
120
vendor/consolidation/robo/src/Log/ResultPrinter.php
vendored
Normal file
120
vendor/consolidation/robo/src/Log/ResultPrinter.php
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Log;
|
||||
|
||||
use Robo\Log\RoboLogLevel;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\LogLevel;
|
||||
use Robo\Common\ProgressIndicatorAwareTrait;
|
||||
use Robo\Contract\OutputAwareInterface;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Contract\ProgressIndicatorAwareInterface;
|
||||
use Robo\Contract\VerbosityThresholdInterface;
|
||||
use Robo\Result;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Log the creation of Result objects.
|
||||
*/
|
||||
class ResultPrinter implements LoggerAwareInterface, ProgressIndicatorAwareInterface, OutputAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
use ProgressIndicatorAwareTrait;
|
||||
|
||||
public function setOutput(OutputInterface $output)
|
||||
{
|
||||
$this->logger->setErrorStream(null);
|
||||
$this->logger->setOutputStream($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the result of a Robo task.
|
||||
*
|
||||
* Returns 'true' if the message is printed, or false if it isn't.
|
||||
*
|
||||
* @param \Robo\Result $result
|
||||
*
|
||||
* @return null|bool
|
||||
*/
|
||||
public function printResult(Result $result)
|
||||
{
|
||||
$task = $result->getTask();
|
||||
if ($task instanceof VerbosityThresholdInterface && !$task->verbosityMeetsThreshold()) {
|
||||
return;
|
||||
}
|
||||
if (!$result->wasSuccessful()) {
|
||||
return $this->printError($result);
|
||||
} else {
|
||||
return $this->printSuccess($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log that we are about to abort due to an error being encountered
|
||||
* in 'stop on fail' mode.
|
||||
*
|
||||
* @param \Robo\Result $result
|
||||
*/
|
||||
public function printStopOnFail($result)
|
||||
{
|
||||
$this->printMessage(LogLevel::NOTICE, 'Stopping on fail. Exiting....');
|
||||
$this->printMessage(LogLevel::ERROR, 'Exit Code: {code}', ['code' => $result->getExitCode()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the result of a Robo task that returned an error.
|
||||
*
|
||||
* @param \Robo\Result $result
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function printError(Result $result)
|
||||
{
|
||||
$task = $result->getTask();
|
||||
$context = $result->getContext() + ['timer-label' => 'Time', '_style' => []];
|
||||
$context['_style']['message'] = '';
|
||||
|
||||
$printOutput = true;
|
||||
if ($task instanceof PrintedInterface) {
|
||||
$printOutput = !$task->getPrinted();
|
||||
}
|
||||
if ($printOutput) {
|
||||
$this->printMessage(LogLevel::ERROR, "{message}", $context);
|
||||
}
|
||||
$this->printMessage(LogLevel::ERROR, 'Exit code {code}', $context);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the result of a Robo task that was successful.
|
||||
*
|
||||
* @param \Robo\Result $result
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function printSuccess(Result $result)
|
||||
{
|
||||
$task = $result->getTask();
|
||||
$context = $result->getContext() + ['timer-label' => 'in'];
|
||||
$time = $result->getExecutionTime();
|
||||
if ($time) {
|
||||
$this->printMessage(RoboLogLevel::SUCCESS, 'Done', $context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $level
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*/
|
||||
protected function printMessage($level, $message, $context = [])
|
||||
{
|
||||
$inProgress = $this->hideProgressIndicator();
|
||||
$this->logger->log($level, $message, $context);
|
||||
if ($inProgress) {
|
||||
$this->restoreProgressIndicator($inProgress);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
vendor/consolidation/robo/src/Log/RoboLogLevel.php
vendored
Normal file
17
vendor/consolidation/robo/src/Log/RoboLogLevel.php
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Log;
|
||||
|
||||
class RoboLogLevel extends \Psr\Log\LogLevel
|
||||
{
|
||||
/**
|
||||
* Command did something in simulated mode.
|
||||
* Displayed at VERBOSITY_NORMAL.
|
||||
*/
|
||||
const SIMULATED_ACTION = 'simulated';
|
||||
|
||||
/**
|
||||
* Successful action; equivalent to 'NOTICE'
|
||||
*/
|
||||
const SUCCESS = 'success';
|
||||
}
|
||||
78
vendor/consolidation/robo/src/Log/RoboLogStyle.php
vendored
Normal file
78
vendor/consolidation/robo/src/Log/RoboLogStyle.php
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Log;
|
||||
|
||||
use Robo\Common\TimeKeeper;
|
||||
use Consolidation\Log\LogOutputStyler;
|
||||
|
||||
/**
|
||||
* Robo Log Styler.
|
||||
*/
|
||||
class RoboLogStyle extends LogOutputStyler
|
||||
{
|
||||
const TASK_STYLE_SIMULATED = 'options=reverse;bold';
|
||||
const TASK_STYLE_SUCCESS = 'fg=white;bg=green;options=bold';
|
||||
|
||||
/**
|
||||
* RoboLogStyle constructor.
|
||||
*
|
||||
* @param array $labelStyles
|
||||
* @param array $messageStyles
|
||||
*/
|
||||
public function __construct($labelStyles = [], $messageStyles = [])
|
||||
{
|
||||
parent::__construct($labelStyles, $messageStyles);
|
||||
|
||||
$this->labelStyles += [
|
||||
RoboLogLevel::SIMULATED_ACTION => self::TASK_STYLE_SIMULATED,
|
||||
RoboLogLevel::SUCCESS => self::TASK_STYLE_SUCCESS,
|
||||
];
|
||||
$this->messageStyles += [
|
||||
RoboLogLevel::SIMULATED_ACTION => '',
|
||||
RoboLogLevel::SUCCESS => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Log style customization for Robo: replace the log level with
|
||||
* the task name.
|
||||
*
|
||||
* @param string $level
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatMessageByLevel($level, $message, $context)
|
||||
{
|
||||
$label = $level;
|
||||
if (array_key_exists('name', $context)) {
|
||||
$label = $context['name'];
|
||||
}
|
||||
return $this->formatMessage($label, $message, $context, $this->labelStyles[$level], $this->messageStyles[$level]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log style customization for Robo: add the time indicator to the
|
||||
* end of the log message if it exists in the context.
|
||||
*
|
||||
* @param string $label
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @param string $taskNameStyle
|
||||
* @param string $messageStyle
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatMessage($label, $message, $context, $taskNameStyle, $messageStyle = '')
|
||||
{
|
||||
$message = parent::formatMessage($label, $message, $context, $taskNameStyle, $messageStyle);
|
||||
|
||||
if (array_key_exists('time', $context) && !empty($context['time']) && array_key_exists('timer-label', $context)) {
|
||||
$duration = TimeKeeper::formatDuration($context['time']);
|
||||
$message .= ' ' . $context['timer-label'] . ' ' . $this->wrapFormatString($duration, 'fg=yellow');
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
30
vendor/consolidation/robo/src/Log/RoboLogger.php
vendored
Normal file
30
vendor/consolidation/robo/src/Log/RoboLogger.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Log;
|
||||
|
||||
use Consolidation\Log\Logger;
|
||||
use Psr\Log\LogLevel;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Robo's default logger
|
||||
*/
|
||||
class RoboLogger extends Logger
|
||||
{
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*/
|
||||
public function __construct(OutputInterface $output)
|
||||
{
|
||||
// In Robo, we use log level 'notice' for messages that appear all
|
||||
// the time, and 'info' for messages that appear only during verbose
|
||||
// output. We have no 'very verbose' (-vv) level. 'Debug' is -vvv, as usual.
|
||||
$roboVerbosityOverrides = [
|
||||
RoboLogLevel::SIMULATED_ACTION => OutputInterface::VERBOSITY_NORMAL, // Default is "verbose"
|
||||
RoboLogLevel::SUCCESS => OutputInterface::VERBOSITY_NORMAL, // Same as "NOTICE"
|
||||
LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL, // Default is "verbose"
|
||||
LogLevel::INFO => OutputInterface::VERBOSITY_VERBOSE, // Default is "very verbose"
|
||||
];
|
||||
parent::__construct($output, $roboVerbosityOverrides);
|
||||
}
|
||||
}
|
||||
297
vendor/consolidation/robo/src/Result.php
vendored
Normal file
297
vendor/consolidation/robo/src/Result.php
vendored
Normal file
@ -0,0 +1,297 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
use Robo\Common\InflectionTrait;
|
||||
use Robo\Common\OutputAwareTrait;
|
||||
use Robo\Contract\InflectionInterface;
|
||||
use Robo\Contract\OutputAwareInterface;
|
||||
use Robo\Contract\TaskInterface;
|
||||
use Robo\Exception\TaskExitException;
|
||||
use Robo\Log\ResultPrinter;
|
||||
use Robo\State\Data;
|
||||
|
||||
class Result extends ResultData implements OutputAwareInterface, InflectionInterface
|
||||
{
|
||||
use InflectionTrait;
|
||||
use OutputAwareTrait;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public static $stopOnFail = false;
|
||||
|
||||
/**
|
||||
* @var \Robo\Contract\TaskInterface
|
||||
*/
|
||||
protected $task;
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param int $exitCode
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(TaskInterface $task, $exitCode, $message = '', $data = [])
|
||||
{
|
||||
parent::__construct($exitCode, $message, $data);
|
||||
$this->task = $task;
|
||||
$this->inflect($task);
|
||||
$this->printResult();
|
||||
|
||||
if (self::$stopOnFail) {
|
||||
$this->stopOnFail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tasks should always return a Result. However, they are also
|
||||
* allowed to return NULL or an array to indicate success.
|
||||
*
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param \Robo\Result|\Robo\State\Data|\Robo\ResultData|array|null
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
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
|
||||
// for printing task results.
|
||||
// TODO: Make IO the responsibility of some other class. Maintaining
|
||||
// existing behavior for backwards compatibility. This is undesirable
|
||||
// in the long run, though, as it can result in unwanted repeated input
|
||||
// in task collections et. al.
|
||||
$resultPrinter = $this->resultPrinter();
|
||||
if ($resultPrinter) {
|
||||
if ($resultPrinter->printResult($this)) {
|
||||
$this->alreadyPrinted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param string $extension
|
||||
* @param string $service
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function errorMissingExtension(TaskInterface $task, $extension, $service)
|
||||
{
|
||||
$messageTpl = 'PHP extension required for %s. Please enable %s';
|
||||
$message = sprintf($messageTpl, $service, $extension);
|
||||
|
||||
return self::error($task, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param string $class
|
||||
* @param string $package
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function errorMissingPackage(TaskInterface $task, $class, $package)
|
||||
{
|
||||
$messageTpl = 'Class %s not found. Please install %s Composer package';
|
||||
$message = sprintf($messageTpl, $class, $package);
|
||||
|
||||
return self::error($task, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function error(TaskInterface $task, $message, $data = [])
|
||||
{
|
||||
return new self($task, self::EXITCODE_ERROR, $message, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param \Exception $e
|
||||
* @param array $data
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function fromException(TaskInterface $task, \Exception $e, $data = [])
|
||||
{
|
||||
$exitCode = $e->getCode();
|
||||
if (!$exitCode) {
|
||||
$exitCode = self::EXITCODE_ERROR;
|
||||
}
|
||||
return new self($task, $exitCode, $e->getMessage(), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Contract\TaskInterface $task
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function success(TaskInterface $task, $message = '', $data = [])
|
||||
{
|
||||
return new self($task, self::EXITCODE_OK, $message, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a context useful for logging messages.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getContext()
|
||||
{
|
||||
$task = $this->getTask();
|
||||
|
||||
return TaskInfo::getTaskContext($task) + [
|
||||
'code' => $this->getExitCode(),
|
||||
'data' => $this->getArrayCopy(),
|
||||
'time' => $this->getExecutionTime(),
|
||||
'message' => $this->getMessage(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the results from the most recent task to the accumulated
|
||||
* results from all tasks that have run so far, merging data
|
||||
* as necessary.
|
||||
*
|
||||
* @param int|string $key
|
||||
* @param \Robo\Result $taskResult
|
||||
*/
|
||||
public function accumulate($key, Result $taskResult)
|
||||
{
|
||||
// If the task is unnamed, then all of its data elements
|
||||
// just get merged in at the top-level of the final Result object.
|
||||
if (static::isUnnamed($key)) {
|
||||
$this->merge($taskResult);
|
||||
} elseif (isset($this[$key])) {
|
||||
// There can only be one task with a given name; however, if
|
||||
// there are tasks added 'before' or 'after' the named task,
|
||||
// then the results from these will be stored under the same
|
||||
// name unless they are given a name of their own when added.
|
||||
$current = $this[$key];
|
||||
$this[$key] = $taskResult->merge($current);
|
||||
} else {
|
||||
$this[$key] = $taskResult;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We assume that named values (e.g. for associative array keys)
|
||||
* are non-numeric; numeric keys are presumed to simply be the
|
||||
* index of an array, and therefore insignificant.
|
||||
*
|
||||
* @param int|string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUnnamed($key)
|
||||
{
|
||||
return is_numeric($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\TaskInterface
|
||||
*/
|
||||
public function getTask()
|
||||
{
|
||||
return $this->task;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Contract\TaskInterface
|
||||
*/
|
||||
public function cloneTask()
|
||||
{
|
||||
$reflect = new \ReflectionClass(get_class($this->task));
|
||||
return $reflect->newInstanceArgs(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated since 1.0.
|
||||
*
|
||||
* @see wasSuccessful()
|
||||
*/
|
||||
public function __invoke()
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated: use wasSuccessful() instead.', E_USER_DEPRECATED);
|
||||
return $this->wasSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function stopOnFail()
|
||||
{
|
||||
if (!$this->wasSuccessful()) {
|
||||
$resultPrinter = $this->resultPrinter();
|
||||
if ($resultPrinter) {
|
||||
$resultPrinter->printStopOnFail($this);
|
||||
}
|
||||
$this->exitEarly($this->getExitCode());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResultPrinter
|
||||
*/
|
||||
protected function resultPrinter()
|
||||
{
|
||||
if (isset($this->output)) {
|
||||
// @todo: Stop using logger in ResultPrinter and we won't need this.
|
||||
$logger = Robo::logger();
|
||||
$resultPrinter = new ResultPrinter();
|
||||
$resultPrinter->setLogger($logger);
|
||||
$resultPrinter->setOutput($this->output);
|
||||
return $resultPrinter;
|
||||
}
|
||||
// @deprecated: In the future, Tasks will be required to extend BaseTask
|
||||
return Robo::resultPrinter();
|
||||
}
|
||||
|
||||
public function injectDependencies($child)
|
||||
{
|
||||
if ($child instanceof OutputAwareInterface) {
|
||||
$child->setOutput($this->output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
*
|
||||
* @throws \Robo\Exception\TaskExitException
|
||||
*/
|
||||
private function exitEarly($status)
|
||||
{
|
||||
throw new TaskExitException($this->getTask(), $this->getMessage(), $status);
|
||||
}
|
||||
}
|
||||
111
vendor/consolidation/robo/src/ResultData.php
vendored
Normal file
111
vendor/consolidation/robo/src/ResultData.php
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
use Consolidation\AnnotatedCommand\ExitCodeInterface;
|
||||
use Consolidation\AnnotatedCommand\OutputDataInterface;
|
||||
use Robo\State\Data;
|
||||
|
||||
class ResultData extends Data implements ExitCodeInterface, OutputDataInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $exitCode;
|
||||
|
||||
const EXITCODE_OK = 0;
|
||||
const EXITCODE_ERROR = 1;
|
||||
/** Symfony Console handles these conditions; Robo returns the status
|
||||
code selected by Symfony. These are here for documentation purposes. */
|
||||
const EXITCODE_MISSING_OPTIONS = 2;
|
||||
const EXITCODE_COMMAND_NOT_FOUND = 127;
|
||||
|
||||
/** The command was aborted because the user chose to cancel it at some prompt.
|
||||
This exit code is arbitrarily the same as EX_TEMPFAIL in sysexits.h, although
|
||||
note that shell error codes are distinct from C exit codes, so this alignment
|
||||
not particularly meaningful. */
|
||||
const EXITCODE_USER_CANCEL = 75;
|
||||
|
||||
/**
|
||||
* @param int $exitCode
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct($exitCode = self::EXITCODE_OK, $message = '', $data = [])
|
||||
{
|
||||
$this->exitCode = $exitCode;
|
||||
parent::__construct($message, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function message($message, $data = [])
|
||||
{
|
||||
return new self(self::EXITCODE_OK, $message, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $data
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function cancelled($message = '', $data = [])
|
||||
{
|
||||
return new ResultData(self::EXITCODE_USER_CANCEL, $message, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getExitCode()
|
||||
{
|
||||
return $this->exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getOutputData()
|
||||
{
|
||||
if (!empty($this->message) && !isset($this['already-printed']) && isset($this['provide-outputdata'])) {
|
||||
return $this->message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the message in this data has already been displayed.
|
||||
*/
|
||||
public function alreadyPrinted()
|
||||
{
|
||||
$this['already-printed'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opt-in to providing the result message as the output data
|
||||
*/
|
||||
public function provideOutputdata()
|
||||
{
|
||||
$this['provide-outputdata'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function wasSuccessful()
|
||||
{
|
||||
return $this->exitCode === self::EXITCODE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function wasCancelled()
|
||||
{
|
||||
return $this->exitCode == self::EXITCODE_USER_CANCEL;
|
||||
}
|
||||
}
|
||||
601
vendor/consolidation/robo/src/Robo.php
vendored
Normal file
601
vendor/consolidation/robo/src/Robo.php
vendored
Normal file
@ -0,0 +1,601 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use League\Container\Container;
|
||||
use League\Container\ContainerAwareInterface;
|
||||
use League\Container\Definition\DefinitionInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Robo\Collection\CollectionBuilder;
|
||||
use Robo\Common\ProcessExecutor;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
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\Console\Command\Command;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Manages the container reference and other static data. Favor
|
||||
* using dependency injection wherever possible. Avoid using
|
||||
* this class directly, unless setting up a custom DI container.
|
||||
*/
|
||||
class Robo
|
||||
{
|
||||
const APPLICATION_NAME = 'Robo';
|
||||
private const VERSION = '5.1.0';
|
||||
|
||||
/**
|
||||
* The currently active container object, or NULL if not initialized yet.
|
||||
*
|
||||
* @var \Psr\Container\ContainerInterface|null
|
||||
*/
|
||||
protected static $container;
|
||||
|
||||
/**
|
||||
* Entrypoint for standalone Robo-based tools. See docs/framework.md.
|
||||
*
|
||||
* @param string[] $argv
|
||||
* @param string $commandClasses
|
||||
* @param null|string $appName
|
||||
* @param null|string $appVersion
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @param null|string $repository
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only provide access to the Robo version via Robo::version() so that
|
||||
* roave/backward-compatibility-check does not complain about b/c breaks
|
||||
* when the version number changes.
|
||||
*/
|
||||
public static function version()
|
||||
{
|
||||
return self::VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new global container.
|
||||
*
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
* A new container instance to replace the current.
|
||||
*/
|
||||
public static function setContainer(ContainerInterface $container)
|
||||
{
|
||||
static::$container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the global container.
|
||||
*/
|
||||
public static function unsetContainer()
|
||||
{
|
||||
static::$container = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently active global container.
|
||||
*
|
||||
* @return \Psr\Container\ContainerInterface
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function getContainer()
|
||||
{
|
||||
if (static::$container === null) {
|
||||
throw new \RuntimeException('container is not initialized yet. \Robo\Robo::setContainer() must be called with a real container.');
|
||||
}
|
||||
return static::$container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the container has been initialized, FALSE otherwise.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasContainer()
|
||||
{
|
||||
return static::$container !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a config object and load it from the provided paths.
|
||||
*
|
||||
* @param string[] $paths
|
||||
*
|
||||
* @return \Consolidation\Config\ConfigInterface
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @param string[] $paths
|
||||
* @param null|\Consolidation\Config\ConfigInterface $config
|
||||
*/
|
||||
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 for Robo application.
|
||||
*
|
||||
* After calling this method you may add any additional items you wish
|
||||
* to manage in your application. After you do that, you must call
|
||||
* Robo::finalizeContainer($container) to complete container initialization.
|
||||
*
|
||||
* @param null|\Robo\Application $app
|
||||
* @param null|\Consolidation\Config\ConfigInterface $config
|
||||
* @param null|\Composer\Autoload\ClassLoader $classLoader
|
||||
*
|
||||
* @return \Psr\Container\ContainerInterface
|
||||
*/
|
||||
public static function createContainer($app = null, $config = null, $classLoader = null)
|
||||
{
|
||||
// Do not allow this function to be called more than once.
|
||||
if (static::hasContainer()) {
|
||||
return static::getContainer();
|
||||
}
|
||||
|
||||
if (!$app) {
|
||||
$app = static::createDefaultApplication();
|
||||
}
|
||||
|
||||
if (!$config) {
|
||||
$config = new \Robo\Config\Config();
|
||||
}
|
||||
|
||||
// $input and $output will not be stored in the container at all in the future.
|
||||
$unusedInput = new StringInput('');
|
||||
$unusedOutput = new \Symfony\Component\Console\Output\NullOutput();
|
||||
|
||||
// Set up our dependency injection container.
|
||||
$container = new Container();
|
||||
static::configureContainer($container, $app, $config, $unusedInput, $unusedOutput, $classLoader);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a container and initiailze it. If you wish to *change*
|
||||
* anything defined in the container, then you should call
|
||||
* Robo::createContainer() and Robo::finalizeContainer() instead of this function.
|
||||
*
|
||||
* @param null|\Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @param null|\Robo\Application $app
|
||||
* @param null|\Consolidation\Config\ConfigInterface $config
|
||||
* @param null|\Composer\Autoload\ClassLoader $classLoader
|
||||
*
|
||||
* @deprecated Use createContainer instead
|
||||
*
|
||||
* @return \Psr\Container\ContainerInterface
|
||||
*/
|
||||
public static function createDefaultContainer($input = null, $output = null, $app = null, $config = null, $classLoader = null)
|
||||
{
|
||||
// Do not allow this function to be called more than once.
|
||||
if (static::hasContainer()) {
|
||||
return static::getContainer();
|
||||
}
|
||||
|
||||
if (!$app) {
|
||||
$app = static::createDefaultApplication();
|
||||
}
|
||||
|
||||
if (!$config) {
|
||||
$config = new \Robo\Config\Config();
|
||||
}
|
||||
|
||||
// Set up our dependency injection container.
|
||||
$container = new Container();
|
||||
static::configureContainer($container, $app, $config, $input, $output, $classLoader);
|
||||
static::finalizeContainer($container);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do final initialization to the provided container. Make any necessary
|
||||
* modifications to the container before calling this method.
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public static function finalizeContainer(ContainerInterface $container)
|
||||
{
|
||||
$app = $container->get('application');
|
||||
|
||||
// Set the application dispatcher
|
||||
$app->setDispatcher($container->get('eventDispatcher'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a shared instance to the container. This is to support 3.x and 4.x of league/container.
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
* @param string $id
|
||||
* @param mixed $concrete
|
||||
* @return \League\Container\Definition\DefinitionInterface
|
||||
*/
|
||||
public static function addShared(ContainerInterface $container, string $id, $concrete)
|
||||
{
|
||||
if (method_exists($container, 'addShared')) {
|
||||
return $container->addShared($id, $concrete);
|
||||
} else {
|
||||
return $container->share($id, $concrete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a container with all of the default Robo services.
|
||||
* IMPORTANT: after calling this method, clients MUST call:
|
||||
*
|
||||
* Robo::finalizeContainer($container);
|
||||
*
|
||||
* Any modification to the container should be done prior to fetching
|
||||
* objects from it.
|
||||
*
|
||||
* It is recommended to use Robo::createContainer() instead.
|
||||
*
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
* @param \Symfony\Component\Console\Application $app
|
||||
* @param \Consolidation\Config\ConfigInterface $config
|
||||
* @param null|\Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @param null|\Composer\Autoload\ClassLoader $classLoader
|
||||
*/
|
||||
public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, ConfigInterface $config, $input = null, $output = null, $classLoader = null)
|
||||
{
|
||||
// Self-referential container refernce for the inflector
|
||||
$container->add('container', $container);
|
||||
static::setContainer($container);
|
||||
|
||||
// Create default input and output objects if they were not provided.
|
||||
// TODO: We would like to remove $input and $output from the container
|
||||
// (or always register StringInput('') and NullOutput()). There are
|
||||
// currently three shortcomings preventing this:
|
||||
// 1. The logger cannot be used (we could remove the logger from Robo)
|
||||
// 2. Commands that abort with an exception do not print a message (bug)
|
||||
// 3. The runner tests do not initialize taskIO correctly for all tests
|
||||
if (!$input) {
|
||||
$input = new StringInput('');
|
||||
}
|
||||
if (!$output) {
|
||||
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
|
||||
}
|
||||
if (!$classLoader) {
|
||||
$classLoader = new ClassLoader();
|
||||
}
|
||||
$config->set(Config::DECORATED, $output->isDecorated());
|
||||
$config->set(Config::INTERACTIVE, $input->isInteractive());
|
||||
|
||||
self::addShared($container, 'application', $app);
|
||||
self::addShared($container, 'config', $config);
|
||||
self::addShared($container, 'input', $input);
|
||||
self::addShared($container, 'output', $output);
|
||||
self::addShared($container, 'outputAdapter', \Robo\Common\OutputAdapter::class);
|
||||
self::addShared($container, 'classLoader', $classLoader);
|
||||
|
||||
// Register logging and related services.
|
||||
self::addShared($container, 'logStyler', \Robo\Log\RoboLogStyle::class);
|
||||
self::addShared($container, 'logger', \Robo\Log\RoboLogger::class)
|
||||
->addArgument('output')
|
||||
->addMethodCall('setLogOutputStyler', ['logStyler']);
|
||||
$container->add('progressBar', \Symfony\Component\Console\Helper\ProgressBar::class)
|
||||
->addArgument('output');
|
||||
self::addShared($container, 'progressIndicator', \Robo\Common\ProgressIndicator::class)
|
||||
->addArgument('progressBar')
|
||||
->addArgument('output');
|
||||
self::addShared($container, 'resultPrinter', \Robo\Log\ResultPrinter::class);
|
||||
$container->add('simulator', \Robo\Task\Simulator::class);
|
||||
self::addShared($container, 'globalOptionsEventListener', \Robo\GlobalOptionsEventListener::class)
|
||||
->addMethodCall('setApplication', ['application']);
|
||||
self::addShared($container, 'injectConfigEventListener', \Consolidation\Config\Inject\ConfigForCommand::class)
|
||||
->addArgument('config')
|
||||
->addMethodCall('setApplication', ['application']);
|
||||
self::addShared($container, 'collectionProcessHook', \Robo\Collection\CollectionProcessHook::class);
|
||||
self::addShared($container, 'alterOptionsCommandEvent', \Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent::class)
|
||||
->addArgument('application');
|
||||
self::addShared($container, 'hookManager', \Consolidation\AnnotatedCommand\Hooks\HookManager::class)
|
||||
->addMethodCall('addCommandEvent', ['alterOptionsCommandEvent'])
|
||||
->addMethodCall('addCommandEvent', ['injectConfigEventListener'])
|
||||
->addMethodCall('addCommandEvent', ['globalOptionsEventListener'])
|
||||
->addMethodCall('addResultProcessor', ['collectionProcessHook', '*']);
|
||||
self::addShared($container, 'eventDispatcher', \Symfony\Component\EventDispatcher\EventDispatcher::class)
|
||||
->addMethodCall('addSubscriber', ['hookManager']);
|
||||
self::addShared($container, 'formatterManager', \Consolidation\OutputFormatters\FormatterManager::class)
|
||||
->addMethodCall('addDefaultFormatters', [])
|
||||
->addMethodCall('addDefaultSimplifiers', []);
|
||||
self::addShared($container, 'prepareTerminalWidthOption', \Consolidation\AnnotatedCommand\Options\PrepareTerminalWidthOption::class)
|
||||
->addMethodCall('setApplication', ['application']);
|
||||
self::addShared($container, 'symfonyStyleInjector', \Robo\Symfony\SymfonyStyleInjector::class);
|
||||
self::addShared($container, 'consoleIOInjector', \Robo\Symfony\ConsoleIOInjector::class);
|
||||
self::addShared($container, 'parameterInjection', \Consolidation\AnnotatedCommand\ParameterInjection::class)
|
||||
->addMethodCall('register', ['Symfony\Component\Console\Style\SymfonyStyle', 'symfonyStyleInjector'])
|
||||
->addMethodCall('register', ['Robo\Symfony\ConsoleIO', 'consoleIOInjector']);
|
||||
self::addShared($container, 'commandProcessor', \Consolidation\AnnotatedCommand\CommandProcessor::class)
|
||||
->addArgument('hookManager')
|
||||
->addMethodCall('setFormatterManager', ['formatterManager'])
|
||||
->addMethodCall('addPrepareFormatter', ['prepareTerminalWidthOption'])
|
||||
->addMethodCall('setParameterInjection', ['parameterInjection'])
|
||||
->addMethodCall(
|
||||
'setDisplayErrorFunction',
|
||||
[
|
||||
function ($output, $message) use ($container) {
|
||||
$logger = $container->get('logger');
|
||||
$logger->error($message);
|
||||
}
|
||||
]
|
||||
);
|
||||
self::addShared($container, 'stdinHandler', \Consolidation\AnnotatedCommand\Input\StdinHandler::class);
|
||||
self::addShared($container, 'commandFactory', \Consolidation\AnnotatedCommand\AnnotatedCommandFactory::class)
|
||||
->addMethodCall('setCommandProcessor', ['commandProcessor'])
|
||||
// Public methods from the class Robo\Commo\IO that should not be
|
||||
// added as available commands.
|
||||
->addMethodCall('addIgnoredCommandsRegexp', ['/^currentState$|^restoreState$/']);
|
||||
self::addShared($container, 'relativeNamespaceDiscovery', \Robo\ClassDiscovery\RelativeNamespaceDiscovery::class)
|
||||
->addArgument('classLoader');
|
||||
|
||||
// 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.
|
||||
$app->setAutoExit(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $appName
|
||||
* @param null|string $appVersion
|
||||
*
|
||||
* @return \Robo\Application
|
||||
*/
|
||||
public static function createDefaultApplication($appName = null, $appVersion = null)
|
||||
{
|
||||
$appName = $appName ?: self::APPLICATION_NAME;
|
||||
$appVersion = $appVersion ?: self::version();
|
||||
|
||||
$app = new \Robo\Application($appName, $appVersion);
|
||||
$app->setAutoExit(false);
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Robo League\Container inflectors to the container
|
||||
*
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
*/
|
||||
public static function addInflectors($container)
|
||||
{
|
||||
// Register our various inflectors.
|
||||
$container->inflector(\Robo\Contract\ConfigAwareInterface::class)
|
||||
->invokeMethod('setConfig', ['config']);
|
||||
$container->inflector(\Psr\Log\LoggerAwareInterface::class)
|
||||
->invokeMethod('setLogger', ['logger']);
|
||||
$container->inflector(\League\Container\ContainerAwareInterface::class)
|
||||
->invokeMethod('setContainer', ['container']);
|
||||
$container->inflector(\Symfony\Component\Console\Input\InputAwareInterface::class)
|
||||
->invokeMethod('setInput', ['input']);
|
||||
$container->inflector(\Robo\Contract\OutputAwareInterface::class)
|
||||
->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']);
|
||||
$container->inflector(\Consolidation\AnnotatedCommand\Input\StdinAwareInterface::class)
|
||||
->invokeMethod('setStdinHandler', ['stdinHandler']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a service from the container.
|
||||
*
|
||||
* Use this method if the desired service is not one of those with a dedicated
|
||||
* accessor method below. If it is listed below, those methods are preferred
|
||||
* as they can return useful type hints.
|
||||
*
|
||||
* @param string $id
|
||||
* The ID of the service to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
* The specified service.
|
||||
*/
|
||||
public static function service($id)
|
||||
{
|
||||
return static::getContainer()->get($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a service is defined in the container.
|
||||
*
|
||||
* @param string $id
|
||||
* The ID of the service to check.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the specified service exists, FALSE otherwise.
|
||||
*/
|
||||
public static function hasService($id)
|
||||
{
|
||||
// Check hasContainer() first in order to always return a Boolean.
|
||||
return static::hasContainer() && static::getContainer()->has($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the result printer object.
|
||||
*
|
||||
* @return \Robo\Log\ResultPrinter
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static function resultPrinter()
|
||||
{
|
||||
return static::service('resultPrinter');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Consolidation\Config\ConfigInterface
|
||||
*/
|
||||
public static function config()
|
||||
{
|
||||
return static::service('config');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Consolidation\Log\Logger
|
||||
*/
|
||||
public static function logger()
|
||||
{
|
||||
return static::service('logger');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Application
|
||||
*/
|
||||
public static function application()
|
||||
{
|
||||
return static::service('application');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the output object.
|
||||
*
|
||||
* @return \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
public static function output()
|
||||
{
|
||||
return static::service('output');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the input object.
|
||||
*
|
||||
* @return \Symfony\Component\Console\Input\InputInterface
|
||||
*/
|
||||
public static function input()
|
||||
{
|
||||
return static::service('input');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Common\ProcessExecutor
|
||||
*/
|
||||
public static function process(Process $process)
|
||||
{
|
||||
return ProcessExecutor::create(static::getContainer(), $process);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Application $app
|
||||
* @param string|object $handler
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function register($app, $handlers)
|
||||
{
|
||||
if (!is_array($handlers)) {
|
||||
$handlers = [ $handlers ];
|
||||
}
|
||||
|
||||
foreach ($handlers as $handler) {
|
||||
static::registerSingle($app, $handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Application $app
|
||||
* @param string|object $handler
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
protected static function registerSingle($app, $handler)
|
||||
{
|
||||
$container = static::getContainer();
|
||||
$instance = static::instantiate($handler);
|
||||
if (!$instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance is a Symfony Command, register it with
|
||||
// the application
|
||||
if ($instance instanceof Command) {
|
||||
$app->add($instance);
|
||||
return $instance;
|
||||
}
|
||||
|
||||
// Register commands for all of the public methods in the RoboFile.
|
||||
$commandFactory = $container->get('commandFactory');
|
||||
$commandList = $commandFactory->createCommandsFromClass($instance);
|
||||
foreach ($commandList as $command) {
|
||||
$app->add($command);
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|object $handler
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public static function instantiate($handler)
|
||||
{
|
||||
$container = Robo::getContainer();
|
||||
|
||||
// Register the RoboFile with the container and then immediately
|
||||
// fetch it; this ensures that all of the inflectors will run.
|
||||
// If the command class is already an instantiated object, then
|
||||
// just use it exactly as it was provided to us.
|
||||
if (is_string($handler)) {
|
||||
if (!class_exists($handler)) {
|
||||
return;
|
||||
}
|
||||
$reflectionClass = new \ReflectionClass($handler);
|
||||
if ($reflectionClass->isAbstract()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$commandFileName = "{$handler}Commands";
|
||||
Robo::addShared($container, $commandFileName, $handler);
|
||||
$handler = $container->get($commandFileName);
|
||||
}
|
||||
// If the command class is a Builder Aware Interface, then
|
||||
// ensure that it has a builder. Every command class needs
|
||||
// its own collection builder, as they have references to each other.
|
||||
if ($handler instanceof BuilderAwareInterface) {
|
||||
$builder = CollectionBuilder::create($container, $handler);
|
||||
$handler->setBuilder($builder);
|
||||
}
|
||||
if ($handler instanceof ContainerAwareInterface) {
|
||||
$handler->setContainer($container);
|
||||
}
|
||||
return $handler;
|
||||
}
|
||||
}
|
||||
600
vendor/consolidation/robo/src/Runner.php
vendored
Normal file
600
vendor/consolidation/robo/src/Runner.php
vendored
Normal file
@ -0,0 +1,600 @@
|
||||
<?php
|
||||
|
||||
namespace Robo;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Collection\CollectionBuilder;
|
||||
use Robo\Common\IO;
|
||||
use Robo\Exception\TaskExitException;
|
||||
use League\Container\ContainerAwareInterface;
|
||||
use League\Container\ContainerAwareTrait;
|
||||
use League\Container\Exception\ContainerException;
|
||||
use Consolidation\Config\Util\EnvConfig;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class Runner implements ContainerAwareInterface
|
||||
{
|
||||
use IO;
|
||||
use ContainerAwareTrait;
|
||||
|
||||
const ROBOCLASS = 'RoboFile';
|
||||
const ROBOFILE = 'RoboFile.php';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $roboClass;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $roboFile;
|
||||
|
||||
/**
|
||||
* Working dir of Robo.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $dir;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $errorConditions = [];
|
||||
|
||||
/**
|
||||
* GitHub Repo for SelfUpdate.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selfUpdateRepository = null;
|
||||
|
||||
/**
|
||||
* Filename to load configuration from (set to 'robo.yml' for RoboFiles).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $configFilename = 'conf.yml';
|
||||
|
||||
/**
|
||||
* @var string prefix for environment variable configuration overrides
|
||||
*/
|
||||
protected $envConfigPrefix = false;
|
||||
|
||||
/**
|
||||
* @var null|\Composer\Autoload\ClassLoader
|
||||
*/
|
||||
protected $classLoader = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $relativePluginNamespace;
|
||||
|
||||
/**
|
||||
* Class Constructor
|
||||
*
|
||||
* @param null|string $roboClass
|
||||
* @param null|string $roboFile
|
||||
*/
|
||||
public function __construct($roboClass = null, $roboFile = null)
|
||||
{
|
||||
// set the const as class properties to allow overwriting in child classes
|
||||
$this->roboClass = $roboClass ? $roboClass : self::ROBOCLASS ;
|
||||
$this->roboFile = $roboFile ? $roboFile : self::ROBOFILE;
|
||||
$this->dir = getcwd();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $msg
|
||||
* @param string $errorType
|
||||
*/
|
||||
protected function errorCondition($msg, $errorType)
|
||||
{
|
||||
$this->errorConditions[$msg] = $errorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function loadRoboFile($output)
|
||||
{
|
||||
// If we have not been provided an output object, make a temporary one.
|
||||
if (!$output) {
|
||||
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
|
||||
}
|
||||
|
||||
// If $this->roboClass is a single class that has not already
|
||||
// been loaded, then we will try to obtain it from $this->roboFile.
|
||||
// If $this->roboClass is an array, we presume all classes requested
|
||||
// are available via the autoloader.
|
||||
if (is_array($this->roboClass) || class_exists($this->roboClass)) {
|
||||
return true;
|
||||
}
|
||||
if (!file_exists($this->dir)) {
|
||||
$this->errorCondition("Path `{$this->dir}` is invalid; please provide a valid absolute path to the Robofile to load.", 'red');
|
||||
return false;
|
||||
}
|
||||
|
||||
$realDir = realpath($this->dir);
|
||||
|
||||
$roboFilePath = $realDir . DIRECTORY_SEPARATOR . $this->roboFile;
|
||||
if (!file_exists($roboFilePath)) {
|
||||
$requestedRoboFilePath = $this->dir . DIRECTORY_SEPARATOR . $this->roboFile;
|
||||
$this->errorCondition("Requested RoboFile `$requestedRoboFilePath` is invalid, please provide valid absolute path to load Robofile.", 'red');
|
||||
return false;
|
||||
}
|
||||
require_once $roboFilePath;
|
||||
|
||||
if (!class_exists($this->roboClass)) {
|
||||
$this->errorCondition("Class {$this->roboClass} was not loaded.", 'red');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $argv
|
||||
* @param null|string $appName
|
||||
* @param null|string $appVersion
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function execute($argv, $appName = null, $appVersion = null, $output = null)
|
||||
{
|
||||
$argv = $this->shebang($argv);
|
||||
$argv = $this->processRoboOptions($argv);
|
||||
$app = null;
|
||||
if ($appName && $appVersion) {
|
||||
$app = Robo::createDefaultApplication($appName, $appVersion);
|
||||
}
|
||||
$commandFiles = $this->getRoboFileCommands($output);
|
||||
return $this->run($argv, $output, $app, $commandFiles, $this->classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an initialized application loaded with specified commands and configuration.
|
||||
*
|
||||
* This should ONLY be used for testing purposes. Works well in conjunction with Symfony's CommandTester.
|
||||
*
|
||||
* @see https://symfony.com/doc/current/console.html#testing-commands
|
||||
* @see CommandTestertTest
|
||||
* @see CommandTesterTrait
|
||||
*
|
||||
* @param string|null $appName
|
||||
* Name of the application.
|
||||
* @param string|null $appVersion
|
||||
* Version of the application.
|
||||
* @param string|array|null $commandFile
|
||||
* Name of the specific command file, or array of commands, that should be included with the application.
|
||||
* @param \Robo\Config\Config|null $config
|
||||
* Robo configuration to be used with the application.
|
||||
* @param \Composer\Autoload\ClassLoader|null $classLoader
|
||||
* Class loader to use.
|
||||
*
|
||||
* @return \Robo\Application
|
||||
* Initialized application based on passed configuration and command classes.
|
||||
*/
|
||||
public function getAppForTesting($appName = null, $appVersion = null, $commandFile = null, $config = null, $classLoader = null)
|
||||
{
|
||||
$app = Robo::createDefaultApplication($appName, $appVersion);
|
||||
$output = new NullOutput();
|
||||
$container = Robo::createDefaultContainer(null, $output, $app, $config, $classLoader);
|
||||
if (!is_null($commandFile) && (is_array($commandFile) || is_string($commandFile))) {
|
||||
if (is_string($commandFile)) {
|
||||
$commandFile = [$commandFile];
|
||||
}
|
||||
$this->registerCommandClasses($app, $commandFile);
|
||||
}
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of locations where config files may be loaded
|
||||
*
|
||||
* @param string $userConfig
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getConfigFilePaths($userConfig)
|
||||
{
|
||||
// Look for application config at the root of the application.
|
||||
// Find the root relative to this file, considering that Robo itself
|
||||
// might be the application, or it might be in the `vendor` directory.
|
||||
$roboAppConfig = dirname(__DIR__) . '/' . basename($userConfig);
|
||||
if (basename(dirname(__DIR__, 3)) == 'vendor') {
|
||||
$roboAppConfig = dirname(__DIR__, 4) . '/' . basename($userConfig);
|
||||
}
|
||||
$configFiles = [$roboAppConfig, $userConfig];
|
||||
if (dirname($userConfig) != '.') {
|
||||
$configFiles[] = basename($userConfig);
|
||||
}
|
||||
return $configFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|array|\Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @param null|\Robo\Application $app
|
||||
* @param array[] $commandFiles
|
||||
* @param null|ClassLoader $classLoader
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function run($input = null, $output = null, $app = null, $commandFiles = [], $classLoader = null)
|
||||
{
|
||||
// Create default input and output objects if they were not provided
|
||||
if (!$input) {
|
||||
$input = new StringInput('');
|
||||
}
|
||||
if (is_array($input)) {
|
||||
$input = new ArgvInput($input);
|
||||
}
|
||||
if (!$output) {
|
||||
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
|
||||
}
|
||||
$this->setInput($input);
|
||||
$this->setOutput($output);
|
||||
|
||||
// If we were not provided a container, then create one
|
||||
try {
|
||||
$this->getContainer();
|
||||
} catch (ContainerException $e) {
|
||||
$configFiles = $this->getConfigFilePaths($this->configFilename);
|
||||
$config = Robo::createConfiguration($configFiles);
|
||||
if ($this->envConfigPrefix) {
|
||||
$envConfig = new EnvConfig($this->envConfigPrefix);
|
||||
$config->addContext('env', $envConfig);
|
||||
}
|
||||
$container = Robo::createDefaultContainer($input, $output, $app, $config, $classLoader);
|
||||
$this->setContainer($container);
|
||||
// Automatically register a shutdown function and
|
||||
// an error handler when we provide the container.
|
||||
$this->installRoboHandlers();
|
||||
}
|
||||
|
||||
if (!$app) {
|
||||
$app = Robo::application();
|
||||
}
|
||||
if ($app instanceof \Robo\Application) {
|
||||
$app->addSelfUpdateCommand($this->getSelfUpdateRepository());
|
||||
if (!isset($commandFiles)) {
|
||||
$this->errorCondition("Robo is not initialized here. Please run `robo init` to create a new RoboFile.", 'yellow');
|
||||
$app->addInitRoboFileCommand($this->roboFile, $this->roboClass);
|
||||
$commandFiles = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->relativePluginNamespace)) {
|
||||
$commandClasses = $this->discoverCommandClasses($this->relativePluginNamespace);
|
||||
$commandFiles = array_merge((array)$commandFiles, $commandClasses);
|
||||
}
|
||||
|
||||
$this->registerCommandClasses($app, $commandFiles);
|
||||
|
||||
try {
|
||||
$statusCode = $app->run($input, $output);
|
||||
} 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) {
|
||||
// TODO: This was 'yell'. Add styling?
|
||||
$output->writeln($msg); // used to wrap at 40 and write in $color
|
||||
}
|
||||
}
|
||||
return $statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getRoboFileCommands($output)
|
||||
{
|
||||
if (!$this->loadRoboFile($output)) {
|
||||
return;
|
||||
}
|
||||
return $this->roboClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Application $app
|
||||
* @param array $commandClasses
|
||||
*/
|
||||
public function registerCommandClasses($app, $commandClasses)
|
||||
{
|
||||
foreach ((array)$commandClasses as $commandClass) {
|
||||
Robo::register($app, $commandClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relativeNamespace
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function discoverCommandClasses($relativeNamespace)
|
||||
{
|
||||
/** @var \Robo\ClassDiscovery\RelativeNamespaceDiscovery $discovery */
|
||||
$discovery = Robo::service('relativeNamespaceDiscovery');
|
||||
$discovery->setRelativeNamespace($relativeNamespace . '\Commands')
|
||||
->setSearchPattern('/.*Commands?\.php$/');
|
||||
return $discovery->getClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Application $app
|
||||
* @param string|BuilderAwareInterface|ContainerAwareInterface $commandClass
|
||||
*
|
||||
* @deprecated Use Robo::register directly
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public function registerCommandClass($app, $commandClass)
|
||||
{
|
||||
return Robo::register($app, $commandClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Robo::instantiate directly
|
||||
*/
|
||||
protected function instantiateCommandClass($commandClass)
|
||||
{
|
||||
return Robo::instantiate($commandClass);
|
||||
}
|
||||
|
||||
public function installRoboHandlers()
|
||||
{
|
||||
register_shutdown_function(array($this, 'shutdown'));
|
||||
set_error_handler(array($this, 'handleError'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a shebang script, if one was used to launch this Runner.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array $args
|
||||
* With shebang script removed.
|
||||
*/
|
||||
protected function shebang($args)
|
||||
{
|
||||
// Option 1: Shebang line names Robo, but includes no parameters.
|
||||
// #!/bin/env robo
|
||||
// The robo class may contain multiple commands; the user may
|
||||
// select which one to run, or even get a list of commands or
|
||||
// run 'help' on any of the available commands as usual.
|
||||
if ((count($args) > 1) && $this->isShebangFile($args[1])) {
|
||||
return array_merge([$args[0]], array_slice($args, 2));
|
||||
}
|
||||
// Option 2: Shebang line stipulates which command to run.
|
||||
// #!/bin/env robo mycommand
|
||||
// The robo class must contain a public method named 'mycommand'.
|
||||
// This command will be executed every time. Arguments and options
|
||||
// may be provided on the commandline as usual.
|
||||
if ((count($args) > 2) && $this->isShebangFile($args[2])) {
|
||||
return array_merge([$args[0]], explode(' ', $args[1]), array_slice($args, 3));
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified argument is a path to a shebang script.
|
||||
* If so, load it.
|
||||
*
|
||||
* @param string $filepath
|
||||
* File to check.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if shebang script was processed.
|
||||
*/
|
||||
protected function isShebangFile($filepath)
|
||||
{
|
||||
// Avoid trying to call $filepath on remote URLs
|
||||
if ((strpos($filepath, '://') !== false) && (substr($filepath, 0, 7) != 'file://')) {
|
||||
return false;
|
||||
}
|
||||
if (!is_file($filepath)) {
|
||||
return false;
|
||||
}
|
||||
$fp = fopen($filepath, "r");
|
||||
if ($fp === false) {
|
||||
return false;
|
||||
}
|
||||
$line = fgets($fp);
|
||||
$result = $this->isShebangLine($line);
|
||||
if ($result) {
|
||||
while ($line = fgets($fp)) {
|
||||
$line = trim($line);
|
||||
if ($line == '<?php') {
|
||||
$script = stream_get_contents($fp);
|
||||
if (preg_match('#^class *([^ ]+)#m', $script, $matches)) {
|
||||
$this->roboClass = $matches[1];
|
||||
eval($script);
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the provided line is a robo 'shebang' line.
|
||||
*
|
||||
* @param string $line
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isShebangLine($line)
|
||||
{
|
||||
return ((substr($line, 0, 2) == '#!') && (strstr($line, 'robo') !== false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for Robo-specific arguments such as --load-from, process them,
|
||||
* and remove them from the array. We have to process --load-from before
|
||||
* we set up Symfony Console.
|
||||
*
|
||||
* @param array $argv
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processRoboOptions($argv)
|
||||
{
|
||||
// loading from other directory
|
||||
$pos = $this->arraySearchBeginsWith('--load-from', $argv) ?: array_search('-f', $argv);
|
||||
if ($pos === false) {
|
||||
return $argv;
|
||||
}
|
||||
|
||||
$passThru = array_search('--', $argv);
|
||||
if (($passThru !== false) && ($passThru < $pos)) {
|
||||
return $argv;
|
||||
}
|
||||
|
||||
if (substr($argv[$pos], 0, 12) == '--load-from=') {
|
||||
$this->dir = substr($argv[$pos], 12);
|
||||
} elseif (isset($argv[$pos + 1])) {
|
||||
$this->dir = $argv[$pos + 1];
|
||||
unset($argv[$pos + 1]);
|
||||
}
|
||||
unset($argv[$pos]);
|
||||
// Make adjustments if '--load-from' points at a file.
|
||||
if (is_file($this->dir) || (substr($this->dir, -4) == '.php')) {
|
||||
$this->roboFile = basename($this->dir);
|
||||
$this->dir = dirname($this->dir);
|
||||
$className = basename($this->roboFile, '.php');
|
||||
if ($className != $this->roboFile) {
|
||||
$this->roboClass = $className;
|
||||
}
|
||||
}
|
||||
// Convert directory to a real path, but only if the
|
||||
// path exists. We do not want to lose the original
|
||||
// directory if the user supplied a bad value.
|
||||
$realDir = realpath($this->dir);
|
||||
if ($realDir) {
|
||||
chdir($realDir);
|
||||
$this->dir = $realDir;
|
||||
}
|
||||
|
||||
return $argv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $needle
|
||||
* @param string[] $haystack
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
protected function arraySearchBeginsWith($needle, $haystack)
|
||||
{
|
||||
for ($i = 0; $i < count($haystack); ++$i) {
|
||||
if (substr($haystack[$i], 0, strlen($needle)) == $needle) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function shutdown()
|
||||
{
|
||||
$error = error_get_last();
|
||||
if (!is_array($error)) {
|
||||
return;
|
||||
}
|
||||
$this->writeln(sprintf("<error>ERROR: %s \nin %s:%d\n</error>", $error['message'], $error['file'], $error['line']));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a proxy error handler that checks the current error_reporting level.
|
||||
* In case error_reporting is disabled the error is marked as handled, otherwise
|
||||
* the normal internal error handling resumes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handleError()
|
||||
{
|
||||
if (error_reporting() === 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSelfUpdateRepository()
|
||||
{
|
||||
return $this->selfUpdateRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $selfUpdateRepository
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSelfUpdateRepository($selfUpdateRepository)
|
||||
{
|
||||
$this->selfUpdateRepository = $selfUpdateRepository;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $configFilename
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfigurationFilename($configFilename)
|
||||
{
|
||||
$this->configFilename = $configFilename;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $envConfigPrefix
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setEnvConfigPrefix($envConfigPrefix)
|
||||
{
|
||||
$this->envConfigPrefix = $envConfigPrefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Composer\Autoload\ClassLoader $classLoader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setClassLoader(ClassLoader $classLoader)
|
||||
{
|
||||
$this->classLoader = $classLoader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relativeNamespace
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRelativePluginNamespace($relativeNamespace)
|
||||
{
|
||||
$this->relativePluginNamespace = $relativeNamespace;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
642
vendor/consolidation/robo/src/Runtime/Runner.php
vendored
Normal file
642
vendor/consolidation/robo/src/Runtime/Runner.php
vendored
Normal file
@ -0,0 +1,642 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Runtime;
|
||||
|
||||
use Robo\Robo;
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\Collection\CollectionBuilder;
|
||||
use Robo\Common\IO;
|
||||
use Robo\Exception\TaskExitException;
|
||||
use League\Container\ContainerAwareInterface;
|
||||
use League\Container\ContainerAwareTrait;
|
||||
use League\Container\Exception\ContainerException;
|
||||
use Consolidation\Config\Util\EnvConfig;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class Runner implements ContainerAwareInterface
|
||||
{
|
||||
use IO;
|
||||
use ContainerAwareTrait;
|
||||
|
||||
const ROBOCLASS = 'RoboFile';
|
||||
const ROBOFILE = 'RoboFile.php';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $roboClass;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $roboFile;
|
||||
|
||||
/**
|
||||
* Working dir of Robo.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $dir;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $errorConditions = [];
|
||||
|
||||
/**
|
||||
* GitHub Repo for SelfUpdate.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selfUpdateRepository = null;
|
||||
|
||||
/**
|
||||
* Filename to load configuration from (set to 'robo.yml' for RoboFiles).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $configFilename = 'conf.yml';
|
||||
|
||||
/**
|
||||
* @var string prefix for environment variable configuration overrides
|
||||
*/
|
||||
protected $envConfigPrefix = false;
|
||||
|
||||
/**
|
||||
* @var null|\Composer\Autoload\ClassLoader
|
||||
*/
|
||||
protected $classLoader = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $relativePluginNamespace;
|
||||
|
||||
/**
|
||||
* Class Constructor
|
||||
*
|
||||
* @param null|string $roboClass
|
||||
* @param null|string $roboFile
|
||||
*/
|
||||
public function __construct($roboClass = null, $roboFile = null)
|
||||
{
|
||||
// set the const as class properties to allow overwriting in child classes
|
||||
$this->roboClass = $roboClass ? $roboClass : self::ROBOCLASS ;
|
||||
$this->roboFile = $roboFile ? $roboFile : self::ROBOFILE;
|
||||
$this->dir = getcwd();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $msg
|
||||
* @param string $errorType
|
||||
*/
|
||||
protected function errorCondition($msg, $errorType)
|
||||
{
|
||||
$this->errorConditions[$msg] = $errorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function loadRoboFile($output)
|
||||
{
|
||||
// If we have not been provided an output object, make a temporary one.
|
||||
if (!$output) {
|
||||
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
|
||||
}
|
||||
|
||||
// If $this->roboClass is a single class that has not already
|
||||
// been loaded, then we will try to obtain it from $this->roboFile.
|
||||
// If $this->roboClass is an array, we presume all classes requested
|
||||
// are available via the autoloader.
|
||||
if (is_array($this->roboClass) || class_exists($this->roboClass)) {
|
||||
return true;
|
||||
}
|
||||
if (!file_exists($this->dir)) {
|
||||
$this->errorCondition("Path `{$this->dir}` is invalid; please provide a valid absolute path to the Robofile to load.", 'red');
|
||||
return false;
|
||||
}
|
||||
|
||||
$realDir = realpath($this->dir);
|
||||
|
||||
$roboFilePath = $realDir . DIRECTORY_SEPARATOR . $this->roboFile;
|
||||
if (!file_exists($roboFilePath)) {
|
||||
$requestedRoboFilePath = $this->dir . DIRECTORY_SEPARATOR . $this->roboFile;
|
||||
$this->errorCondition("Requested RoboFile `$requestedRoboFilePath` is invalid, please provide valid absolute path to load Robofile.", 'red');
|
||||
return false;
|
||||
}
|
||||
require_once $roboFilePath;
|
||||
|
||||
if (!class_exists($this->roboClass)) {
|
||||
$this->errorCondition("Class {$this->roboClass} was not loaded.", 'red');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $argv
|
||||
* @param null|string $appName
|
||||
* @param null|string $appVersion
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function execute($argv, $appName = null, $appVersion = null, $output = null)
|
||||
{
|
||||
$argv = $this->shebang($argv);
|
||||
$argv = $this->processRoboOptions($argv);
|
||||
$app = null;
|
||||
if ($appName && $appVersion) {
|
||||
$app = Robo::createDefaultApplication($appName, $appVersion);
|
||||
}
|
||||
$commandFiles = $this->getRoboFileCommands($output);
|
||||
return $this->run($argv, $output, $app, $commandFiles, $this->classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an initialized application loaded with specified commands and configuration.
|
||||
*
|
||||
* This should ONLY be used for testing purposes. Works well in conjunction with Symfony's CommandTester.
|
||||
*
|
||||
* @see https://symfony.com/doc/current/console.html#testing-commands
|
||||
* @see CommandTestertTest
|
||||
* @see CommandTesterTrait
|
||||
*
|
||||
* @param string|null $appName
|
||||
* Name of the application.
|
||||
* @param string|null $appVersion
|
||||
* Version of the application.
|
||||
* @param string|array|null $commandFile
|
||||
* Name of the specific command file, or array of commands, that should be included with the application.
|
||||
* @param \Robo\Config\Config|null $config
|
||||
* Robo configuration to be used with the application.
|
||||
* @param \Composer\Autoload\ClassLoader|null $classLoader
|
||||
* Class loader to use.
|
||||
*
|
||||
* @return \Robo\Application
|
||||
* Initialized application based on passed configuration and command classes.
|
||||
*/
|
||||
public function getAppForTesting($appName = null, $appVersion = null, $commandFile = null, $config = null, $classLoader = null)
|
||||
{
|
||||
$app = Robo::createDefaultApplication($appName, $appVersion);
|
||||
$output = new NullOutput();
|
||||
$container = Robo::createDefaultContainer(null, $output, $app, $config, $classLoader);
|
||||
if (!is_null($commandFile) && (is_array($commandFile) || is_string($commandFile))) {
|
||||
if (is_string($commandFile)) {
|
||||
$commandFile = [$commandFile];
|
||||
}
|
||||
$this->registerCommandClasses($app, $commandFile);
|
||||
}
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of locations where config files may be loaded
|
||||
*
|
||||
* @param string $userConfig
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getConfigFilePaths($userConfig)
|
||||
{
|
||||
// Look for application config at the root of the application.
|
||||
// Find the root relative to this file, considering that Robo itself
|
||||
// might be the application, or it might be in the `vendor` directory.
|
||||
$roboAppConfig = dirname(__DIR__) . '/' . basename($userConfig);
|
||||
if (basename(dirname(__DIR__, 3)) == 'vendor') {
|
||||
$roboAppConfig = dirname(__DIR__, 4) . '/' . basename($userConfig);
|
||||
}
|
||||
$configFiles = [$roboAppConfig, $userConfig];
|
||||
if (dirname($userConfig) != '.') {
|
||||
$configFiles[] = basename($userConfig);
|
||||
}
|
||||
return $configFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|array|\Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @param null|\Robo\Application $app
|
||||
* @param array[] $commandFiles
|
||||
* @param null|ClassLoader $classLoader
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function run($input = null, $output = null, $app = null, $commandFiles = [], $classLoader = null)
|
||||
{
|
||||
// Create default input and output objects if they were not provided
|
||||
if (!$input) {
|
||||
$input = new StringInput('');
|
||||
}
|
||||
if (is_array($input)) {
|
||||
$input = new ArgvInput($input);
|
||||
}
|
||||
if (!$output) {
|
||||
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
|
||||
}
|
||||
$this->setInput($input);
|
||||
$this->setOutput($output);
|
||||
|
||||
// If we were not provided a container, then create one
|
||||
try {
|
||||
$this->getContainer();
|
||||
} catch (ContainerException $e) {
|
||||
$configFiles = $this->getConfigFilePaths($this->configFilename);
|
||||
$config = Robo::createConfiguration($configFiles);
|
||||
if ($this->envConfigPrefix) {
|
||||
$envConfig = new EnvConfig($this->envConfigPrefix);
|
||||
$config->addContext('env', $envConfig);
|
||||
}
|
||||
$container = Robo::createDefaultContainer($input, $output, $app, $config, $classLoader);
|
||||
$this->setContainer($container);
|
||||
// Automatically register a shutdown function and
|
||||
// an error handler when we provide the container.
|
||||
$this->installRoboHandlers();
|
||||
}
|
||||
|
||||
if (!$app) {
|
||||
$app = Robo::application();
|
||||
}
|
||||
if ($app instanceof \Robo\Application) {
|
||||
$app->addSelfUpdateCommand($this->getSelfUpdateRepository());
|
||||
if (!isset($commandFiles)) {
|
||||
$this->errorCondition("Robo is not initialized here. Please run `robo init` to create a new RoboFile.", 'yellow');
|
||||
$app->addInitRoboFileCommand($this->roboFile, $this->roboClass);
|
||||
$commandFiles = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->relativePluginNamespace)) {
|
||||
$commandClasses = $this->discoverCommandClasses($this->relativePluginNamespace);
|
||||
$commandFiles = array_merge((array)$commandFiles, $commandClasses);
|
||||
}
|
||||
|
||||
$this->registerCommandClasses($app, $commandFiles);
|
||||
|
||||
try {
|
||||
$statusCode = $app->run($input, $output);
|
||||
} 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) {
|
||||
// TODO: This was 'yell'. Add styling?
|
||||
$output->writeln($msg); // used to wrap at 40 and write in $color
|
||||
}
|
||||
}
|
||||
return $statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getRoboFileCommands($output)
|
||||
{
|
||||
if (!$this->loadRoboFile($output)) {
|
||||
return;
|
||||
}
|
||||
return $this->roboClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Application $app
|
||||
* @param array $commandClasses
|
||||
*/
|
||||
public function registerCommandClasses($app, $commandClasses)
|
||||
{
|
||||
foreach ((array)$commandClasses as $commandClass) {
|
||||
$this->registerCommandClass($app, $commandClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relativeNamespace
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function discoverCommandClasses($relativeNamespace)
|
||||
{
|
||||
/** @var \Robo\ClassDiscovery\RelativeNamespaceDiscovery $discovery */
|
||||
$discovery = Robo::service('relativeNamespaceDiscovery');
|
||||
$discovery->setRelativeNamespace($relativeNamespace . '\Commands')
|
||||
->setSearchPattern('/.*Commands?\.php$/');
|
||||
return $discovery->getClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Robo\Application $app
|
||||
* @param string|BuilderAwareInterface|ContainerAwareInterface $commandClass
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public function registerCommandClass($app, $commandClass)
|
||||
{
|
||||
$container = Robo::getContainer();
|
||||
$roboCommandFileInstance = $this->instantiateCommandClass($commandClass);
|
||||
if (!$roboCommandFileInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register commands for all of the public methods in the RoboFile.
|
||||
$commandFactory = $container->get('commandFactory');
|
||||
$commandList = $commandFactory->createCommandsFromClass($roboCommandFileInstance);
|
||||
foreach ($commandList as $command) {
|
||||
$app->add($command);
|
||||
}
|
||||
return $roboCommandFileInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|\Robo\Contract\BuilderAwareInterface|\League\Container\ContainerAwareInterface $commandClass
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
protected function instantiateCommandClass($commandClass)
|
||||
{
|
||||
$container = Robo::getContainer();
|
||||
|
||||
// Register the RoboFile with the container and then immediately
|
||||
// fetch it; this ensures that all of the inflectors will run.
|
||||
// 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;
|
||||
}
|
||||
|
||||
$commandFileName = "{$commandClass}Commands";
|
||||
Robo::addShared($container, $commandFileName, $commandClass);
|
||||
$commandClass = $container->get($commandFileName);
|
||||
}
|
||||
// If the command class is a Builder Aware Interface, then
|
||||
// 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 = CollectionBuilder::create($container, $commandClass);
|
||||
$commandClass->setBuilder($builder);
|
||||
}
|
||||
if ($commandClass instanceof ContainerAwareInterface) {
|
||||
$commandClass->setContainer($container);
|
||||
}
|
||||
return $commandClass;
|
||||
}
|
||||
|
||||
public function installRoboHandlers()
|
||||
{
|
||||
register_shutdown_function(array($this, 'shutdown'));
|
||||
set_error_handler(array($this, 'handleError'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a shebang script, if one was used to launch this Runner.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array $args
|
||||
* With shebang script removed.
|
||||
*/
|
||||
protected function shebang($args)
|
||||
{
|
||||
// Option 1: Shebang line names Robo, but includes no parameters.
|
||||
// #!/bin/env robo
|
||||
// The robo class may contain multiple commands; the user may
|
||||
// select which one to run, or even get a list of commands or
|
||||
// run 'help' on any of the available commands as usual.
|
||||
if ((count($args) > 1) && $this->isShebangFile($args[1])) {
|
||||
return array_merge([$args[0]], array_slice($args, 2));
|
||||
}
|
||||
// Option 2: Shebang line stipulates which command to run.
|
||||
// #!/bin/env robo mycommand
|
||||
// The robo class must contain a public method named 'mycommand'.
|
||||
// This command will be executed every time. Arguments and options
|
||||
// may be provided on the commandline as usual.
|
||||
if ((count($args) > 2) && $this->isShebangFile($args[2])) {
|
||||
return array_merge([$args[0]], explode(' ', $args[1]), array_slice($args, 3));
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified argument is a path to a shebang script.
|
||||
* If so, load it.
|
||||
*
|
||||
* @param string $filepath
|
||||
* File to check.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if shebang script was processed.
|
||||
*/
|
||||
protected function isShebangFile($filepath)
|
||||
{
|
||||
// Avoid trying to call $filepath on remote URLs
|
||||
if ((strpos($filepath, '://') !== false) && (substr($filepath, 0, 7) != 'file://')) {
|
||||
return false;
|
||||
}
|
||||
if (!is_file($filepath)) {
|
||||
return false;
|
||||
}
|
||||
$fp = fopen($filepath, "r");
|
||||
if ($fp === false) {
|
||||
return false;
|
||||
}
|
||||
$line = fgets($fp);
|
||||
$result = $this->isShebangLine($line);
|
||||
if ($result) {
|
||||
while ($line = fgets($fp)) {
|
||||
$line = trim($line);
|
||||
if ($line == '<?php') {
|
||||
$script = stream_get_contents($fp);
|
||||
if (preg_match('#^class *([^ ]+)#m', $script, $matches)) {
|
||||
$this->roboClass = $matches[1];
|
||||
eval($script);
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the provided line is a robo 'shebang' line.
|
||||
*
|
||||
* @param string $line
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isShebangLine($line)
|
||||
{
|
||||
return ((substr($line, 0, 2) == '#!') && (strstr($line, 'robo') !== false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for Robo-specific arguments such as --load-from, process them,
|
||||
* and remove them from the array. We have to process --load-from before
|
||||
* we set up Symfony Console.
|
||||
*
|
||||
* @param array $argv
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function processRoboOptions($argv)
|
||||
{
|
||||
// loading from other directory
|
||||
$pos = $this->arraySearchBeginsWith('--load-from', $argv) ?: array_search('-f', $argv);
|
||||
if ($pos === false) {
|
||||
return $argv;
|
||||
}
|
||||
|
||||
$passThru = array_search('--', $argv);
|
||||
if (($passThru !== false) && ($passThru < $pos)) {
|
||||
return $argv;
|
||||
}
|
||||
|
||||
if (substr($argv[$pos], 0, 12) == '--load-from=') {
|
||||
$this->dir = substr($argv[$pos], 12);
|
||||
} elseif (isset($argv[$pos + 1])) {
|
||||
$this->dir = $argv[$pos + 1];
|
||||
unset($argv[$pos + 1]);
|
||||
}
|
||||
unset($argv[$pos]);
|
||||
// Make adjustments if '--load-from' points at a file.
|
||||
if (is_file($this->dir) || (substr($this->dir, -4) == '.php')) {
|
||||
$this->roboFile = basename($this->dir);
|
||||
$this->dir = dirname($this->dir);
|
||||
$className = basename($this->roboFile, '.php');
|
||||
if ($className != $this->roboFile) {
|
||||
$this->roboClass = $className;
|
||||
}
|
||||
}
|
||||
// Convert directory to a real path, but only if the
|
||||
// path exists. We do not want to lose the original
|
||||
// directory if the user supplied a bad value.
|
||||
$realDir = realpath($this->dir);
|
||||
if ($realDir) {
|
||||
chdir($realDir);
|
||||
$this->dir = $realDir;
|
||||
}
|
||||
|
||||
return $argv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $needle
|
||||
* @param string[] $haystack
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
protected function arraySearchBeginsWith($needle, $haystack)
|
||||
{
|
||||
for ($i = 0; $i < count($haystack); ++$i) {
|
||||
if (substr($haystack[$i], 0, strlen($needle)) == $needle) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function shutdown()
|
||||
{
|
||||
$error = error_get_last();
|
||||
if (!is_array($error)) {
|
||||
return;
|
||||
}
|
||||
$this->writeln(sprintf("<error>ERROR: %s \nin %s:%d\n</error>", $error['message'], $error['file'], $error['line']));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a proxy error handler that checks the current error_reporting level.
|
||||
* In case error_reporting is disabled the error is marked as handled, otherwise
|
||||
* the normal internal error handling resumes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handleError()
|
||||
{
|
||||
if (error_reporting() === 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSelfUpdateRepository()
|
||||
{
|
||||
return $this->selfUpdateRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $selfUpdateRepository
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSelfUpdateRepository($selfUpdateRepository)
|
||||
{
|
||||
$this->selfUpdateRepository = $selfUpdateRepository;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $configFilename
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfigurationFilename($configFilename)
|
||||
{
|
||||
$this->configFilename = $configFilename;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $envConfigPrefix
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setEnvConfigPrefix($envConfigPrefix)
|
||||
{
|
||||
$this->envConfigPrefix = $envConfigPrefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Composer\Autoload\ClassLoader $classLoader
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setClassLoader(ClassLoader $classLoader)
|
||||
{
|
||||
$this->classLoader = $classLoader;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $relativeNamespace
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRelativePluginNamespace($relativeNamespace)
|
||||
{
|
||||
$this->relativePluginNamespace = $relativeNamespace;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
13
vendor/consolidation/robo/src/State/Consumer.php
vendored
Normal file
13
vendor/consolidation/robo/src/State/Consumer.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\State;
|
||||
|
||||
use Robo\State\Data;
|
||||
|
||||
interface Consumer
|
||||
{
|
||||
/**
|
||||
* @return \Robo\State\Data
|
||||
*/
|
||||
public function receiveState(Data $state);
|
||||
}
|
||||
157
vendor/consolidation/robo/src/State/Data.php
vendored
Normal file
157
vendor/consolidation/robo/src/State/Data.php
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
<?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\State\Data $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
|
||||
*
|
||||
* @param array|float $duration
|
||||
*
|
||||
* @return null|float
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function accumulateMessage($message)
|
||||
{
|
||||
if (!empty($this->message)) {
|
||||
$this->message .= "\n";
|
||||
}
|
||||
$this->message .= $message;
|
||||
return $this->getMessage();
|
||||
}
|
||||
}
|
||||
32
vendor/consolidation/robo/src/State/StateAwareInterface.php
vendored
Normal file
32
vendor/consolidation/robo/src/State/StateAwareInterface.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\State;
|
||||
|
||||
use Robo\State\Data;
|
||||
|
||||
interface StateAwareInterface
|
||||
{
|
||||
/**
|
||||
* @return \Robo\State\Data
|
||||
*/
|
||||
public function getState();
|
||||
|
||||
/**
|
||||
* @param \Robo\State\Data $state
|
||||
*/
|
||||
public function setState(Data $state);
|
||||
|
||||
/**
|
||||
* @param int|string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setStateValue($key, $value);
|
||||
|
||||
/**
|
||||
* @param \Robo\State\Data
|
||||
* Update state takes precedence over current state.
|
||||
*/
|
||||
public function updateState(Data $update);
|
||||
|
||||
public function resetState();
|
||||
}
|
||||
48
vendor/consolidation/robo/src/State/StateAwareTrait.php
vendored
Normal file
48
vendor/consolidation/robo/src/State/StateAwareTrait.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\State;
|
||||
|
||||
use Robo\State\Data;
|
||||
|
||||
/**
|
||||
* @see \Robo\State\StateAwareInterface
|
||||
*/
|
||||
trait StateAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \Robo\State\Data
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* @return \Robo\State\Data
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function setState(Data $state)
|
||||
{
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setStateValue($key, $value)
|
||||
{
|
||||
$this->state[$key] = $value;
|
||||
}
|
||||
|
||||
public function updateState(Data $update)
|
||||
{
|
||||
$this->state->update($update);
|
||||
}
|
||||
|
||||
public function resetState()
|
||||
{
|
||||
$this->state = new Data();
|
||||
}
|
||||
}
|
||||
115
vendor/consolidation/robo/src/Symfony/ConsoleIO.php
vendored
Normal file
115
vendor/consolidation/robo/src/Symfony/ConsoleIO.php
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Symfony;
|
||||
|
||||
use Consolidation\AnnotatedCommand\CommandData;
|
||||
use Consolidation\AnnotatedCommand\CommandProcessor;
|
||||
use Consolidation\AnnotatedCommand\ParameterInjector;
|
||||
use Robo\Common\InflectionTrait;
|
||||
use Robo\Contract\InflectionInterface;
|
||||
use Robo\Contract\OutputAwareInterface;
|
||||
use Symfony\Component\Console\Input\InputAwareInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class ConsoleIO extends SymfonyStyle implements InflectionInterface // InputInterface?
|
||||
{
|
||||
use InflectionTrait;
|
||||
|
||||
protected $input;
|
||||
protected $output;
|
||||
|
||||
public function __construct(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
parent::__construct($input, $output);
|
||||
}
|
||||
|
||||
public function input()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*/
|
||||
public function say($text)
|
||||
{
|
||||
$char = $this->decorationCharacter('>', '➜');
|
||||
$this->writeln("$char $text");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param int $length
|
||||
* @param string $color
|
||||
*/
|
||||
public function yell($text, $length = 40, $color = 'green')
|
||||
{
|
||||
$char = $this->decorationCharacter(' ', '➜');
|
||||
$format = "$char <fg=white;bg=$color;options=bold>%s</fg=white;bg=$color;options=bold>";
|
||||
$this->formattedOutput($text, $length, $format);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param int $length
|
||||
* @param string $format
|
||||
*/
|
||||
protected function formattedOutput($text, $length, $format)
|
||||
{
|
||||
$lines = explode("\n", trim($text, "\n"));
|
||||
$maxLineLength = array_reduce(array_map('strlen', $lines), 'max');
|
||||
$length = max($length, $maxLineLength);
|
||||
$len = $length + 2;
|
||||
$space = str_repeat(' ', $len);
|
||||
$this->writeln(sprintf($format, $space));
|
||||
foreach ($lines as $line) {
|
||||
$line = str_pad($line, $length, ' ', STR_PAD_BOTH);
|
||||
$this->writeln(sprintf($format, " $line "));
|
||||
}
|
||||
$this->writeln(sprintf($format, $space));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nonDecorated
|
||||
* @param string $decorated
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function decorationCharacter($nonDecorated, $decorated)
|
||||
{
|
||||
if (!$this->output()->isDecorated() || (strncasecmp(PHP_OS, 'WIN', 3) == 0)) {
|
||||
return $nonDecorated;
|
||||
}
|
||||
return $decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lightText($message)
|
||||
{
|
||||
$this->block($message, '', 'fg=gray', '', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function injectDependencies($child)
|
||||
{
|
||||
if ($child instanceof InputAwareInterface) {
|
||||
$child->setInput($this->input());
|
||||
}
|
||||
if ($child instanceof OutputAwareInterface) {
|
||||
$child->setOutput($this->output());
|
||||
}
|
||||
}
|
||||
}
|
||||
16
vendor/consolidation/robo/src/Symfony/ConsoleIOInjector.php
vendored
Normal file
16
vendor/consolidation/robo/src/Symfony/ConsoleIOInjector.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Symfony;
|
||||
|
||||
use Consolidation\AnnotatedCommand\CommandData;
|
||||
use Consolidation\AnnotatedCommand\CommandProcessor;
|
||||
use Consolidation\AnnotatedCommand\ParameterInjector;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class ConsoleIOInjector implements ParameterInjector
|
||||
{
|
||||
public function get(CommandData $commandData, $interfaceName)
|
||||
{
|
||||
return new ConsoleIO($commandData->input(), $commandData->output());
|
||||
}
|
||||
}
|
||||
16
vendor/consolidation/robo/src/Symfony/SymfonyStyleInjector.php
vendored
Normal file
16
vendor/consolidation/robo/src/Symfony/SymfonyStyleInjector.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Symfony;
|
||||
|
||||
use Consolidation\AnnotatedCommand\CommandData;
|
||||
use Consolidation\AnnotatedCommand\CommandProcessor;
|
||||
use Consolidation\AnnotatedCommand\ParameterInjector;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class SymfonyStyleInjector implements ParameterInjector
|
||||
{
|
||||
public function get(CommandData $commandData, $interfaceName)
|
||||
{
|
||||
return new SymfonyStyle($commandData->input(), $commandData->output());
|
||||
}
|
||||
}
|
||||
563
vendor/consolidation/robo/src/Task/ApiGen/ApiGen.php
vendored
Normal file
563
vendor/consolidation/robo/src/Task/ApiGen/ApiGen.php
vendored
Normal file
@ -0,0 +1,563 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\ApiGen;
|
||||
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Task\BaseTask;
|
||||
use Traversable;
|
||||
use Robo\Common\ExecOneCommand;
|
||||
|
||||
/**
|
||||
* Executes ApiGen command to generate documentation
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // ApiGen Command
|
||||
* $this->taskApiGen('./vendor/apigen/apigen.phar')
|
||||
* ->config('./apigen.neon')
|
||||
* ->templateConfig('vendor/apigen/apigen/templates/bootstrap/config.neon')
|
||||
* ->wipeout(true)
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class ApiGen extends BaseTask implements CommandInterface
|
||||
{
|
||||
use ExecOneCommand;
|
||||
|
||||
const BOOL_NO = 'no';
|
||||
const BOOL_YES = 'yes';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $command;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $operation = 'generate';
|
||||
|
||||
/**
|
||||
* @param null|string $pathToApiGen
|
||||
*
|
||||
* @throws \Robo\Exception\TaskException
|
||||
*/
|
||||
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');
|
||||
}
|
||||
if (!$this->command) {
|
||||
throw new TaskException(__CLASS__, "No apigen installation found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass methods parameters as arguments to executable. Argument values
|
||||
* are automatically escaped.
|
||||
*
|
||||
* @param string|string[] $args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function args($args)
|
||||
{
|
||||
$func_args = func_get_args();
|
||||
if (!is_array($args)) {
|
||||
$args = $func_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.
|
||||
*
|
||||
* @return array|\Traversable
|
||||
* The provided argument if it was already traversable, or the given
|
||||
* argument returned as a one-element array.
|
||||
*/
|
||||
protected static function forceTraversable($arg)
|
||||
{
|
||||
$traversable = $arg;
|
||||
if (!is_array($traversable) && !($traversable instanceof \Traversable)) {
|
||||
$traversable = array($traversable);
|
||||
}
|
||||
return $traversable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $arg
|
||||
* A single argument or an array of multiple string values.
|
||||
*
|
||||
* @return string
|
||||
* A comma-separated string of all of the provided arguments, suitable as
|
||||
* a command-line "list" type argument for ApiGen.
|
||||
*/
|
||||
protected static function asList($arg)
|
||||
{
|
||||
$normalized = is_array($arg) ? $arg : array($arg);
|
||||
return implode(',', $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $val
|
||||
* An argument to be normalized.
|
||||
* @param string $default
|
||||
* One of self::BOOL_YES or self::BOOK_NO if the provided value could not
|
||||
* deterministically be converted to a yes or no value.
|
||||
*
|
||||
* @return string
|
||||
* The given value as a command-line "yes|no" type of argument for ApiGen,
|
||||
* or the default value if none could be determined.
|
||||
*/
|
||||
protected static function asTextBool($val, $default)
|
||||
{
|
||||
if ($val === self::BOOL_YES || $val === self::BOOL_NO) {
|
||||
return $val;
|
||||
}
|
||||
if (!$val) {
|
||||
return self::BOOL_NO;
|
||||
}
|
||||
if ($val === true) {
|
||||
return self::BOOL_YES;
|
||||
}
|
||||
if (is_numeric($val) && $val != 0) {
|
||||
return self::BOOL_YES;
|
||||
}
|
||||
if (strcasecmp($val[0], 'y') === 0) {
|
||||
return self::BOOL_YES;
|
||||
}
|
||||
if (strcasecmp($val[0], 'n') === 0) {
|
||||
return self::BOOL_NO;
|
||||
}
|
||||
// meh, good enough, let apigen sort it out
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function config($config)
|
||||
{
|
||||
$this->option('config', $config);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string|\Traversable $src
|
||||
* One or more source values.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function source($src)
|
||||
{
|
||||
foreach (self::forceTraversable($src) as $source) {
|
||||
$this->option('source', $source);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dest
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function destination($dest)
|
||||
{
|
||||
$this->option('destination', $dest);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $exts
|
||||
* One or more extensions.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function extensions($exts)
|
||||
{
|
||||
$this->option('extensions', self::asList($exts));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $exclude
|
||||
* One or more exclusions.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function exclude($exclude)
|
||||
{
|
||||
foreach (self::forceTraversable($exclude) as $excl) {
|
||||
$this->option('exclude', $excl);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string|\Traversable $path
|
||||
* One or more skip-doc-path values.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function skipDocPath($path)
|
||||
{
|
||||
foreach (self::forceTraversable($path) as $skip) {
|
||||
$this->option('skip-doc-path', $skip);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string|\Traversable $prefix
|
||||
* One or more skip-doc-prefix values.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function skipDocPrefix($prefix)
|
||||
{
|
||||
foreach (self::forceTraversable($prefix) as $skip) {
|
||||
$this->option('skip-doc-prefix', $skip);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $charset
|
||||
* One or more charsets.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function charset($charset)
|
||||
{
|
||||
$this->option('charset', self::asList($charset));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function mainProjectNamePrefix($name)
|
||||
{
|
||||
$this->option('main', $name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function title($title)
|
||||
{
|
||||
$this->option('title', $title);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $baseUrl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function baseUrl($baseUrl)
|
||||
{
|
||||
$this->option('base-url', $baseUrl);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function googleCseId($id)
|
||||
{
|
||||
$this->option('google-cse-id', $id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $trackingCode
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function googleAnalytics($trackingCode)
|
||||
{
|
||||
$this->option('google-analytics', $trackingCode);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $templateConfig
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function templateConfig($templateConfig)
|
||||
{
|
||||
$this->option('template-config', $templateConfig);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $tags
|
||||
* One or more supported html tags.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function allowedHtml($tags)
|
||||
{
|
||||
$this->option('allowed-html', self::asList($tags));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $groups
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function groups($groups)
|
||||
{
|
||||
$this->option('groups', $groups);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $types
|
||||
* One or more supported autocomplete types.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function autocomplete($types)
|
||||
{
|
||||
$this->option('autocomplete', self::asList($types));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $levels
|
||||
* One or more access levels.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function accessLevels($levels)
|
||||
{
|
||||
$this->option('access-levels', self::asList($levels));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean|string $internal
|
||||
* 'yes' or true if internal, 'no' or false if not.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function internal($internal)
|
||||
{
|
||||
$this->option('internal', self::asTextBool($internal, self::BOOL_NO));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $php
|
||||
* 'yes' or true to generate documentation for internal php classes, 'no'
|
||||
* or false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function php($php)
|
||||
{
|
||||
$this->option('php', self::asTextBool($php, self::BOOL_YES));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $tree
|
||||
* 'yes' or true to generate a tree view of classes, 'no' or false
|
||||
* otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function tree($tree)
|
||||
{
|
||||
$this->option('tree', self::asTextBool($tree, self::BOOL_YES));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $dep
|
||||
* 'yes' or true to generate documentation for deprecated classes, 'no' or
|
||||
* false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function deprecated($dep)
|
||||
{
|
||||
$this->option('deprecated', self::asTextBool($dep, self::BOOL_NO));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $todo
|
||||
* 'yes' or true to document tasks, 'no' or false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function todo($todo)
|
||||
{
|
||||
$this->option('todo', self::asTextBool($todo, self::BOOL_NO));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $src
|
||||
* 'yes' or true to generate highlighted source code, 'no' or false
|
||||
* otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function sourceCode($src)
|
||||
{
|
||||
$this->option('source-code', self::asTextBool($src, self::BOOL_YES));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $zipped
|
||||
* 'yes' or true to generate downloadable documentation, 'no' or false
|
||||
* otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function download($zipped)
|
||||
{
|
||||
$this->option('download', self::asTextBool($zipped, self::BOOL_NO));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function report($path)
|
||||
{
|
||||
$this->option('report', $path);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $wipeout
|
||||
* 'yes' or true to clear out the destination directory, 'no' or false
|
||||
* otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function wipeout($wipeout)
|
||||
{
|
||||
$this->option('wipeout', self::asTextBool($wipeout, self::BOOL_YES));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $quiet
|
||||
* 'yes' or true for quiet, 'no' or false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function quiet($quiet)
|
||||
{
|
||||
$this->option('quiet', self::asTextBool($quiet, self::BOOL_NO));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $bar
|
||||
* 'yes' or true to display a progress bar, 'no' or false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function progressbar($bar)
|
||||
{
|
||||
$this->option('progressbar', self::asTextBool($bar, self::BOOL_YES));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $colors
|
||||
* 'yes' or true colorize the output, 'no' or false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function colors($colors)
|
||||
{
|
||||
$this->option('colors', self::asTextBool($colors, self::BOOL_YES));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $check
|
||||
* 'yes' or true to check for updates, 'no' or false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function updateCheck($check)
|
||||
{
|
||||
$this->option('update-check', self::asTextBool($check, self::BOOL_YES));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $debug
|
||||
* 'yes' or true to enable debug mode, 'no' or false otherwise.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function debug($debug)
|
||||
{
|
||||
$this->option('debug', self::asTextBool($debug, self::BOOL_NO));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return "$this->command $this->operation$this->arguments";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->printTaskInfo('Running ApiGen {args}', ['args' => $this->arguments]);
|
||||
return $this->executeCommand($this->getCommand());
|
||||
}
|
||||
}
|
||||
16
vendor/consolidation/robo/src/Task/ApiGen/Tasks.php
vendored
Normal file
16
vendor/consolidation/robo/src/Task/ApiGen/Tasks.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\ApiGen;
|
||||
|
||||
trait Tasks
|
||||
{
|
||||
/**
|
||||
* @param null|string $pathToApiGen
|
||||
*
|
||||
* @return \Robo\Task\ApiGen\ApiGen|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskApiGen($pathToApiGen = null)
|
||||
{
|
||||
return $this->task(ApiGen::class, $pathToApiGen);
|
||||
}
|
||||
}
|
||||
295
vendor/consolidation/robo/src/Task/Archive/Extract.php
vendored
Normal file
295
vendor/consolidation/robo/src/Task/Archive/Extract.php
vendored
Normal file
@ -0,0 +1,295 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Archive;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Task\Filesystem\Tasks as FilesystemTaskLoader;
|
||||
use Robo\Contract\BuilderAwareInterface;
|
||||
use Robo\TaskAccessor;
|
||||
|
||||
/**
|
||||
* Extracts an archive.
|
||||
*
|
||||
* Note that often, distributions are packaged in tar or zip archives
|
||||
* where the topmost folder may contain variable information, such as
|
||||
* the release date, or the version of the package. This information
|
||||
* is very useful when unpacking by hand, but arbitrarily-named directories
|
||||
* are much less useful to scripts. Therefore, by default, Extract will
|
||||
* remove the top-level directory, and instead store all extracted files
|
||||
* into the directory specified by $archivePath.
|
||||
*
|
||||
* To keep the top-level directory when extracting, use
|
||||
* `preserveTopDirectory(true)`.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->taskExtract($archivePath)
|
||||
* ->to($destination)
|
||||
* ->preserveTopDirectory(false) // the default
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Extract extends BaseTask implements BuilderAwareInterface
|
||||
{
|
||||
use TaskAccessor;
|
||||
use FilesystemTaskLoader;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $to;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $preserveTopDirectory = false;
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*/
|
||||
public function __construct($filename)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location to store extracted files.
|
||||
*
|
||||
* @param string $to
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function to($to)
|
||||
{
|
||||
$this->to = $to;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $preserve
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function preserveTopDirectory($preserve = true)
|
||||
{
|
||||
$this->preserveTopDirectory = $preserve;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (!file_exists($this->filename)) {
|
||||
$this->printTaskError("File {filename} does not exist", ['filename' => $this->filename]);
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!($mimetype = static::archiveType($this->filename))) {
|
||||
$this->printTaskError("Could not determine type of archive for {filename}", ['filename' => $this->filename]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$umask = 0777 - umask();
|
||||
|
||||
// We will first extract to $extractLocation and then move to $this->to
|
||||
$extractLocation = $this->getTempDir();
|
||||
@mkdir($extractLocation, $umask, true);
|
||||
|
||||
$destinationParentDir = dirname($this->to);
|
||||
if (!file_exists($destinationParentDir)) {
|
||||
@mkdir($destinationParentDir, $umask, true);
|
||||
}
|
||||
|
||||
$this->startTimer();
|
||||
|
||||
$this->printTaskInfo("Extracting {filename}", ['filename' => $this->filename]);
|
||||
|
||||
$result = $this->extractAppropriateType($mimetype, $extractLocation);
|
||||
if ($result->wasSuccessful()) {
|
||||
$this->printTaskInfo("{filename} extracted", ['filename' => $this->filename]);
|
||||
// Now, we want to move the extracted files to $this->to. There
|
||||
// are two possibilities that we must consider:
|
||||
//
|
||||
// (1) Archived files were encapsulated in a folder with an arbitrary name
|
||||
// (2) There was no encapsulating folder, and all the files in the archive
|
||||
// were extracted into $extractLocation
|
||||
//
|
||||
// In the case of (1), we want to move and rename the encapsulating folder
|
||||
// to $this->to.
|
||||
//
|
||||
// In the case of (2), we will just move and rename $extractLocation.
|
||||
$filesInExtractLocation = glob("$extractLocation/*");
|
||||
$hasEncapsulatingFolder = ((count($filesInExtractLocation) == 1) && is_dir($filesInExtractLocation[0]));
|
||||
if ($hasEncapsulatingFolder && !$this->preserveTopDirectory) {
|
||||
$this
|
||||
->taskFilesystemStack()
|
||||
->rename($filesInExtractLocation[0], $this->to)
|
||||
->remove($extractLocation)
|
||||
->run();
|
||||
} else {
|
||||
$this
|
||||
->taskFilesystemStack()
|
||||
->rename($extractLocation, $this->to)
|
||||
->run();
|
||||
}
|
||||
}
|
||||
$this->stopTimer();
|
||||
$result['time'] = $this->getExecutionTime();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mimetype
|
||||
* @param string $extractLocation
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function extractAppropriateType($mimetype, $extractLocation)
|
||||
{
|
||||
// Perform the extraction of a zip file.
|
||||
if (($mimetype == 'application/zip') || ($mimetype == 'application/x-zip')) {
|
||||
return $this->extractZip($extractLocation);
|
||||
}
|
||||
return $this->extractTar($extractLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extractLocation
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function extractZip($extractLocation)
|
||||
{
|
||||
if (!extension_loaded('zlib')) {
|
||||
return Result::errorMissingExtension($this, 'zlib', 'zip extracting');
|
||||
}
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
if (($status = $zip->open($this->filename)) !== true) {
|
||||
return Result::error($this, "Could not open zip archive {$this->filename}");
|
||||
}
|
||||
if (!$zip->extractTo($extractLocation)) {
|
||||
return Result::error($this, "Could not extract zip archive {$this->filename}");
|
||||
}
|
||||
$zip->close();
|
||||
|
||||
return Result::success($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extractLocation
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function extractTar($extractLocation)
|
||||
{
|
||||
if (!class_exists('Archive_Tar')) {
|
||||
return Result::errorMissingPackage($this, 'Archive_Tar', 'pear/archive_tar');
|
||||
}
|
||||
$tar_object = new \Archive_Tar($this->filename);
|
||||
if (!$tar_object->extract($extractLocation)) {
|
||||
return Result::error($this, "Could not extract tar archive {$this->filename}");
|
||||
}
|
||||
|
||||
return Result::success($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
protected static function archiveType($filename)
|
||||
{
|
||||
$content_type = false;
|
||||
if (class_exists('finfo')) {
|
||||
$finfo = new \finfo(FILEINFO_MIME_TYPE);
|
||||
$content_type = $finfo->file($filename);
|
||||
// If finfo cannot determine the content type, then we will try other methods
|
||||
if ($content_type == 'application/octet-stream') {
|
||||
$content_type = false;
|
||||
}
|
||||
}
|
||||
// Examing the file's magic header bytes.
|
||||
if (!$content_type) {
|
||||
if ($file = fopen($filename, 'rb')) {
|
||||
$first = fread($file, 2);
|
||||
fclose($file);
|
||||
if ($first !== false) {
|
||||
// Interpret the two bytes as a little endian 16-bit unsigned int.
|
||||
$data = unpack('v', $first);
|
||||
switch ($data[1]) {
|
||||
case 0x8b1f:
|
||||
// First two bytes of gzip files are 0x1f, 0x8b (little-endian).
|
||||
// See https://www.gzip.org/zlib/rfc-gzip.html#header-trailer
|
||||
$content_type = 'application/x-gzip';
|
||||
break;
|
||||
|
||||
case 0x4b50:
|
||||
// First two bytes of zip files are 0x50, 0x4b ('PK') (little-endian).
|
||||
// See https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
|
||||
$content_type = 'application/zip';
|
||||
break;
|
||||
|
||||
case 0x5a42:
|
||||
// First two bytes of bzip2 files are 0x5a, 0x42 ('BZ') (big-endian).
|
||||
// See https://en.wikipedia.org/wiki/Bzip2#File_format
|
||||
$content_type = 'application/x-bzip2';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. Lastly if above methods didn't work, try to guess the mime type from
|
||||
// the file extension. This is useful if the file has no identificable magic
|
||||
// header bytes (for example tarballs).
|
||||
if (!$content_type) {
|
||||
// Remove querystring from the filename, if present.
|
||||
$filename = basename(current(explode('?', $filename, 2)));
|
||||
$extension_mimetype = array(
|
||||
'.tar.gz' => 'application/x-gzip',
|
||||
'.tgz' => 'application/x-gzip',
|
||||
'.tar' => 'application/x-tar',
|
||||
);
|
||||
foreach ($extension_mimetype as $extension => $ct) {
|
||||
if (substr($filename, -strlen($extension)) === $extension) {
|
||||
$content_type = $ct;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getTempDir()
|
||||
{
|
||||
return $this->to . '-tmp' . rand() . time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use $this->getTempDir() instead.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @see getTempDir
|
||||
*/
|
||||
protected static function getTmpDir()
|
||||
{
|
||||
return getcwd() . '/tmp' . rand() . time();
|
||||
}
|
||||
}
|
||||
291
vendor/consolidation/robo/src/Task/Archive/Pack.php
vendored
Normal file
291
vendor/consolidation/robo/src/Task/Archive/Pack.php
vendored
Normal file
@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Archive;
|
||||
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
* Creates a zip or tar archive.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->taskPack(
|
||||
* <archiveFile>)
|
||||
* ->add('README') // Puts file 'README' in archive at the root
|
||||
* ->add('project') // Puts entire contents of directory 'project' in archinve inside 'project'
|
||||
* ->addFile('dir/file.txt', 'file.txt') // Takes 'file.txt' from cwd and puts it in archive inside 'dir'.
|
||||
* ->exclude(['dir\/.*.zip', '.*.md']) // Add regex (or array of regex) to the excluded patterns list.
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Pack extends BaseTask implements PrintedInterface
|
||||
{
|
||||
/**
|
||||
* The list of items to be packed into the archive.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $items = [];
|
||||
|
||||
/**
|
||||
* The full path to the archive to be created.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $archiveFile;
|
||||
|
||||
/**
|
||||
* A list of regex patterns to exclude from the archive.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $ignoreList;
|
||||
/**
|
||||
* Construct the class.
|
||||
*
|
||||
* @param string $archiveFile
|
||||
* The full path and name of the archive file to create.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function __construct($archiveFile)
|
||||
{
|
||||
$this->archiveFile = $archiveFile;
|
||||
$this->ignoreList = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Satisfy the parent requirement.
|
||||
*
|
||||
* @return bool
|
||||
* Always returns true.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function getPrinted()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $archiveFile
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function archiveFile($archiveFile)
|
||||
{
|
||||
$this->archiveFile = $archiveFile;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the archive. Like file_exists(), the parameter
|
||||
* may be a file or a directory.
|
||||
*
|
||||
* @param string $placementLocation
|
||||
* Relative path and name of item to store in archive.
|
||||
* @param string $filesystemLocation
|
||||
* Absolute or relative path to file or directory's location in filesystem.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addFile($placementLocation, $filesystemLocation)
|
||||
{
|
||||
$this->items[$placementLocation] = $filesystemLocation;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for addFile, in case anyone has angst about using
|
||||
* addFile with a directory.
|
||||
*
|
||||
* @param string $placementLocation
|
||||
* Relative path and name of directory to store in archive.
|
||||
* @param string $filesystemLocation
|
||||
* Absolute or relative path to directory or directory's location in filesystem.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addDir($placementLocation, $filesystemLocation)
|
||||
{
|
||||
$this->addFile($placementLocation, $filesystemLocation);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file or directory, or list of same to the archive.
|
||||
*
|
||||
* @param string|array $item
|
||||
* If given a string, should contain the relative filesystem path to the
|
||||
* the item to store in archive; this will also be used as the item's
|
||||
* path in the archive, so absolute paths should not be used here.
|
||||
* If given an array, the key of each item should be the path to store
|
||||
* in the archive, and the value should be the filesystem path to the
|
||||
* item to store.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add($item)
|
||||
{
|
||||
if (is_array($item)) {
|
||||
$this->items = array_merge($this->items, $item);
|
||||
} else {
|
||||
$this->addFile($item, $item);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow files or folder to be excluded from the archive. Use regex, without enclosing slashes.
|
||||
*
|
||||
* @param string|string[]
|
||||
* A regex (or array of) to be excluded.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function exclude($ignoreList)
|
||||
{
|
||||
$this->ignoreList = array_merge($this->ignoreList, (array) $ignoreList);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a zip archive for distribution.
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->startTimer();
|
||||
|
||||
// Use the file extension to determine what kind of archive to create.
|
||||
$fileInfo = new \SplFileInfo($this->archiveFile);
|
||||
$extension = strtolower($fileInfo->getExtension());
|
||||
if (empty($extension)) {
|
||||
return Result::error($this, "Archive filename must use an extension (e.g. '.zip') to specify the kind of archive to create.");
|
||||
}
|
||||
|
||||
try {
|
||||
// Inform the user which archive we are creating
|
||||
$this->printTaskInfo("Creating archive {filename}", ['filename' => $this->archiveFile]);
|
||||
if ($extension == 'zip') {
|
||||
$result = $this->archiveZip($this->archiveFile, $this->items);
|
||||
} else {
|
||||
$result = $this->archiveTar($this->archiveFile, $this->items);
|
||||
}
|
||||
$this->printTaskSuccess("{filename} created.", ['filename' => $this->archiveFile]);
|
||||
} catch (\Exception $e) {
|
||||
$this->printTaskError("Could not create {filename}. {exception}", ['filename' => $this->archiveFile, 'exception' => $e->getMessage(), '_style' => ['exception' => '']]);
|
||||
$result = Result::error($this, sprintf('Could not create %s. %s', $this->archiveFile, $e->getMessage()));
|
||||
}
|
||||
$this->stopTimer();
|
||||
$result['time'] = $this->getExecutionTime();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $archiveFile
|
||||
* @param array $items
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function archiveTar($archiveFile, $items)
|
||||
{
|
||||
if (!class_exists('Archive_Tar')) {
|
||||
return Result::errorMissingPackage($this, 'Archive_Tar', 'pear/archive_tar');
|
||||
}
|
||||
|
||||
$tar_object = new \Archive_Tar($archiveFile);
|
||||
if (!empty($this->ignoreList)) {
|
||||
$regexp = '#/' . join('$|/', $this->ignoreList) . '#';
|
||||
$tar_object->setIgnoreRegexp($regexp);
|
||||
}
|
||||
foreach ($items as $placementLocation => $filesystemLocation) {
|
||||
$p_remove_dir = $filesystemLocation;
|
||||
$p_add_dir = $placementLocation;
|
||||
if (is_file($filesystemLocation)) {
|
||||
$p_remove_dir = dirname($filesystemLocation);
|
||||
$p_add_dir = dirname($placementLocation);
|
||||
if (basename($filesystemLocation) != basename($placementLocation)) {
|
||||
return Result::error($this, "Tar archiver does not support renaming files during extraction; could not add $filesystemLocation as $placementLocation.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$tar_object->addModify([$filesystemLocation], $p_add_dir, $p_remove_dir)) {
|
||||
return Result::error($this, "Could not add $filesystemLocation to the archive.");
|
||||
}
|
||||
}
|
||||
|
||||
return Result::success($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $archiveFile
|
||||
* @param array $items
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function archiveZip($archiveFile, $items)
|
||||
{
|
||||
if (!extension_loaded('zlib') || !class_exists(\ZipArchive::class)) {
|
||||
return Result::errorMissingExtension($this, 'zlib', 'zip packing');
|
||||
}
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
if (!$zip->open($archiveFile, \ZipArchive::CREATE)) {
|
||||
return Result::error($this, "Could not create zip archive {$archiveFile}");
|
||||
}
|
||||
$result = $this->addItemsToZip($zip, $items);
|
||||
$zip->close();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ZipArchive $zip
|
||||
* @param array $items
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function addItemsToZip($zip, $items)
|
||||
{
|
||||
foreach ($items as $placementLocation => $filesystemLocation) {
|
||||
if (is_dir($filesystemLocation)) {
|
||||
$finder = new Finder();
|
||||
$finder->files()->in($filesystemLocation)->ignoreDotFiles(false);
|
||||
if (!empty($this->ignoreList)) {
|
||||
// Add slashes so Symfony Finder patterns work like Archive_Tar ones.
|
||||
$zipIgnoreList = preg_filter('/^|$/', '/', $this->ignoreList);
|
||||
$finder->notName($zipIgnoreList)->notPath($zipIgnoreList);
|
||||
}
|
||||
|
||||
foreach ($finder as $file) {
|
||||
// Replace Windows slashes or resulting zip will have issues on *nixes.
|
||||
$relativePathname = str_replace('\\', '/', $file->getRelativePathname());
|
||||
|
||||
if (!$zip->addFile($file->getRealpath(), "{$placementLocation}/{$relativePathname}")) {
|
||||
return Result::error($this, "Could not add directory $filesystemLocation to the archive; error adding {$file->getRealpath()}.");
|
||||
}
|
||||
}
|
||||
} elseif (is_file($filesystemLocation)) {
|
||||
if (!$zip->addFile($filesystemLocation, $placementLocation)) {
|
||||
return Result::error($this, "Could not add file $filesystemLocation to the archive.");
|
||||
}
|
||||
} else {
|
||||
return Result::error($this, "Could not find $filesystemLocation for the archive.");
|
||||
}
|
||||
}
|
||||
|
||||
return Result::success($this);
|
||||
}
|
||||
}
|
||||
26
vendor/consolidation/robo/src/Task/Archive/Tasks.php
vendored
Normal file
26
vendor/consolidation/robo/src/Task/Archive/Tasks.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Archive;
|
||||
|
||||
trait Tasks
|
||||
{
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
* @return \Robo\Task\Archive\Pack|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskPack($filename)
|
||||
{
|
||||
return $this->task(Pack::class, $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
* @return \Robo\Task\Archive\Extract|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskExtract($filename)
|
||||
{
|
||||
return $this->task(Extract::class, $filename);
|
||||
}
|
||||
}
|
||||
214
vendor/consolidation/robo/src/Task/Assets/CssPreprocessor.php
vendored
Normal file
214
vendor/consolidation/robo/src/Task/Assets/CssPreprocessor.php
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Assets;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
|
||||
abstract class CssPreprocessor extends BaseTask
|
||||
{
|
||||
const FORMAT_NAME = '';
|
||||
|
||||
/**
|
||||
* Default compiler to use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $compiler;
|
||||
|
||||
/**
|
||||
* Available compilers list
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $compilers = [];
|
||||
|
||||
/**
|
||||
* Compiler options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $compilerOptions = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $files = [];
|
||||
|
||||
/**
|
||||
* Constructor. Accepts array of file paths.
|
||||
*
|
||||
* @param array $input
|
||||
*/
|
||||
public function __construct(array $input)
|
||||
{
|
||||
$this->files = $input;
|
||||
|
||||
$this->setDefaultCompiler();
|
||||
}
|
||||
|
||||
protected function setDefaultCompiler()
|
||||
{
|
||||
if (isset($this->compilers[0])) {
|
||||
//set first compiler as default
|
||||
$this->compiler = $this->compilers[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets import directories
|
||||
* Alias for setImportPaths
|
||||
* @see CssPreprocessor::setImportPaths
|
||||
*
|
||||
* @param array|string $dirs
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function importDir($dirs)
|
||||
{
|
||||
return $this->setImportPaths($dirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds import directory
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addImportPath($dir)
|
||||
{
|
||||
if (!isset($this->compilerOptions['importDirs'])) {
|
||||
$this->compilerOptions['importDirs'] = [];
|
||||
}
|
||||
|
||||
if (!in_array($dir, $this->compilerOptions['importDirs'], true)) {
|
||||
$this->compilerOptions['importDirs'][] = $dir;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets import directories
|
||||
*
|
||||
* @param array|string $dirs
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setImportPaths($dirs)
|
||||
{
|
||||
if (!is_array($dirs)) {
|
||||
$dirs = [$dirs];
|
||||
}
|
||||
|
||||
$this->compilerOptions['importDirs'] = $dirs;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $formatterName
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFormatter($formatterName)
|
||||
{
|
||||
$this->compilerOptions['formatter'] = $formatterName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the compiler.
|
||||
*
|
||||
* @param string $compiler
|
||||
* @param array $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function compiler($compiler, array $options = [])
|
||||
{
|
||||
$this->compiler = $compiler;
|
||||
$this->compilerOptions = array_merge($this->compilerOptions, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles file
|
||||
*
|
||||
* @param $file
|
||||
*
|
||||
* @return bool|mixed
|
||||
*/
|
||||
protected function compile($file)
|
||||
{
|
||||
if (is_callable($this->compiler)) {
|
||||
return call_user_func($this->compiler, $file, $this->compilerOptions);
|
||||
}
|
||||
|
||||
if (method_exists($this, $this->compiler)) {
|
||||
return $this->{$this->compiler}($file);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (!in_array($this->compiler, $this->compilers, true)
|
||||
&& !is_callable($this->compiler)
|
||||
) {
|
||||
$message = sprintf('Invalid ' . static::FORMAT_NAME . ' compiler %s!', $this->compiler);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
|
||||
foreach ($this->files as $in => $out) {
|
||||
if (!file_exists($in)) {
|
||||
$message = sprintf('File %s not found.', $in);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
if (file_exists($out) && !is_writable($out)) {
|
||||
return Result::error($this, 'Destination already exists and cannot be overwritten.');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->files as $in => $out) {
|
||||
$css = $this->compile($in);
|
||||
|
||||
if ($css instanceof Result) {
|
||||
return $css;
|
||||
} elseif (false === $css) {
|
||||
$message = sprintf(
|
||||
ucfirst(static::FORMAT_NAME) . ' compilation failed for %s.',
|
||||
$in
|
||||
);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
|
||||
$dst = $out . '.part';
|
||||
$write_result = file_put_contents($dst, $css);
|
||||
|
||||
if (false === $write_result) {
|
||||
$message = sprintf('File write failed: %s', $out);
|
||||
|
||||
@unlink($dst);
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
|
||||
// Cannot be cross-volume: should always succeed
|
||||
@rename($dst, $out);
|
||||
|
||||
$this->printTaskSuccess('Wrote CSS to {filename}', ['filename' => $out]);
|
||||
}
|
||||
|
||||
return Result::success($this, 'All ' . static::FORMAT_NAME . ' files compiled.');
|
||||
}
|
||||
}
|
||||
761
vendor/consolidation/robo/src/Task/Assets/ImageMinify.php
vendored
Normal file
761
vendor/consolidation/robo/src/Task/Assets/ImageMinify.php
vendored
Normal file
@ -0,0 +1,761 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Assets;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Task\Base\Exec;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Filesystem\Filesystem as sfFilesystem;
|
||||
|
||||
/**
|
||||
* Minifies images.
|
||||
*
|
||||
* When the task is run without any specified minifier it will compress the
|
||||
* images based on the extension.
|
||||
*
|
||||
* ```php
|
||||
* $this->taskImageMinify('assets/images/*')
|
||||
* ->to('dist/images/')
|
||||
* ->run();
|
||||
* ```
|
||||
*
|
||||
* This will use the following minifiers based in the extension:
|
||||
*
|
||||
* - PNG: optipng
|
||||
* - GIF: gifsicle
|
||||
* - JPG, JPEG: jpegtran
|
||||
* - SVG: svgo
|
||||
*
|
||||
* When the required minifier is not installed on the system the task will try
|
||||
* to download it from the [imagemin](https://github.com/imagemin) repository
|
||||
* into a local directory.
|
||||
* This directory is `vendor/bin/` by default and may be changed:
|
||||
*
|
||||
* ```php
|
||||
* $this->taskImageMinify('assets/images/*')
|
||||
* ->setExecutableDir('/tmp/imagemin/bin/)
|
||||
* ->to('dist/images/')
|
||||
* ->run();
|
||||
* ```
|
||||
*
|
||||
* When the minifier is specified the task will use that for all the input
|
||||
* files. In that case it is useful to filter the files with the extension:
|
||||
*
|
||||
* ```php
|
||||
* $this->taskImageMinify('assets/images/*.png')
|
||||
* ->to('dist/images/')
|
||||
* ->minifier('pngcrush');
|
||||
* ->run();
|
||||
* ```
|
||||
*
|
||||
* The task supports the following minifiers:
|
||||
*
|
||||
* - optipng
|
||||
* - pngquant
|
||||
* - advpng
|
||||
* - pngout
|
||||
* - zopflipng
|
||||
* - pngcrush
|
||||
* - gifsicle
|
||||
* - jpegoptim
|
||||
* - jpeg-recompress
|
||||
* - jpegtran
|
||||
* - svgo (only minification, no downloading)
|
||||
*
|
||||
* You can also specifiy extra options for the minifiers:
|
||||
*
|
||||
* ```php
|
||||
* $this->taskImageMinify('assets/images/*.jpg')
|
||||
* ->to('dist/images/')
|
||||
* ->minifier('jpegtran', ['-progressive' => null, '-copy' => 'none'])
|
||||
* ->run();
|
||||
* ```
|
||||
*
|
||||
* This will execute as:
|
||||
* `jpegtran -copy none -progressive -optimize -outfile "dist/images/test.jpg" "/var/www/test/assets/images/test.jpg"`
|
||||
*/
|
||||
class ImageMinify extends BaseTask
|
||||
{
|
||||
/**
|
||||
* Destination directory for the minified images.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $to;
|
||||
|
||||
/**
|
||||
* Array of the source files.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dirs = [];
|
||||
|
||||
/**
|
||||
* Symfony 2 filesystem.
|
||||
*
|
||||
* @var sfFilesystem
|
||||
*/
|
||||
protected $fs;
|
||||
|
||||
/**
|
||||
* Target directory for the downloaded binary executables.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $executableTargetDir;
|
||||
|
||||
/**
|
||||
* Array for the downloaded binary executables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $executablePaths = [];
|
||||
|
||||
/**
|
||||
* Array for the individual results of all the files.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $results = [];
|
||||
|
||||
/**
|
||||
* Default minifier to use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $minifier;
|
||||
|
||||
/**
|
||||
* Array for minifier options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $minifierOptions = [];
|
||||
|
||||
/**
|
||||
* Supported minifiers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $minifiers = [
|
||||
// Default 4
|
||||
'optipng',
|
||||
'gifsicle',
|
||||
'jpegtran',
|
||||
'svgo',
|
||||
// PNG
|
||||
'pngquant',
|
||||
'advpng',
|
||||
'pngout',
|
||||
'zopflipng',
|
||||
'pngcrush',
|
||||
// JPG
|
||||
'jpegoptim',
|
||||
'jpeg-recompress',
|
||||
];
|
||||
|
||||
/**
|
||||
* Binary repositories of Imagemin.
|
||||
*
|
||||
* @link https://github.com/imagemin
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $imageminRepos = [
|
||||
// PNG
|
||||
'optipng' => 'https://github.com/imagemin/optipng-bin',
|
||||
'pngquant' => 'https://github.com/imagemin/pngquant-bin',
|
||||
'advpng' => 'https://github.com/imagemin/advpng-bin',
|
||||
'pngout' => 'https://github.com/imagemin/pngout-bin',
|
||||
'zopflipng' => 'https://github.com/imagemin/zopflipng-bin',
|
||||
'pngcrush' => 'https://github.com/imagemin/pngcrush-bin',
|
||||
// Gif
|
||||
'gifsicle' => 'https://github.com/imagemin/gifsicle-bin',
|
||||
// JPG
|
||||
'jpegtran' => 'https://github.com/imagemin/jpegtran-bin',
|
||||
'jpegoptim' => 'https://github.com/imagemin/jpegoptim-bin',
|
||||
'cjpeg' => 'https://github.com/imagemin/mozjpeg-bin', // note: we do not support this minifier because it creates JPG from non-JPG files
|
||||
'jpeg-recompress' => 'https://github.com/imagemin/jpeg-recompress-bin',
|
||||
// WebP
|
||||
'cwebp' => 'https://github.com/imagemin/cwebp-bin', // note: we do not support this minifier because it creates WebP from non-WebP files
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string|string[] $dirs
|
||||
*/
|
||||
public function __construct($dirs)
|
||||
{
|
||||
is_array($dirs)
|
||||
? $this->dirs = $dirs
|
||||
: $this->dirs[] = $dirs;
|
||||
|
||||
$this->fs = new sfFilesystem();
|
||||
|
||||
// guess the best path for the executables based on __DIR__
|
||||
if (($pos = strpos(__DIR__, 'consolidation/robo')) !== false) {
|
||||
// the executables should be stored in vendor/bin
|
||||
$this->setExecutableDir(substr(__DIR__, 0, $pos) . 'bin');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// find the files
|
||||
$files = $this->findFiles($this->dirs);
|
||||
|
||||
// minify the files
|
||||
$result = $this->minify($files);
|
||||
// check if there was an error
|
||||
if ($result instanceof Result) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$amount = (count($files) == 1 ? 'image' : 'images');
|
||||
$message = "Minified {filecount} out of {filetotal} $amount into {destination}";
|
||||
$context = ['filecount' => count($this->results['success']), 'filetotal' => count($files), 'destination' => $this->to];
|
||||
|
||||
if (count($this->results['success']) == count($files)) {
|
||||
$this->printTaskSuccess($message, $context);
|
||||
|
||||
return Result::success($this, $message, $context);
|
||||
} else {
|
||||
return Result::error($this, $message, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target directory for executables (`vendor/bin/` by default)
|
||||
*
|
||||
* @param string $directory
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setExecutableDir($directory)
|
||||
{
|
||||
$this->executableTargetDir = $directory;
|
||||
|
||||
// check if the executables are already available in there
|
||||
foreach ($this->imageminRepos as $exec => $url) {
|
||||
$path = $this->executableTargetDir . '/' . $exec;
|
||||
// if this is Windows add a .exe extension
|
||||
if (substr($this->getOS(), 0, 3) == 'win') {
|
||||
$path .= '.exe';
|
||||
}
|
||||
if (is_file($path)) {
|
||||
$this->executablePaths[$exec] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target directory where the files will be copied to.
|
||||
*
|
||||
* @param string $target
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function to($target)
|
||||
{
|
||||
$this->to = rtrim($target, '/');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minifier.
|
||||
*
|
||||
* @param string $minifier
|
||||
* @param array $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function minifier($minifier, array $options = [])
|
||||
{
|
||||
$this->minifier = $minifier;
|
||||
$this->minifierOptions = array_merge($this->minifierOptions, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $dirs
|
||||
*
|
||||
* @return array|\Robo\Result
|
||||
*
|
||||
* @throws \Robo\Exception\TaskException
|
||||
*/
|
||||
protected function findFiles($dirs)
|
||||
{
|
||||
$files = array();
|
||||
|
||||
// find the files
|
||||
foreach ($dirs as $k => $v) {
|
||||
// reset finder
|
||||
$finder = new Finder();
|
||||
|
||||
$dir = $k;
|
||||
$to = $v;
|
||||
// check if target was given with the to() method instead of key/value pairs
|
||||
if (is_int($k)) {
|
||||
$dir = $v;
|
||||
if (isset($this->to)) {
|
||||
$to = $this->to;
|
||||
} else {
|
||||
throw new TaskException($this, 'target directory is not defined');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$finder->files()->in($dir);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// if finder cannot handle it, try with in()->name()
|
||||
if (strpos($dir, '/') === false) {
|
||||
$dir = './' . $dir;
|
||||
}
|
||||
$parts = explode('/', $dir);
|
||||
$new_dir = implode('/', array_slice($parts, 0, -1));
|
||||
try {
|
||||
$finder->files()->in($new_dir)->name(array_pop($parts));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return Result::fromException($this, $e);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($finder as $file) {
|
||||
// store the absolute path as key and target as value in the files array
|
||||
$files[$file->getRealpath()] = $this->getTarget($file->getRealPath(), $to);
|
||||
}
|
||||
$fileNoun = count($finder) == 1 ? ' file' : ' files';
|
||||
$this->printTaskInfo("Found {filecount} $fileNoun in {dir}", ['filecount' => count($finder), 'dir' => $dir]);
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTarget($file, $to)
|
||||
{
|
||||
$target = $to . '/' . basename($file);
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $files
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function minify($files)
|
||||
{
|
||||
// store the individual results into the results array
|
||||
$this->results = [
|
||||
'success' => [],
|
||||
'error' => [],
|
||||
];
|
||||
|
||||
// loop through the files
|
||||
foreach ($files as $from => $to) {
|
||||
$minifier = '';
|
||||
|
||||
if (!isset($this->minifier)) {
|
||||
// check filetype based on the extension
|
||||
$extension = strtolower(pathinfo($from, PATHINFO_EXTENSION));
|
||||
|
||||
// set the default minifiers based on the extension
|
||||
switch ($extension) {
|
||||
case 'png':
|
||||
$minifier = 'optipng';
|
||||
break;
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
$minifier = 'jpegtran';
|
||||
break;
|
||||
case 'gif':
|
||||
$minifier = 'gifsicle';
|
||||
break;
|
||||
case 'svg':
|
||||
$minifier = 'svgo';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!in_array($this->minifier, $this->minifiers, true)
|
||||
&& !is_callable(strtr($this->minifier, '-', '_'))
|
||||
) {
|
||||
$message = sprintf('Invalid minifier %s!', $this->minifier);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
$minifier = $this->minifier;
|
||||
}
|
||||
|
||||
// Convert minifier name to camelCase (e.g. jpeg-recompress)
|
||||
$funcMinifier = $this->camelCase($minifier);
|
||||
|
||||
// call the minifier method which prepares the command
|
||||
if (is_callable($funcMinifier)) {
|
||||
$command = call_user_func($funcMinifier, $from, $to, $this->minifierOptions);
|
||||
} elseif (method_exists($this, $funcMinifier)) {
|
||||
$command = $this->{$funcMinifier}($from, $to);
|
||||
} else {
|
||||
$message = sprintf('Minifier method <info>%s</info> cannot be found!', $funcMinifier);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
|
||||
// launch the command
|
||||
$this->printTaskInfo('Minifying {filepath} with {minifier}', ['filepath' => $from, 'minifier' => $minifier]);
|
||||
$result = $this->executeCommand($command);
|
||||
|
||||
// check the return code
|
||||
if ($result->getExitCode() == 127) {
|
||||
$this->printTaskError('The {minifier} executable cannot be found', ['minifier' => $minifier]);
|
||||
// try to install from imagemin repository
|
||||
if (array_key_exists($minifier, $this->imageminRepos)) {
|
||||
$result = $this->installFromImagemin($minifier);
|
||||
if ($result instanceof Result) {
|
||||
if ($result->wasSuccessful()) {
|
||||
$this->printTaskSuccess($result->getMessage());
|
||||
// retry the conversion with the downloaded executable
|
||||
if (is_callable($minifier)) {
|
||||
$command = call_user_func($minifier, $from, $to, $this->minifierOptions);
|
||||
} elseif (method_exists($this, $minifier)) {
|
||||
$command = $this->{$minifier}($from, $to);
|
||||
}
|
||||
// launch the command
|
||||
$this->printTaskInfo('Minifying {filepath} with {minifier}', ['filepath' => $from, 'minifier' => $minifier]);
|
||||
$result = $this->executeCommand($command);
|
||||
} else {
|
||||
$this->printTaskError($result->getMessage());
|
||||
// the download was not successful
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// check the success of the conversion
|
||||
if ($result->getExitCode() !== 0) {
|
||||
$this->results['error'][] = $from;
|
||||
} else {
|
||||
$this->results['success'][] = $from;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getOS()
|
||||
{
|
||||
$os = php_uname('s');
|
||||
$os .= '/' . php_uname('m');
|
||||
// replace x86_64 to x64, because the imagemin repo uses that
|
||||
$os = str_replace('x86_64', 'x64', $os);
|
||||
// replace i386, i686, etc to x86, because of imagemin
|
||||
$os = preg_replace('/i[0-9]86/', 'x86', $os);
|
||||
// turn info to lowercase, because of imagemin
|
||||
$os = strtolower($os);
|
||||
|
||||
return $os;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $command
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function executeCommand($command)
|
||||
{
|
||||
// insert the options into the command
|
||||
$a = explode(' ', $command);
|
||||
$executable = array_shift($a);
|
||||
foreach ($this->minifierOptions as $key => $value) {
|
||||
// first prepend the value
|
||||
if (!empty($value)) {
|
||||
array_unshift($a, $value);
|
||||
}
|
||||
// then add the key
|
||||
if (!is_numeric($key)) {
|
||||
array_unshift($a, $key);
|
||||
}
|
||||
}
|
||||
// prefer the downloaded executable if it exists already
|
||||
if (array_key_exists($executable, $this->executablePaths)) {
|
||||
$executable = $this->executablePaths[$executable];
|
||||
}
|
||||
array_unshift($a, $executable);
|
||||
$command = implode(' ', $a);
|
||||
|
||||
// execute the command
|
||||
$exec = new Exec($command);
|
||||
|
||||
return $exec->inflect($this)->printOutput(false)->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $executable
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function installFromImagemin($executable)
|
||||
{
|
||||
// check if there is an url defined for the executable
|
||||
if (!array_key_exists($executable, $this->imageminRepos)) {
|
||||
$message = sprintf('The executable %s cannot be found in the defined imagemin repositories', $executable);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
$this->printTaskInfo('Downloading the {executable} executable from the imagemin repository', ['executable' => $executable]);
|
||||
|
||||
$os = $this->getOS();
|
||||
$url = $this->imageminRepos[$executable] . '/blob/main/vendor/' . $os . '/' . $executable . '?raw=true';
|
||||
if (substr($os, 0, 3) == 'win') {
|
||||
// if it is win, add a .exe extension
|
||||
$url = $this->imageminRepos[$executable] . '/blob/main/vendor/' . $os . '/' . $executable . '.exe?raw=true';
|
||||
}
|
||||
$data = @file_get_contents($url, false, null);
|
||||
if ($data === false) {
|
||||
// there is something wrong with the url, try it without the version info
|
||||
$url = preg_replace('/x[68][64]\//', '', $url);
|
||||
$data = @file_get_contents($url, false, null);
|
||||
if ($data === false) {
|
||||
// there is still something wrong with the url if it is win, try with win32
|
||||
if (substr($os, 0, 3) == 'win') {
|
||||
$url = preg_replace('win/', 'win32/', $url);
|
||||
$data = @file_get_contents($url, false, null);
|
||||
if ($data === false) {
|
||||
// there is nothing more we can do
|
||||
$message = sprintf('Could not download the executable <info>%s</info>', $executable);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
}
|
||||
// if it is not windows there is nothing we can do
|
||||
$message = sprintf('Could not download the executable <info>%s</info>', $executable);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
}
|
||||
// check if target directory was set
|
||||
if (empty($this->executableTargetDir)) {
|
||||
return Result::error($this, 'No target directory for executables set');
|
||||
}
|
||||
// check if target directory exists
|
||||
if (!is_dir($this->executableTargetDir)) {
|
||||
// create and check access rights (directory created, but not readable)
|
||||
if (!mkdir($this->executableTargetDir) && !is_dir($this->executableTargetDir)) {
|
||||
$message = sprintf('Can not create target directory for executables in <info>%s</info>', $this->executableTargetDir);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
}
|
||||
// save the executable into the target dir
|
||||
$path = $this->executableTargetDir . '/' . $executable;
|
||||
if (substr($os, 0, 3) == 'win') {
|
||||
// if it is win, add a .exe extension
|
||||
$path = $this->executableTargetDir . '/' . $executable . '.exe';
|
||||
}
|
||||
$result = file_put_contents($path, $data);
|
||||
if ($result === false) {
|
||||
$message = sprintf('Could not copy the executable <info>%s</info> to %s', $executable, $path);
|
||||
|
||||
return Result::error($this, $message);
|
||||
}
|
||||
// set the binary to executable
|
||||
chmod($path, 0755);
|
||||
|
||||
// if everything successful, store the executable path
|
||||
$this->executablePaths[$executable] = $this->executableTargetDir . '/' . $executable;
|
||||
// if it is win, add a .exe extension
|
||||
if (substr($os, 0, 3) == 'win') {
|
||||
$this->executablePaths[$executable] .= '.exe';
|
||||
}
|
||||
|
||||
$message = sprintf('Executable <info>%s</info> successfully downloaded', $executable);
|
||||
|
||||
return Result::success($this, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function optipng($from, $to)
|
||||
{
|
||||
$command = sprintf('optipng -quiet -out "%s" -- "%s"', $to, $from);
|
||||
if ($from != $to && is_file($to)) {
|
||||
// earlier versions of optipng do not overwrite the target without a backup
|
||||
// https://sourceforge.net/p/optipng/bugs/37/
|
||||
unlink($to);
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function jpegtran($from, $to)
|
||||
{
|
||||
$command = sprintf('jpegtran -optimize -outfile "%s" "%s"', $to, $from);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function gifsicle($from, $to)
|
||||
{
|
||||
$command = sprintf('gifsicle -o "%s" "%s"', $to, $from);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function svgo($from, $to)
|
||||
{
|
||||
$command = sprintf('svgo "%s" "%s"', $from, $to);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function pngquant($from, $to)
|
||||
{
|
||||
$command = sprintf('pngquant --force --output "%s" "%s"', $to, $from);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function advpng($from, $to)
|
||||
{
|
||||
// advpng does not have any output parameters, copy the file and then compress the copy
|
||||
$command = sprintf('advpng --recompress --quiet "%s"', $to);
|
||||
$this->fs->copy($from, $to, true);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function pngout($from, $to)
|
||||
{
|
||||
$command = sprintf('pngout -y -q "%s" "%s"', $from, $to);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function zopflipng($from, $to)
|
||||
{
|
||||
$command = sprintf('zopflipng -y "%s" "%s"', $from, $to);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function pngcrush($from, $to)
|
||||
{
|
||||
$command = sprintf('pngcrush -q -ow "%s" "%s"', $from, $to);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function jpegoptim($from, $to)
|
||||
{
|
||||
// jpegoptim only takes the destination directory as an argument
|
||||
$command = sprintf('jpegoptim --quiet -o --dest "%s" "%s"', dirname($to), $from);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function jpegRecompress($from, $to)
|
||||
{
|
||||
$command = sprintf('jpeg-recompress --quiet "%s" "%s"', $from, $to);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function camelCase($text)
|
||||
{
|
||||
// non-alpha and non-numeric characters become spaces
|
||||
$text = preg_replace('/[^a-z0-9]+/i', ' ', $text);
|
||||
$text = trim($text);
|
||||
// uppercase the first character of each word
|
||||
$text = ucwords($text);
|
||||
$text = str_replace(" ", "", $text);
|
||||
$text = lcfirst($text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
109
vendor/consolidation/robo/src/Task/Assets/Less.php
vendored
Normal file
109
vendor/consolidation/robo/src/Task/Assets/Less.php
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Assets;
|
||||
|
||||
use Robo\Result;
|
||||
|
||||
/**
|
||||
* Compiles less files.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $this->taskLess([
|
||||
* 'less/default.less' => 'css/default.css'
|
||||
* ])
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Use one of both less compilers in your project:
|
||||
*
|
||||
* ```
|
||||
* "leafo/lessphp": "~0.5",
|
||||
* "oyejorge/less.php": "~1.5"
|
||||
* ```
|
||||
*
|
||||
* Specify directory (string or array) for less imports lookup:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $this->taskLess([
|
||||
* 'less/default.less' => 'css/default.css'
|
||||
* ])
|
||||
* ->importDir('less')
|
||||
* ->compiler('lessphp')
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* You can implement additional compilers by extending this task and adding a
|
||||
* method named after them and overloading the lessCompilers() method to
|
||||
* inject the name there.
|
||||
*/
|
||||
class Less extends CssPreprocessor
|
||||
{
|
||||
const FORMAT_NAME = 'less';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $compilers = [
|
||||
'less', // https://github.com/oyejorge/less.php
|
||||
'lessphp', //https://github.com/leafo/lessphp
|
||||
];
|
||||
|
||||
/**
|
||||
* lessphp compiler
|
||||
* @link https://github.com/leafo/lessphp
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function lessphp($file)
|
||||
{
|
||||
if (!class_exists('\lessc')) {
|
||||
return Result::errorMissingPackage($this, 'lessc', 'leafo/lessphp');
|
||||
}
|
||||
|
||||
$lessCode = file_get_contents($file);
|
||||
|
||||
$less = new \lessc();
|
||||
if (isset($this->compilerOptions['importDirs'])) {
|
||||
$less->setImportDir($this->compilerOptions['importDirs']);
|
||||
}
|
||||
|
||||
return $less->compile($lessCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* less compiler
|
||||
* @link https://github.com/oyejorge/less.php
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function less($file)
|
||||
{
|
||||
if (!class_exists('\Less_Parser')) {
|
||||
return Result::errorMissingPackage($this, 'Less_Parser', 'oyejorge/less.php');
|
||||
}
|
||||
|
||||
$lessCode = file_get_contents($file);
|
||||
|
||||
$parser = new \Less_Parser();
|
||||
$parser->SetOptions($this->compilerOptions);
|
||||
if (isset($this->compilerOptions['importDirs'])) {
|
||||
$importDirs = [];
|
||||
foreach ($this->compilerOptions['importDirs'] as $dir) {
|
||||
$importDirs[$dir] = $dir;
|
||||
}
|
||||
$parser->SetImportDirs($importDirs);
|
||||
}
|
||||
|
||||
$parser->parse($lessCode);
|
||||
|
||||
return $parser->getCss();
|
||||
}
|
||||
}
|
||||
299
vendor/consolidation/robo/src/Task/Assets/Minify.php
vendored
Normal file
299
vendor/consolidation/robo/src/Task/Assets/Minify.php
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Assets;
|
||||
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
|
||||
/**
|
||||
* Minifies an asset file (CSS or JS).
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->taskMinify('web/assets/theme.css')
|
||||
* ->run()
|
||||
* ?>
|
||||
* ```
|
||||
* Please install additional packages to use this task:
|
||||
*
|
||||
* ```
|
||||
* composer require patchwork/jsqueeze:^2.0
|
||||
* composer require natxet/cssmin:^3.0
|
||||
* ```
|
||||
*/
|
||||
class Minify extends BaseTask
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $types = ['css', 'js'];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $text;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $dst;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
*/
|
||||
protected $squeezeOptions = [
|
||||
'singleLine' => true,
|
||||
'keepImportantComments' => true,
|
||||
'specialVarRx' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor. Accepts asset file path or string source.
|
||||
*
|
||||
* @param string $input
|
||||
*/
|
||||
public function __construct($input)
|
||||
{
|
||||
if (file_exists($input)) {
|
||||
$this->fromFile($input);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fromText($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets destination. Tries to guess type from it.
|
||||
*
|
||||
* @param string $dst
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function to($dst)
|
||||
{
|
||||
$this->dst = $dst;
|
||||
|
||||
if (!empty($this->dst) && empty($this->type)) {
|
||||
$this->type($this->getExtension($this->dst));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets type with validation.
|
||||
*
|
||||
* @param string $type
|
||||
* Allowed values: "css", "js".
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function type($type)
|
||||
{
|
||||
$type = strtolower($type);
|
||||
|
||||
if (in_array($type, $this->types)) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets text from string source.
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function fromText($text)
|
||||
{
|
||||
$this->text = (string)$text;
|
||||
unset($this->type);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets text from asset file path. Tries to guess type and set default destination.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function fromFile($path)
|
||||
{
|
||||
$this->text = file_get_contents($path);
|
||||
|
||||
unset($this->type);
|
||||
$this->type($this->getExtension($path));
|
||||
|
||||
if (empty($this->dst) && !empty($this->type)) {
|
||||
$ext_length = strlen($this->type) + 1;
|
||||
$this->dst = substr($path, 0, -$ext_length) . '.min.' . $this->type;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets file extension from path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getExtension($path)
|
||||
{
|
||||
return pathinfo($path, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Minifies and returns text.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function getMinifiedText()
|
||||
{
|
||||
switch ($this->type) {
|
||||
case 'css':
|
||||
if (!class_exists('\CssMin')) {
|
||||
return Result::errorMissingPackage($this, 'CssMin', 'natxet/cssmin');
|
||||
}
|
||||
|
||||
return \CssMin::minify($this->text);
|
||||
break;
|
||||
|
||||
case 'js':
|
||||
if (!class_exists('\JSqueeze') && !class_exists('\Patchwork\JSqueeze')) {
|
||||
return Result::errorMissingPackage($this, 'Patchwork\JSqueeze', 'patchwork/jsqueeze');
|
||||
}
|
||||
|
||||
if (class_exists('\JSqueeze')) {
|
||||
$jsqueeze = new \JSqueeze();
|
||||
} else {
|
||||
$jsqueeze = new \Patchwork\JSqueeze();
|
||||
}
|
||||
|
||||
return $jsqueeze->squeeze(
|
||||
$this->text,
|
||||
$this->squeezeOptions['singleLine'],
|
||||
$this->squeezeOptions['keepImportantComments'],
|
||||
$this->squeezeOptions['specialVarRx']
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single line option for the JS minimisation.
|
||||
*
|
||||
* @param bool $singleLine
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function singleLine($singleLine)
|
||||
{
|
||||
$this->squeezeOptions['singleLine'] = (bool)$singleLine;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* keepImportantComments option for the JS minimisation.
|
||||
*
|
||||
* @param bool $keepImportantComments
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function keepImportantComments($keepImportantComments)
|
||||
{
|
||||
$this->squeezeOptions['keepImportantComments'] = (bool)$keepImportantComments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set specialVarRx option for the JS minimisation.
|
||||
*
|
||||
* @param bool $specialVarRx
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function specialVarRx($specialVarRx)
|
||||
{
|
||||
$this->squeezeOptions['specialVarRx'] = (bool)$specialVarRx;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->getMinifiedText();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (empty($this->type)) {
|
||||
return Result::error($this, 'Unknown asset type.');
|
||||
}
|
||||
|
||||
if (empty($this->dst)) {
|
||||
return Result::error($this, 'Unknown file destination.');
|
||||
}
|
||||
|
||||
if (file_exists($this->dst) && !is_writable($this->dst)) {
|
||||
return Result::error($this, 'Destination already exists and cannot be overwritten.');
|
||||
}
|
||||
|
||||
$size_before = strlen($this->text);
|
||||
$minified = $this->getMinifiedText();
|
||||
|
||||
if ($minified instanceof Result) {
|
||||
return $minified;
|
||||
} elseif (false === $minified) {
|
||||
return Result::error($this, 'Minification failed.');
|
||||
}
|
||||
|
||||
$size_after = strlen($minified);
|
||||
|
||||
// Minification did not reduce file size, so use original file.
|
||||
if ($size_after > $size_before) {
|
||||
$minified = $this->text;
|
||||
$size_after = $size_before;
|
||||
}
|
||||
|
||||
$dst = $this->dst . '.part';
|
||||
$write_result = file_put_contents($dst, $minified);
|
||||
|
||||
if (false === $write_result) {
|
||||
@unlink($dst);
|
||||
return Result::error($this, 'File write failed.');
|
||||
}
|
||||
// Cannot be cross-volume; should always succeed.
|
||||
@rename($dst, $this->dst);
|
||||
if ($size_before === 0) {
|
||||
$minified_percent = 0;
|
||||
} else {
|
||||
$minified_percent = number_format(100 - ($size_after / $size_before * 100), 1);
|
||||
}
|
||||
$this->printTaskSuccess('Wrote {filepath}', ['filepath' => $this->dst]);
|
||||
$context = [
|
||||
'bytes' => $this->formatBytes($size_after),
|
||||
'reduction' => $this->formatBytes(($size_before - $size_after)),
|
||||
'percentage' => $minified_percent,
|
||||
];
|
||||
$this->printTaskSuccess('Wrote {bytes} (reduced by {reduction} / {percentage})', $context);
|
||||
return Result::success($this, 'Asset minified.');
|
||||
}
|
||||
}
|
||||
94
vendor/consolidation/robo/src/Task/Assets/Scss.php
vendored
Normal file
94
vendor/consolidation/robo/src/Task/Assets/Scss.php
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Assets;
|
||||
|
||||
use Robo\Result;
|
||||
|
||||
/**
|
||||
* Compiles scss files.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $this->taskScss([
|
||||
* 'scss/default.scss' => 'css/default.css'
|
||||
* ])
|
||||
* ->importDir('assets/styles')
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Use the following scss compiler in your project:
|
||||
*
|
||||
* ```
|
||||
* "scssphp/scssphp ": "~1.0.0",
|
||||
* ```
|
||||
*
|
||||
* You can implement additional compilers by extending this task and adding a
|
||||
* method named after them and overloading the scssCompilers() method to
|
||||
* inject the name there.
|
||||
*/
|
||||
class Scss extends CssPreprocessor
|
||||
{
|
||||
const FORMAT_NAME = 'scss';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $compilers = [
|
||||
'scssphp', // https://github.com/scssphp/scssphp
|
||||
];
|
||||
|
||||
/**
|
||||
* scssphp compiler
|
||||
* @link https://github.com/scssphp/scssphp
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function scssphp($file)
|
||||
{
|
||||
if (!class_exists('\ScssPhp\ScssPhp\Compiler')) {
|
||||
return Result::errorMissingPackage($this, 'scssphp', 'scssphp/scssphp');
|
||||
}
|
||||
|
||||
$scssCode = file_get_contents($file);
|
||||
$scss = new \ScssPhp\ScssPhp\Compiler();
|
||||
|
||||
// set options for the scssphp compiler
|
||||
if (isset($this->compilerOptions['importDirs'])) {
|
||||
$scss->setImportPaths($this->compilerOptions['importDirs']);
|
||||
}
|
||||
|
||||
if (isset($this->compilerOptions['formatter'])) {
|
||||
$scss->setFormatter($this->compilerOptions['formatter']);
|
||||
}
|
||||
|
||||
return $scss->compile($scssCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the formatter for scssphp
|
||||
*
|
||||
* The method setFormatter($formatterName) sets the current formatter to $formatterName,
|
||||
* the name of a class as a string that implements the formatting interface. See the source
|
||||
* for ScssPhp\ScssPhp\Formatter\Expanded for an example.
|
||||
*
|
||||
* Five formatters are included with scssphp/scssphp:
|
||||
* - ScssPhp\ScssPhp\Formatter\Expanded
|
||||
* - ScssPhp\ScssPhp\Formatter\Nested (default)
|
||||
* - ScssPhp\ScssPhp\Formatter\Compressed
|
||||
* - ScssPhp\ScssPhp\Formatter\Compact
|
||||
* - ScssPhp\ScssPhp\Formatter\Crunched
|
||||
*
|
||||
* @link https://scssphp.github.io/scssphp/docs/#output-formatting
|
||||
*
|
||||
* @param string $formatterName
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFormatter($formatterName)
|
||||
{
|
||||
return parent::setFormatter($formatterName);
|
||||
}
|
||||
}
|
||||
46
vendor/consolidation/robo/src/Task/Assets/Tasks.php
vendored
Normal file
46
vendor/consolidation/robo/src/Task/Assets/Tasks.php
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Assets;
|
||||
|
||||
trait Tasks
|
||||
{
|
||||
/**
|
||||
* @param string $input
|
||||
*
|
||||
* @return \Robo\Task\Assets\Minify|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskMinify($input)
|
||||
{
|
||||
return $this->task(Minify::class, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|string[] $input
|
||||
*
|
||||
* @return \Robo\Task\Assets\ImageMinify|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskImageMinify($input)
|
||||
{
|
||||
return $this->task(ImageMinify::class, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $input
|
||||
*
|
||||
* @return \Robo\Task\Assets\Less|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskLess($input)
|
||||
{
|
||||
return $this->task(Less::class, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $input
|
||||
*
|
||||
* @return \Robo\Task\Assets\Scss|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskScss($input)
|
||||
{
|
||||
return $this->task(Scss::class, $input);
|
||||
}
|
||||
}
|
||||
145
vendor/consolidation/robo/src/Task/Base/Exec.php
vendored
Normal file
145
vendor/consolidation/robo/src/Task/Base/Exec.php
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Closure;
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Contract\SimulatedInterface;
|
||||
use Robo\Task\BaseTask;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Robo\Result;
|
||||
use Robo\Common\CommandReceiver;
|
||||
use Robo\Common\ExecOneCommand;
|
||||
|
||||
/**
|
||||
* Executes shell script. Closes it when running in background mode.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->taskExec('compass')->arg('watch')->run();
|
||||
* // or use shortcut
|
||||
* $this->_exec('compass watch');
|
||||
*
|
||||
* $this->taskExec('compass watch')->background()->run();
|
||||
*
|
||||
* if ($this->taskExec('phpunit .')->run()->wasSuccessful()) {
|
||||
* $this->say('tests passed');
|
||||
* }
|
||||
*
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Exec extends BaseTask implements CommandInterface, PrintedInterface, SimulatedInterface
|
||||
{
|
||||
use CommandReceiver;
|
||||
use ExecOneCommand;
|
||||
|
||||
/**
|
||||
* @var static[]
|
||||
*/
|
||||
protected static $instances = [];
|
||||
|
||||
/**
|
||||
* @var string|\Robo\Contract\CommandInterface
|
||||
*/
|
||||
protected $command;
|
||||
|
||||
private static $isSetupStopRunningJob = false;
|
||||
|
||||
/**
|
||||
* @param string|\Robo\Contract\CommandInterface $command
|
||||
*/
|
||||
public function __construct($command)
|
||||
{
|
||||
$this->command = $this->receiveCommand($command);
|
||||
|
||||
$this->setupStopRunningJobs();
|
||||
}
|
||||
|
||||
private function setupStopRunningJobs()
|
||||
{
|
||||
if (self::$isSetupStopRunningJob === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stopRunningJobs = Closure::fromCallable(self::class.'::stopRunningJobs');
|
||||
|
||||
if (function_exists('pcntl_signal')) {
|
||||
pcntl_signal(SIGTERM, $stopRunningJobs);
|
||||
}
|
||||
|
||||
register_shutdown_function($stopRunningJobs);
|
||||
|
||||
self::$isSetupStopRunningJob = true;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes command in background mode (asynchronously)
|
||||
*
|
||||
* @param bool $arg
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function background($arg = true)
|
||||
{
|
||||
self::$instances[] = $this;
|
||||
$this->background = $arg;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCommandDescription()
|
||||
{
|
||||
return $this->getCommand();
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return trim($this->command . $this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function simulate($context)
|
||||
{
|
||||
$this->printAction($context);
|
||||
}
|
||||
|
||||
public static function stopRunningJobs()
|
||||
{
|
||||
foreach (self::$instances as $instance) {
|
||||
if ($instance) {
|
||||
unset($instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->hideProgressIndicator();
|
||||
// TODO: Symfony 4 requires that we supply the working directory.
|
||||
$result_data = $this->execute(Process::fromShellCommandline($this->getCommand(), getcwd()));
|
||||
$result = new Result(
|
||||
$this,
|
||||
$result_data->getExitCode(),
|
||||
$result_data->getMessage(),
|
||||
$result_data->getData()
|
||||
);
|
||||
$this->showProgressIndicator();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
24
vendor/consolidation/robo/src/Task/Base/ExecStack.php
vendored
Normal file
24
vendor/consolidation/robo/src/Task/Base/ExecStack.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Robo\Task\CommandStack;
|
||||
|
||||
/**
|
||||
* Execute commands one by one in stack.
|
||||
* Stack can be stopped on first fail if you call `stopOnFail()`.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $this->taskExecStack()
|
||||
* ->stopOnFail()
|
||||
* ->exec('mkdir site')
|
||||
* ->exec('cd site')
|
||||
* ->run();
|
||||
*
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class ExecStack extends CommandStack
|
||||
{
|
||||
}
|
||||
216
vendor/consolidation/robo/src/Task/Base/ParallelExec.php
vendored
Normal file
216
vendor/consolidation/robo/src/Task/Base/ParallelExec.php
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Robo\Contract\CommandInterface;
|
||||
use Robo\Contract\PrintedInterface;
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
use Symfony\Component\Process\Exception\ProcessTimedOutException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Robo\Common\CommandReceiver;
|
||||
|
||||
/**
|
||||
* Class ParallelExecTask
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->taskParallelExec()
|
||||
* ->process('php ~/demos/script.php hey')
|
||||
* ->process('php ~/demos/script.php hoy')
|
||||
* ->process('php ~/demos/script.php gou')
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class ParallelExec extends BaseTask implements CommandInterface, PrintedInterface
|
||||
{
|
||||
use CommandReceiver;
|
||||
|
||||
/**
|
||||
* @var Process[]
|
||||
*/
|
||||
protected $processes = [];
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $timeout = null;
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $idleTimeout = null;
|
||||
|
||||
/**
|
||||
* @var null|int
|
||||
*/
|
||||
protected $waitInterval = 0;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isPrinted = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPrinted()
|
||||
{
|
||||
return $this->isPrinted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isPrinted
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function printOutput($isPrinted = true)
|
||||
{
|
||||
$this->isPrinted = $isPrinted;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isPrinted
|
||||
*
|
||||
* @deprecated Use printOutput instead
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function printed($isPrinted = true)
|
||||
{
|
||||
return $this->printOutput($isPrinted);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|\Robo\Contract\CommandInterface $command
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function process($command)
|
||||
{
|
||||
// TODO: Symfony 4 requires that we supply the working directory.
|
||||
$this->processes[] = Process::fromShellCommandline($this->receiveCommand($command), getcwd());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops process if it runs longer then `$timeout` (seconds).
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function timeout($timeout)
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops process if it does not output for time longer then `$timeout` (seconds).
|
||||
*
|
||||
* @param int $idleTimeout
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function idleTimeout($idleTimeout)
|
||||
{
|
||||
$this->idleTimeout = $idleTimeout;
|
||||
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}
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return implode(' && ', $this->processes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function progressIndicatorSteps()
|
||||
{
|
||||
return count($this->processes);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->startProgressIndicator();
|
||||
$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();
|
||||
} catch (ProcessTimedOutException $e) {
|
||||
$this->printTaskWarning("Process timed out for {command}", ['command' => $process->getCommandLine(), '_style' => ['command' => 'fg=white;bg=magenta']]);
|
||||
}
|
||||
if (!$process->isRunning()) {
|
||||
$this->advanceProgressIndicator();
|
||||
if ($this->isPrinted) {
|
||||
$this->printTaskInfo("Output for {command}:\n\n{output}", ['command' => $process->getCommandLine(), 'output' => $process->getOutput(), '_style' => ['command' => 'fg=white;bg=magenta']]);
|
||||
$errorOutput = $process->getErrorOutput();
|
||||
if ($errorOutput) {
|
||||
$this->printTaskError(rtrim($errorOutput));
|
||||
}
|
||||
}
|
||||
unset($running[$k]);
|
||||
}
|
||||
}
|
||||
if (empty($running) && empty($queue)) {
|
||||
break;
|
||||
}
|
||||
usleep(1000);
|
||||
}
|
||||
$this->stopProgressIndicator();
|
||||
|
||||
$errorMessage = '';
|
||||
$exitCode = 0;
|
||||
foreach ($this->processes as $p) {
|
||||
if ($p->getExitCode() === 0) {
|
||||
continue;
|
||||
}
|
||||
if (trim($p->getErrorOutput())) {
|
||||
$this->printTaskError("Error for {command} \n{output}", ['command' => $process->getCommandLine(), 'output' => $p->getErrorOutput()]);
|
||||
}
|
||||
$errorMessage .= "'" . $p->getCommandLine() . "' exited with code " . $p->getExitCode() . " \n";
|
||||
$exitCode = max($exitCode, $p->getExitCode());
|
||||
}
|
||||
if (!$errorMessage) {
|
||||
$this->printTaskSuccess('{process-count} processes finished running', ['process-count' => count($this->processes)]);
|
||||
}
|
||||
|
||||
return new Result($this, $exitCode, $errorMessage, ['time' => $this->getExecutionTime()]);
|
||||
}
|
||||
}
|
||||
18
vendor/consolidation/robo/src/Task/Base/Shortcuts.php
vendored
Normal file
18
vendor/consolidation/robo/src/Task/Base/Shortcuts.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
trait Shortcuts
|
||||
{
|
||||
/**
|
||||
* Executes shell command
|
||||
*
|
||||
* @param string|\Robo\Contract\CommandInterface $command
|
||||
*
|
||||
* @return \Robo\Result
|
||||
*/
|
||||
protected function _exec($command)
|
||||
{
|
||||
return $this->taskExec($command)->run();
|
||||
}
|
||||
}
|
||||
76
vendor/consolidation/robo/src/Task/Base/SymfonyCommand.php
vendored
Normal file
76
vendor/consolidation/robo/src/Task/Base/SymfonyCommand.php
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Robo\Robo;
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
|
||||
/**
|
||||
* Executes Symfony Command
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // Symfony Command
|
||||
* $this->taskSymfonyCommand(new \Codeception\Command\Run('run'))
|
||||
* ->arg('suite','acceptance')
|
||||
* ->opt('debug')
|
||||
* ->run();
|
||||
*
|
||||
* // Artisan Command
|
||||
* $this->taskSymfonyCommand(new ModelGeneratorCommand())
|
||||
* ->arg('name', 'User')
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class SymfonyCommand extends BaseTask
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Command\Command
|
||||
*/
|
||||
protected $command;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
public function __construct(Command $command)
|
||||
{
|
||||
$this->command = $command;
|
||||
$this->input = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $arg
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function arg($arg, $value)
|
||||
{
|
||||
$this->input[$arg] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function opt($option, $value = null)
|
||||
{
|
||||
$this->input["--$option"] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->printTaskInfo('Running command {command}', ['command' => $this->command->getName()]);
|
||||
return new Result(
|
||||
$this,
|
||||
$this->command->run(new ArrayInput($this->input), $this->output())
|
||||
);
|
||||
}
|
||||
}
|
||||
50
vendor/consolidation/robo/src/Task/Base/Tasks.php
vendored
Normal file
50
vendor/consolidation/robo/src/Task/Base/Tasks.php
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
trait Tasks
|
||||
{
|
||||
/**
|
||||
* @param string|\Robo\Contract\CommandInterface $command
|
||||
*
|
||||
* @return \Robo\Task\Base\Exec|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskExec($command)
|
||||
{
|
||||
return $this->task(Exec::class, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Task\Base\ExecStack|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskExecStack()
|
||||
{
|
||||
return $this->task(ExecStack::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Task\Base\ParallelExec|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskParallelExec()
|
||||
{
|
||||
return $this->task(ParallelExec::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\Console\Command\Command $command
|
||||
*
|
||||
* @return \Robo\Task\Base\SymfonyCommand|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskSymfonyCommand($command)
|
||||
{
|
||||
return $this->task(SymfonyCommand::class, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Robo\Task\Base\Watch|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskWatch()
|
||||
{
|
||||
return $this->task(Watch::class, $this);
|
||||
}
|
||||
}
|
||||
125
vendor/consolidation/robo/src/Task/Base/Watch.php
vendored
Normal file
125
vendor/consolidation/robo/src/Task/Base/Watch.php
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Base;
|
||||
|
||||
use Lurker\ResourceWatcher;
|
||||
use Robo\Result;
|
||||
use Robo\Task\BaseTask;
|
||||
|
||||
/**
|
||||
* Runs task when specified file or dir was changed.
|
||||
* Uses Lurker library.
|
||||
* Monitor third parameter takes Lurker filesystem events types to watch.
|
||||
* By default its set to MODIFY event.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $this->taskWatch()
|
||||
* ->monitor(
|
||||
* 'composer.json',
|
||||
* function() {
|
||||
* $this->taskComposerUpdate()->run();
|
||||
* }
|
||||
* )->monitor(
|
||||
* 'src',
|
||||
* function() {
|
||||
* $this->taskExec('phpunit')->run();
|
||||
* },
|
||||
* \Lurker\Event\FilesystemEvent::ALL
|
||||
* )->monitor(
|
||||
* 'migrations',
|
||||
* function() {
|
||||
* //do something
|
||||
* },
|
||||
* [
|
||||
* \Lurker\Event\FilesystemEvent::CREATE,
|
||||
* \Lurker\Event\FilesystemEvent::DELETE
|
||||
* ]
|
||||
* )->run();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Pass through the changed file to the callable function
|
||||
*
|
||||
* ```
|
||||
* $this
|
||||
* ->taskWatch()
|
||||
* ->monitor(
|
||||
* 'filename',
|
||||
* function ($event) {
|
||||
* $resource = $event->getResource();
|
||||
* ... do something with (string)$resource ...
|
||||
* },
|
||||
* FilesystemEvent::ALL
|
||||
* )
|
||||
* ->run();
|
||||
* ```
|
||||
*
|
||||
* The $event parameter is a [standard Symfony file resource object](https://api.symfony.com/3.1/Symfony/Component/Config/Resource/FileResource.html)
|
||||
*/
|
||||
class Watch extends BaseTask
|
||||
{
|
||||
/**
|
||||
* @var \Closure
|
||||
*/
|
||||
protected $closure;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $monitor = [];
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
protected $bindTo;
|
||||
|
||||
/**
|
||||
* @param $bindTo
|
||||
*/
|
||||
public function __construct($bindTo)
|
||||
{
|
||||
$this->bindTo = $bindTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|string[] $paths
|
||||
* @param \Closure $callable
|
||||
* @param int|int[] $events
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function monitor($paths, \Closure $callable, $events = 2)
|
||||
{
|
||||
$this->monitor[] = [(array)$paths, $callable, (array)$events];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (!class_exists('Lurker\\ResourceWatcher')) {
|
||||
return Result::errorMissingPackage($this, 'ResourceWatcher', 'totten/lurkerlite');
|
||||
}
|
||||
|
||||
$watcher = new ResourceWatcher();
|
||||
|
||||
foreach ($this->monitor as $k => $monitor) {
|
||||
/** @var \Closure $closure */
|
||||
$closure = $monitor[1];
|
||||
$closure->bindTo($this->bindTo);
|
||||
foreach ($monitor[0] as $i => $dir) {
|
||||
foreach ($monitor[2] as $j => $event) {
|
||||
$watcher->track("fs.$k.$i.$j", $dir, $event);
|
||||
$watcher->addListener("fs.$k.$i.$j", $closure);
|
||||
}
|
||||
$this->printTaskInfo('Watching {dir} for changes...', ['dir' => $dir]);
|
||||
}
|
||||
}
|
||||
|
||||
$watcher->start();
|
||||
return Result::success($this);
|
||||
}
|
||||
}
|
||||
67
vendor/consolidation/robo/src/Task/BaseTask.php
vendored
Normal file
67
vendor/consolidation/robo/src/Task/BaseTask.php
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task;
|
||||
|
||||
use Robo\Common\InflectionTrait;
|
||||
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, VerbosityThresholdInterface, ConfigAwareInterface, ProgressIndicatorAwareInterface, InflectionInterface, OutputAwareInterface
|
||||
{
|
||||
use TaskIO; // uses LoggerAwareTrait, OutputAwareTrait, 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`.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
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`.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function configPostfix()
|
||||
{
|
||||
return '.settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function injectDependencies($child)
|
||||
{
|
||||
if ($child instanceof LoggerAwareInterface && $this->logger) {
|
||||
$child->setLogger($this->logger);
|
||||
}
|
||||
if ($child instanceof OutputAwareInterface) {
|
||||
$child->setOutput($this->output());
|
||||
}
|
||||
if ($child instanceof ProgressIndicatorAwareInterface && $this->progressIndicator) {
|
||||
$child->setProgressIndicator($this->progressIndicator);
|
||||
}
|
||||
if ($child instanceof ConfigAwareInterface && $this->getConfig()) {
|
||||
$child->setConfig($this->getConfig());
|
||||
}
|
||||
if ($child instanceof VerbosityThresholdInterface && $this->outputAdapter()) {
|
||||
$child->setOutputAdapter($this->outputAdapter());
|
||||
}
|
||||
}
|
||||
}
|
||||
97
vendor/consolidation/robo/src/Task/Bower/Base.php
vendored
Normal file
97
vendor/consolidation/robo/src/Task/Bower/Base.php
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Bower;
|
||||
|
||||
use Robo\Task\BaseTask;
|
||||
use Robo\Exception\TaskException;
|
||||
use Robo\Common\ExecOneCommand;
|
||||
|
||||
abstract class Base extends BaseTask
|
||||
{
|
||||
use ExecOneCommand;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $opts = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $action = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $command = '';
|
||||
|
||||
/**
|
||||
* adds `allow-root` option to bower
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function allowRoot()
|
||||
{
|
||||
$this->option('allow-root');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `force-latest` option to bower
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function forceLatest()
|
||||
{
|
||||
$this->option('force-latest');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `production` option to bower
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noDev()
|
||||
{
|
||||
$this->option('production');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds `offline` option to bower
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function offline()
|
||||
{
|
||||
$this->option('offline');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor.
|
||||
*
|
||||
* @param null|string $pathToBower
|
||||
*
|
||||
* @throws \Robo\Exception\TaskException
|
||||
*/
|
||||
public function __construct($pathToBower = null)
|
||||
{
|
||||
$this->command = $pathToBower;
|
||||
if (!$this->command) {
|
||||
$this->command = $this->findExecutable('bower');
|
||||
}
|
||||
if (!$this->command) {
|
||||
throw new TaskException(__CLASS__, "Bower executable not found.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return "{$this->command} {$this->action}{$this->arguments}";
|
||||
}
|
||||
}
|
||||
37
vendor/consolidation/robo/src/Task/Bower/Install.php
vendored
Normal file
37
vendor/consolidation/robo/src/Task/Bower/Install.php
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Bower;
|
||||
|
||||
use Robo\Contract\CommandInterface;
|
||||
|
||||
/**
|
||||
* Bower Install
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple execution
|
||||
* $this->taskBowerInstall()->run();
|
||||
*
|
||||
* // prefer dist with custom path
|
||||
* $this->taskBowerInstall('path/to/my/bower')
|
||||
* ->noDev()
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Install extends Base implements CommandInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $action = 'install';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->printTaskInfo('Install Bower packages: {arguments}', ['arguments' => $this->arguments]);
|
||||
return $this->executeCommand($this->getCommand());
|
||||
}
|
||||
}
|
||||
26
vendor/consolidation/robo/src/Task/Bower/Tasks.php
vendored
Normal file
26
vendor/consolidation/robo/src/Task/Bower/Tasks.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Bower;
|
||||
|
||||
trait Tasks
|
||||
{
|
||||
/**
|
||||
* @param null|string $pathToBower
|
||||
*
|
||||
* @return \Robo\Task\Bower\Install|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskBowerInstall($pathToBower = null)
|
||||
{
|
||||
return $this->task(Install::class, $pathToBower);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $pathToBower
|
||||
*
|
||||
* @return \Robo\Task\Bower\Update|\Robo\Collection\CollectionBuilder
|
||||
*/
|
||||
protected function taskBowerUpdate($pathToBower = null)
|
||||
{
|
||||
return $this->task(Update::class, $pathToBower);
|
||||
}
|
||||
}
|
||||
35
vendor/consolidation/robo/src/Task/Bower/Update.php
vendored
Normal file
35
vendor/consolidation/robo/src/Task/Bower/Update.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Robo\Task\Bower;
|
||||
|
||||
/**
|
||||
* Bower Update
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // simple execution
|
||||
* $this->taskBowerUpdate->run();
|
||||
*
|
||||
* // prefer dist with custom path
|
||||
* $this->taskBowerUpdate('path/to/my/bower')
|
||||
* ->noDev()
|
||||
* ->run();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
class Update extends Base
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $action = 'update';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->printTaskInfo('Update Bower packages: {arguments}', ['arguments' => $this->arguments]);
|
||||
return $this->executeCommand($this->getCommand());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user