Failed Conditions
Push — develop ( 97d950...17c62d )
by Maxime
19:32
created

AbstractBinary::getCommand()   B

Complexity

Conditions 4
Paths 6

Duplication

Lines 0
Ratio 0 %

Size

Total Lines 22
Code Lines 12

Code Coverage

Tests 14
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 14
cts 14
cp 1
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 12
nc 6
nop 4
crap 4
1
<?php
2
3
/*
4
 * This file is part of Rocketeer
5
 *
6
 * (c) Maxime Fabre <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 */
12
13
namespace Rocketeer\Binaries;
14
15
use Illuminate\Support\Arr;
16
use Illuminate\Support\Str;
17
use Rocketeer\Services\Connections\Shell\Bash;
18
use Rocketeer\Traits\ContainerAwareTrait;
19
20
/**
21
 * A generic class to represent a binary as a class.
22
 *
23
 * @mixin Bash
24
 */
25
abstract class AbstractBinary
26
{
27
    use ContainerAwareTrait;
28
29
    /**
30
     * The core binary.
31
     *
32
     * @var string
33
     */
34
    protected $binary;
35
36
    /**
37
     * @var bool
38
     */
39
    protected $resolved = false;
40
41
    /**
42
     * A parent binary to call this one with.
43
     *
44
     * @var AbstractBinary|string
45
     */
46
    protected $parent;
47
48
    /**
49
     * Get an array of default paths to look for.
50
     *
51
     * @return array
52
     */
53 65
    protected function getKnownPaths()
54
    {
55 65
        return [];
56
    }
57
58
    //////////////////////////////////////////////////////////////////////
59
    ///////////////////////////// PROPERTIES /////////////////////////////
60
    //////////////////////////////////////////////////////////////////////
61
62
    /**
63
     * @param AbstractBinary|string $parent
64
     */
65 8
    public function setParent($parent)
66
    {
67 8
        $this->parent = $parent;
68 8
    }
69
70
    /**
71
     * @param string $binary
72
     */
73 68
    public function setBinary($binary)
74
    {
75 68
        $this->binary = $binary;
76 68
        $this->resolved = true;
77 68
    }
78
79
    /**
80
     * Get the name of the binary class.
81
     *
82
     * @return string
83
     */
84 5
    public function getName()
85
    {
86 5
        return class_basename($this);
87 1
    }
88
89
    /**
90
     * Get the current binary name.
91
     *
92
     * @return string
93
     */
94 106
    public function getBinary()
95
    {
96
        // Resolve true path to binary
97 106
        if (!$this->resolved) {
98 95
            $paths = $this->getKnownPaths();
99 95
            if ($this->connections->getCurrentConnectionKey() && $paths) {
100 55
                $binary = Arr::get($paths, 0);
101 55
                $fallback = Arr::get($paths, 1);
102 55
                $this->setBinary($this->bash->which($binary, $fallback, false));
103 95
            } elseif ($paths) {
104
                $this->setBinary($paths[0]);
105
            }
106 95
        }
107
108 106
        return $this->binary;
109
    }
110
111
    /**
112
     * Call or execute a command on the Binary.
113
     *
114
     * @param string $name
115
     * @param array  $arguments
116
     *
117
     * @return string|null
118
     */
119 80
    public function __call($name, $arguments)
120
    {
121
        // Execution aliases
122 80
        if (Str::startsWith($name, 'run')) {
123 60
            $command = array_shift($arguments);
124 60
            $command = $this->$command(...$arguments);
125
126 60
            return $this->bash->$name($command);
127
        }
128
129
        // Format name
130 70
        $name = Str::snake($name, '-');
131
132
        // Prepend command name to arguments and call
133 70
        array_unshift($arguments, $name);
134 70
        $command = $this->getCommand(...$arguments);
0 ignored issues
show
Documentation introduced by Maxime Fabre
$arguments is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
135
136 70
        return $command;
137
    }
138
139
    ////////////////////////////////////////////////////////////////////
140
    //////////////////////////////// HELPERS ///////////////////////////
141
    ////////////////////////////////////////////////////////////////////
142
143
    /**
144
     * Returns a command with the VCS's binary.
145
     *
146
     * @param string|null     $command
147
     * @param string|string[] $arguments
148
     * @param string|string[] $flags
149
     * @param array           $environmentVariables
150
     *
151
     * @return string
152
     */
153 101
    public function getCommand($command = null, $arguments = [], $flags = [], $environmentVariables = [])
154
    {
155
        // Format arguments
156 101
        $arguments = $this->buildArguments($arguments);
157 101
        $options = $this->buildOptions($flags);
158 101
        $environmentVariables = $this->buildEnvironmentVariables($environmentVariables);
159
160
        // Build command
161 101
        $binary = $this->getBinary();
162 101
        $components = [$command, $arguments, $options];
163 101
        foreach ($components as $component) {
164 101
            if ($component) {
165 101
                $binary .= ' '.$component;
166 101
            }
167 101
        }
168
169
        // If the binary has a parent, wrap the call with it
170 101
        $parent = $this->parent instanceof self ? $this->parent->getBinary() : $this->parent;
171 101
        $command = $environmentVariables.$parent.' '.$binary;
172
173 101
        return trim($command);
174
    }
175
176
    /**
177
     * @param string|string[] $flags
178
     *
179
     * @return string
180
     */
181 101
    protected function buildOptions($flags)
182
    {
183
        // Return if already builts
184 101
        if (is_string($flags)) {
185 8
            return $flags;
186
        }
187
188
        // Build flags
189 96
        $options = [];
190 96
        $flags = $flags ? $this->sanitizeFlags($flags) : [];
191 96
        foreach ($flags as $flag => $value) {
192 62
            if (is_array($value)) {
193 7
                foreach ($value as $v) {
194 7
                    $options[] = $flag.'="'.$v.'"';
195 7
                }
196 7
            } else {
197 61
                if (is_numeric($flag)) {
198 1
                    $flag = $value;
199 1
                    $value = null;
200 1
                }
201
202 61
                $options[] = $value ? $flag.'="'.$value.'"' : $flag;
203
            }
204 96
        }
205
206 96
        return implode(' ', $options);
207
    }
208
209
    /**
210
     * @param string|string[] $arguments
211
     *
212
     * @return string
213
     */
214 101
    protected function buildArguments($arguments)
215
    {
216 101
        if (!is_string($arguments)) {
217 95
            $arguments = (array) $arguments;
218 95
            $arguments = implode(' ', $arguments);
219 95
        }
220
221 101
        return $arguments;
222
    }
223
224
    /**
225
     * @param array $env
226
     *
227
     * @return string
228
     */
229 101
    protected function buildEnvironmentVariables($env)
230
    {
231 101
        $variables = '';
232 101
        foreach ($env as $key => $value) {
233 1
            $variables .= $key.'='.$value.' ';
234 101
        }
235
236 101
        return trim($variables);
237
    }
238
239
    /**
240
     * Quote a string.
241
     *
242
     * @param string $string
243
     *
244
     * @return string
245
     */
246 23
    protected function quote($string)
247
    {
248 23
        return '"'.$string.'"';
249
    }
250
251
    /**
252
     * Sanitize a flags array.
253
     *
254
     * @param array $flags
255
     *
256
     * @return array
257
     */
258 62
    protected function sanitizeFlags(array $flags)
259
    {
260 62
        $flags = (array) $flags;
261
262
        // Flip array if necessary
263 62
        $firstKey = Arr::get(array_keys($flags), 0);
264 62
        if ($firstKey !== null && is_int($firstKey)) {
265 24
            $flags = array_combine(
266 24
                array_values($flags),
267 24
                array_fill(0, count($flags), null)
268 24
            );
269 24
        }
270
271 62
        return $flags;
272
    }
273
}
274