ExecuteTask::run()   F
last analyzed

Complexity

Conditions 16
Paths 673

Size

Total Lines 99
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 99
rs 2.3966
c 0
b 0
f 0
cc 16
eloc 55
nc 673
nop 1

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
/**
4
 * This file is part of Bldr.io
5
 *
6
 * (c) Aaron Scherer <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE
10
 */
11
12
namespace Bldr\Block\Execute\Task;
13
14
use Bldr\Block\Core\Task\AbstractTask;
15
use Bldr\Event;
16
use Bldr\Event\PostExecuteEvent;
17
use Bldr\Event\PreExecuteEvent;
18
use Bldr\Exception\TaskRuntimeException;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Console\Output\StreamOutput;
21
use Symfony\Component\Process\Process;
22
use Symfony\Component\Process\ProcessBuilder;
23
use Symfony\Component\Console\Helper\DebugFormatterHelper;
24
25
/**
26
 * @author Aaron Scherer <[email protected]>
27
 */
28
class ExecuteTask extends AbstractTask
29
{
30
    /**
31
     * Configures the Task
32
     */
33
    public function configure()
34
    {
35
        $this->setName('exec')
36
            ->setDescription('Executes the given options using the executable')
37
            ->addParameter('executable', true, 'Executable to run')
38
            ->addParameter('arguments', false, 'Arguments to run on the executable (Array)', [])
39
            ->addParameter('cwd', false, 'Sets the working directory for the executable')
40
            ->addParameter('output', false, 'Sets the location to output to')
41
            ->addParameter('raw', false, 'Should the output be raw (unformatted)')
42
            ->addParameter('successCodes', false, 'Sets the status codes allowed for a success (Array)', [0])
43
            ->addParameter('append', false, 'If output is set, should it append?', false)
44
            ->addParameter('dry_run', false, 'If set will not run command', false)
45
            ->addParameter('timeout', false, 'Timeout for the command', 0)
46
        ;
47
    }
48
49
    /**
50
     * {@inheritDoc}
51
     */
52
    public function run(OutputInterface $output)
53
    {
54
        /** @type DebugFormatterHelper $debugFormatter */
55
        $debugFormatter = $this->getHelperSet()->get('debug_formatter');
56
57
        $arguments = $this->resolveProcessArgs();
58
59
        $builder = new ProcessBuilder($arguments);
60
        $process = $builder->getProcess();
61
62
        if (null !== $dispatcher = $this->getEventDispatcher()) {
63
            $event = new PreExecuteEvent($this, $process);
64
            $dispatcher->dispatch(Event::PRE_EXECUTE, $event);
65
66
            if ($event->isPropagationStopped()) {
67
                return true;
68
            }
69
        }
70
71
        if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERY_VERBOSE) {
72
            $output->writeln(
73
                sprintf(
74
                    '        // Setting timeout for %d seconds.',
75
                    $this->getParameter('timeout')
76
                )
77
            );
78
        }
79
80
        $process->setTimeout($this->getParameter('timeout') !== 0 ? $this->getParameter('timeout') : null);
0 ignored issues
show
Bug introduced by
It seems like $this->getParameter('tim...meter('timeout') : null can also be of type array or string; however, Symfony\Component\Process\Process::setTimeout() does only seem to accept integer|double|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
81
82
        if ($this->hasParameter('cwd')) {
83
            $process->setWorkingDirectory($this->getParameter('cwd'));
0 ignored issues
show
Bug introduced by
It seems like $this->getParameter('cwd') targeting Bldr\Block\Core\Task\AbstractTask::getParameter() can also be of type array; however, Symfony\Component\Proces...::setWorkingDirectory() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
84
        }
85
86
87
        if (get_class($this) === 'Bldr\Block\Execute\Task\ExecuteTask') {
88
            $output->writeln(
89
                ['', sprintf('    <info>[%s]</info> - <comment>Starting</comment>', $this->getName()), '']
90
            );
91
        }
92
93
        if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERBOSE || $this->getParameter('dry_run')) {
94
            $output->writeln('        // '.$process->getCommandLine());
95
        }
96
97
        if ($this->getParameter('dry_run')) {
98
            return true;
99
        }
100
101
        if ($this->hasParameter('output')) {
102
            $append = $this->hasParameter('append') && $this->getParameter('append') ? 'a' : 'w';
103
            $stream = fopen($this->getParameter('output'), $append);
104
            $output = new StreamOutput($stream, StreamOutput::VERBOSITY_NORMAL, true);
105
        }
106
107
        $output->writeln("<fg=blue>==============================\n</fg=blue>");
108
        $output->writeln(
109
            $debugFormatter->start(
110
                spl_object_hash($process),
111
                $process->getCommandLine()
112
            )
113
        );
114
115
        $process->run(
116
            function ($type, $buffer) use ($output, $debugFormatter, $process) {
117
                if ($this->getParameter('raw')) {
118
                    $output->write($buffer, false, OutputInterface::OUTPUT_RAW);
119
120
                    return;
121
                }
122
123
                $output->write(
124
                    $debugFormatter->progress(
125
                        spl_object_hash($process),
126
                        $buffer,
127
                        Process::ERR === $type
128
                    )
129
                );
130
            }
131
        );
132
133
        $output->writeln(
134
            $debugFormatter->stop(
135
                spl_object_hash($process),
136
                $process->getCommandLine(),
137
                $process->isSuccessful()
138
            )
139
        );
140
        $output->writeln("<fg=blue>==============================</fg=blue>");
141
142
        if (null !== $dispatcher) {
143
            $event = new PostExecuteEvent($this, $process);
144
            $dispatcher->dispatch(Event::POST_EXECUTE, $event);
145
        }
146
147
        if (!in_array($process->getExitCode(), $this->getParameter('successCodes'))) {
148
            throw new TaskRuntimeException($this->getName(), $process->getErrorOutput());
149
        }
150
    }
151
152
    /**
153
     * Resolves the Executable and Arguments and returns a merged array
154
     *
155
     * @return array
156
     */
157
    protected function resolveProcessArgs()
158
    {
159
        return array_merge(
160
            [$this->getParameter('executable')],
161
            $this->getParameter('arguments')
162
        );
163
    }
164
}
165