task = $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. */ 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 = Robo::resultPrinter(); if ($resultPrinter) { if ($resultPrinter->printResult($this)) { $this->alreadyPrinted(); } } } /** * @param \Robo\Contract\TaskInterface $task * @param string $extension * @param string $service * * @return \Robo\Result */ 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 \Robo\Result */ 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 \Robo\Result */ 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 \Robo\Result */ 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 \Robo\Result */ 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 = Robo::resultPrinter(); if ($resultPrinter) { $resultPrinter->printStopOnFail($this); } $this->exitEarly($this->getExitCode()); } return $this; } /** * @param int $status * * @throws \Robo\Exception\TaskExitException */ private function exitEarly($status) { throw new TaskExitException($this->getTask(), $this->getMessage(), $status); } }