4 use Robo\Contract\WrappedTaskInterface;
5 use Robo\Exception\TaskException;
8 use Robo\Contract\TaskInterface;
9 use Robo\Contract\SimulatedInterface;
10 use Robo\Log\RoboLogLevel;
11 use Robo\Contract\CommandInterface;
13 class Simulator extends BaseTask implements CommandInterface
16 * @var \Robo\Contract\TaskInterface
23 protected $constructorParameters;
28 protected $stack = [];
31 * @param \Robo\Contract\TaskInterface $task
32 * @param array $constructorParameters
34 public function __construct(TaskInterface $task, $constructorParameters)
36 // TODO: If we ever want to convert the simulated task back into
37 // an executable task, then we should save the wrapped task.
38 $this->task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task;
39 $this->constructorParameters = $constructorParameters;
43 * @param string $function
46 * @return \Robo\Result|\Robo\Task\Simulator
48 public function __call($function, $args)
50 $this->stack[] = array_merge([$function], $args);
51 $result = call_user_func_array([$this->task, $function], $args);
52 return $result == $this->task ? $this : $result;
61 foreach ($this->stack as $action) {
62 $command = array_shift($action);
63 $parameters = $this->formatParameters($action);
64 $callchain .= "\n ->$command(<fg=green>$parameters</>)";
66 $context = $this->getTaskContext(
68 '_level' => RoboLogLevel::SIMULATED_ACTION,
69 'simulated' => TaskInfo::formatTaskName($this->task),
70 'parameters' => $this->formatParameters($this->constructorParameters),
71 '_style' => ['simulated' => 'fg=blue;options=bold'],
75 // RoboLogLevel::SIMULATED_ACTION
77 "Simulating {simulated}({parameters})$callchain",
82 if ($this->task instanceof SimulatedInterface) {
83 $result = $this->task->simulate($context);
85 if (!isset($result)) {
86 $result = Result::success($this);
93 * Danger: reach through the simulated wrapper and pull out the command
94 * to be executed. This is used when using a simulated task with another
95 * simulated task that runs commands, e.g. the Remote\Ssh task. Using
96 * a simulated CommandInterface task with a non-simulated task may produce
97 * unexpected results (e.g. execution!).
101 * @throws \Robo\Exception\TaskException
103 public function getCommand()
105 if (!$this->task instanceof CommandInterface) {
106 throw new TaskException($this->task, 'Simulated task that is not a CommandInterface used as a CommandInterface.');
108 return $this->task->getCommand();
112 * @param string $action
116 protected function formatParameters($action)
118 $parameterList = array_map([$this, 'convertParameter'], $action);
119 return implode(', ', $parameterList);
127 protected function convertParameter($item)
129 if (is_callable($item)) {
130 return 'inline_function(...)';
132 if (is_array($item)) {
133 return $this->shortenParameter(var_export($item, true));
135 if (is_object($item)) {
136 return '[' . get_class($item). ' object]';
138 if (is_string($item)) {
139 return $this->shortenParameter("'$item'");
141 if (is_null($item)) {
148 * @param string $item
149 * @param string $shortForm
153 protected function shortenParameter($item, $shortForm = '')
157 if (strlen($item) < $maxLength) {
160 if (!empty($shortForm)) {
164 $tail = preg_replace("#.*\n#ms", '', substr($item, -$tailLength));
165 $head = preg_replace("#\n.*#ms", '', substr($item, 0, $maxLength - (strlen($tail) + 5)));
166 return "$head ... $tail";