Completed
Push — master ( b7a64b...32e57f )
by Greg
02:36
created

ExecTrait::execute()   D

Complexity

Conditions 13
Paths 256

Size

Total Lines 68
Code Lines 45

Duplication

Lines 21
Ratio 30.88 %

Importance

Changes 0
Metric Value
dl 21
loc 68
rs 4.2817
c 0
b 0
f 0
cc 13
eloc 45
nc 256
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Robo\Common;
4
5
use Robo\ResultData;
6
use Symfony\Component\Process\Process;
7
8
/**
9
 * Class ExecTrait
10
 * @package Robo\Common
11
 */
12
trait ExecTrait
13
{
14
    /**
15
     * @var bool
16
     */
17
    protected $background = false;
18
19
    /**
20
     * @var null|int
21
     */
22
    protected $timeout = null;
23
24
    /**
25
     * @var null|int
26
     */
27
    protected $idleTimeout = null;
28
29
    /**
30
     * @var null|array
31
     */
32
    protected $env = null;
33
34
    /**
35
     * @var Process
36
     */
37
    protected $process;
38
39
    /**
40
     * @var resource|string
41
     */
42
    protected $input;
43
44
    /**
45
     * @var boolean
46
     */
47
    protected $interactive = null;
48
49
    /**
50
     * @var bool
51
     */
52
    protected $isPrinted = true;
53
54
    /**
55
     * @var bool
56
     */
57
    protected $isMetadataPrinted = true;
58
59
    /**
60
     * @var string
61
     */
62
    protected $workingDirectory;
63
64
    /**
65
     * @return string
66
     */
67
    abstract public function getCommandDescription();
68
69
    /** Typically provided by Timer trait via ProgressIndicatorAwareTrait. */
70
    abstract public function startTimer();
71
    abstract public function stopTimer();
72
    abstract public function getExecutionTime();
73
74
    /**
75
     * Typically provided by TaskIO Trait.
76
     */
77
    abstract public function hideTaskProgress();
78
    abstract public function showTaskProgress($inProgress);
79
    abstract public function printTaskInfo($text, $context = null);
80
81
    /**
82
     * Typically provided by VerbosityThresholdTrait.
83
     */
84
    abstract public function verbosityMeetsThreshold();
85
    abstract public function writeMessage($message);
86
87
    /**
88
     * Sets $this->interactive() based on posix_isatty().
89
     *
90
     * @return $this
91
     */
92
    public function detectInteractive()
93
    {
94
        // If the caller did not explicity set the 'interactive' mode,
95
        // and output should be produced by this task (verbosityMeetsThreshold),
96
        // then we will automatically set interactive mode based on whether
97
        // or not output was redirected when robo was executed.
98
        if (!isset($this->interactive) && function_exists('posix_isatty') && $this->verbosityMeetsThreshold()) {
99
            $this->interactive = posix_isatty(STDOUT);
100
        }
101
102
        return $this;
103
    }
104
105
    /**
106
     * Executes command in background mode (asynchronously)
107
     *
108
     * @return $this
109
     */
110
    public function background($arg = true)
111
    {
112
        $this->background = $arg;
113
        return $this;
114
    }
115
116
    /**
117
     * Stop command if it runs longer then $timeout in seconds
118
     *
119
     * @param int $timeout
120
     *
121
     * @return $this
122
     */
123
    public function timeout($timeout)
124
    {
125
        $this->timeout = $timeout;
126
        return $this;
127
    }
128
129
    /**
130
     * Stops command if it does not output something for a while
131
     *
132
     * @param int $timeout
133
     *
134
     * @return $this
135
     */
136
    public function idleTimeout($timeout)
137
    {
138
        $this->idleTimeout = $timeout;
139
        return $this;
140
    }
141
142
    /**
143
     * Set a single environment variable, or multiple.
144
     */
145
    public function env($env, $value = null)
146
    {
147
        if (!is_array($env)) {
148
            $env = [$env => ($value ? $value : true)];
149
        }
150
        return $this->envVars($env);
151
    }
152
153
    /**
154
     * Sets the environment variables for the command
155
     *
156
     * @param array $env
157
     *
158
     * @return $this
159
     */
160
    public function envVars(array $env)
161
    {
162
        $this->env = $env;
163
        return $this;
164
    }
165
166
    /**
167
     * Pass an input to the process. Can be resource created with fopen() or string
168
     *
169
     * @param resource|string $input
170
     *
171
     * @return $this
172
     */
173
    public function setInput($input)
174
    {
175
        $this->input = $input;
176
        return $this;
177
    }
178
179
    /**
180
     * Attach tty to process for interactive input
181
     *
182
     * @param $interactive bool
183
     *
184
     * @return $this
185
     */
186
    public function interactive($interactive = true)
187
    {
188
        $this->interactive = $interactive;
189
        return $this;
190
    }
191
192
193
    /**
194
     * Is command printing its output to screen
195
     *
196
     * @return bool
197
     */
198
    public function getPrinted()
199
    {
200
        return $this->isPrinted;
201
    }
202
203
    /**
204
     * Changes working directory of command
205
     *
206
     * @param string $dir
207
     *
208
     * @return $this
209
     */
210
    public function dir($dir)
211
    {
212
        $this->workingDirectory = $dir;
213
        return $this;
214
    }
215
216
    /**
217
     * Shortcut for setting isPrinted() and isMetadataPrinted() to false.
218
     *
219
     * @param bool $arg
220
     *
221
     * @return $this
222
     */
223
    public function silent($arg)
224
    {
225
        if (is_bool($arg)) {
226
            $this->isPrinted = !$arg;
227
            $this->isMetadataPrinted = !$arg;
228
        }
229
        return $this;
230
    }
231
232
    /**
233
     * Should command output be printed
234
     *
235
     * @param bool $arg
236
     *
237
     * @return $this
238
     *
239
     * @deprecated
240
     */
241
    public function printed($arg)
242
    {
243
        $this->logger->warning("printed() is deprecated. Please use printOutput().");
0 ignored issues
show
Bug introduced by
The property logger does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
244
        return $this->printOutput($arg);
245
    }
246
247
    /**
248
     * Should command output be printed
249
     *
250
     * @param bool $arg
251
     *
252
     * @return $this
253
     */
254
    public function printOutput($arg)
255
    {
256
        if (is_bool($arg)) {
257
            $this->isPrinted = $arg;
258
        }
259
        return $this;
260
    }
261
262
    /**
263
     * Should command metadata be printed. I,e., command and timer.
264
     *
265
     * @param bool $arg
266
     *
267
     * @return $this
268
     */
269
    public function printMetadata($arg)
270
    {
271
        if (is_bool($arg)) {
272
            $this->isMetadataPrinted = $arg;
273
        }
274
        return $this;
275
    }
276
277
    /**
278
     * @param Process $process
279
     * @param callable $output_callback
280
     *
281
     * @return \Robo\ResultData
282
     */
283
    protected function execute($process, $output_callback = null)
284
    {
285
        $this->process = $process;
286
287
        if (!$output_callback) {
288
            $output_callback = function ($type, $buffer) {
289
                $progressWasVisible = $this->hideTaskProgress();
290
                $this->writeMessage($buffer);
291
                $this->showTaskProgress($progressWasVisible);
292
            };
293
        }
294
295
        $this->detectInteractive();
296
297
        if ($this->isMetadataPrinted) {
298
            $this->printAction();
299
        }
300
        $this->process->setTimeout($this->timeout);
301
        $this->process->setIdleTimeout($this->idleTimeout);
302
        if ($this->workingDirectory) {
303
            $this->process->setWorkingDirectory($this->workingDirectory);
304
        }
305
        if ($this->input) {
306
            $this->process->setInput($this->input);
307
        }
308
309
        if ($this->interactive && $this->isPrinted) {
310
            $this->process->setTty(true);
311
        }
312
313
        if (isset($this->env)) {
314
            $this->process->setEnv($this->env);
315
        }
316
317 View Code Duplication
        if (!$this->background && !$this->isPrinted) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
318
            $this->startTimer();
319
            $this->process->run();
320
            $this->stopTimer();
321
            $output = rtrim($this->process->getOutput());
322
            return new ResultData(
323
                $this->process->getExitCode(),
324
                $output,
325
                $this->getResultData()
326
            );
327
        }
328
329 View Code Duplication
        if (!$this->background && $this->isPrinted) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
330
            $this->startTimer();
331
            $this->process->run($output_callback);
332
            $this->stopTimer();
333
            return new ResultData(
334
                $this->process->getExitCode(),
335
                $this->process->getOutput(),
336
                $this->getResultData()
337
            );
338
        }
