AbstractBinary::getBinary()   B
last analyzed

Complexity

Conditions 7
Paths 14

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 7.2269

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 10
cts 12
cp 0.8333
rs 8.2222
c 0
b 0
f 0
cc 7
eloc 11
nc 14
nop 0
crap 7.2269
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 70
    public function setBinary($binary)
74
    {
75 70
        $this->binary = $binary;
76 70
        $this->resolved = true;
77 70
    }
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 108
    public function getBinary()
95
    {
96
        $default = $this->binary;
97 108
98 97
        // Resolve true path to binary
99 97
        if (!$this->resolved) {
100 57
            $paths = $this->getKnownPaths() ?: [$default];
101 57
            if ($this->connections->getCurrentConnectionKey() && $paths) {
102 57
                $binary = Arr::get($paths, 0);
103 97
                $fallback = Arr::get($paths, 1);
104
                $this->setBinary($this->bash->which($binary, $fallback, false));
105
            } elseif ($paths) {
106 97
                $this->setBinary($paths[0]);
107
            }
108 108
        }
109
110
        return $this->binary ?: $default;
111
    }
112
113
    /**
114
     * Call or execute a command on the Binary.
115
     *
116
     * @param string $name
117
     * @param array  $arguments
118
     *
119 82
     * @return string|null
120
     */
121
    public function __call($name, $arguments)
122 82
    {
123 57
        // Execution aliases
124 57
        if (Str::startsWith($name, 'run')) {
125
            $command = array_shift($arguments);
126 57
            $command = $this->$command(...$arguments);
127
128
            return $this->bash->$name($command);
129
        }
130 72
131
        // Format name
132
        $name = Str::snake($name, '-');
133 72
134 72
        // Prepend command name to arguments and call
135
        array_unshift($arguments, $name);
136 72
        $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...
137
138
        return $command;
139
    }
140
141
    ////////////////////////////////////////////////////////////////////
142
    //////////////////////////////// HELPERS ///////////////////////////
143
    ////////////////////////////////////////////////////////////////////
144
145
    /**
146
     * Returns a command with the VCS's binary.
147
     *
148
     * @param string|null     $command
149
     * @param string|string[] $arguments
150
     * @param string|string[] $flags
151
     * @param array           $environmentVariables
152
     *
153 103
     * @return string
154
     */
155
    public function getCommand($command = null, $arguments = [], $flags = [], $environmentVariables = [])
156 103
    {
157 103
        // Format arguments
158 103
        $arguments = $this->buildArguments($arguments);
159
        $options = $this->buildOptions($flags);
160
        $environmentVariables = $this->buildEnvironmentVariables($environmentVariables);
161 103
162 103
        // Build command
163 103
        $binary = $this->getBinary();
164 103
        $components = [$command, $arguments, $options];
165 103
        foreach ($components as $component) {
166 103
            if ($component) {
167 103
                $binary .= ' '.$component;
168
            }
169
        }
170 103
171 103
        // If the binary has a parent, wrap the call with it
172
        $parent = $this->parent instanceof self ? $this->parent->getBinary() : $this->parent;
173 103
        $command = $environmentVariables.$parent.' '.$binary;
174
175
        return trim($command);
176
    }
177
178
    /**
179
     * @param string|string[] $flags
180
     *
181 103
     * @return string
182
     */
183
    protected function buildOptions($flags)
184 103
    {
185 8
        // Return if already built
186
        if (is_string($flags)) {
187
            return $flags;
188
        }
189 98
190 98
        // Build flags
191 98
        $options = [];
192 64
        $flags = $flags ? $this->sanitizeFlags($flags) : [];
193 7
        foreach ($flags as $flag => $value) {
194 7
            if (is_array($value)) {
195 7
                foreach ($value as $v) {
196 7
                    $options[] = $flag.'="'.$v.'"';
197 63
                }
198 1
            } else {
199 1
                if (is_numeric($flag)) {
200 1
                    $flag = $value;
201
                    $value = null;
202 63
                }
203
204 98
                $options[] = $value ? $flag.'="'.$value.'"' : $flag;
205
            }
206 98
        }
207
208
        return implode(' ', $options);
209
    }
210
211
    /**
212
     * @param string|string[] $arguments
213
     *
214 103
     * @return string
215
     */
216 103
    protected function buildArguments($arguments)
217 96
    {
218 96
        if (!is_string($arguments)) {
219 96
            $arguments = (array) $arguments;
220
            $arguments = implode(' ', $arguments);
221 103
        }
222
223
        return $arguments;
224
    }
225
226
    /**
227
     * @param array $env
228
     *
229 103
     * @return string
230
     */
231 103
    protected function buildEnvironmentVariables($env)
232 103
    {
233 8
        $variables = '';
234 103
        foreach ($env as $key => $value) {
235
            $variables .= $key.'='.$value.' ';
236 103
        }
237
238
        return trim($variables);
239
    }
240
241
    /**
242
     * Quote a string.
243
     *
244
     * @param string $string
245
     *
246 23
     * @return string
247
     */
248 23
    protected function quote($string)
249
    {
250
        return '"'.$string.'"';
251
    }
252
253
    /**
254
     * Sanitize a flags array.
255
     *
256
     * @param array $flags
257
     *
258 64
     * @return array
259
     */
260 64
    protected function sanitizeFlags(array $flags)
261
    {
262
        $flags = (array) $flags;
263 64
264 64
        // Flip array if necessary
265 24
        $firstKey = Arr::get(array_keys($flags), 0);
266 24
        if ($firstKey !== null && is_int($firstKey)) {
267 24
            $flags = array_combine(
268 24
                array_values($flags),
269 24
                array_fill(0, count($flags), null)
270
            );
271 64
        }
272
273
        return $flags;
274
    }
275
}
276