339
340
        try {
341
            $this->process->start();
342
        } catch (\Exception $e) {
343
            return new ResultData(
344
                $this->process->getExitCode(),
345
                $e->getMessage(),
346
                $this->getResultData()
347
            );
348
        }
349
        return new ResultData($this->process->getExitCode());
350
    }
351
352
    /**
353
     *
354
     */
355
    protected function stop()
356
    {
357
        if ($this->background && isset($this->process) && $this->process->isRunning()) {
358
            $this->process->stop();
359
            $this->printTaskInfo(
360
                "Stopped {command}",
361
                ['command' => $this->getCommandDescription()]
362
            );
363
        }
364
    }
365
366
    /**
367
     * @param array $context
368
     */
369
    protected function printAction($context = [])
370
    {
371
        $command = $this->getCommandDescription();
372
        $formatted_command = $this->formatCommandDisplay($command);
373
374
        $dir = $this->workingDirectory ? " in {dir}" : "";
375
        $this->printTaskInfo("Running {command}$dir", [
376
                'command' => $formatted_command,
377
                'dir' => $this->workingDirectory
378
            ] + $context);
379
    }
380
381
    /**
382
     * @param $command
383
     *
384
     * @return mixed
385
     */
386
    protected function formatCommandDisplay($command)
387
    {
388
        $formatted_command = str_replace("&&", "&&\n", $command);
389
        $formatted_command = str_replace("||", "||\n", $formatted_command);
390
391
        return $formatted_command;
392
    }
393
394
    /**
395
     * Gets the data array to be passed to Result().
396
     *
397
     * @return array
398
     *   The data array passed to Result().
399
     */
400
    protected function getResultData()
401
    {
402
        if ($this->isMetadataPrinted) {
403
            return ['time' => $this->getExecutionTime()];
404
        }
405
406
        return [];
407
    }
408
}
409