Completed
Push — develop ( 61d4f1...4b8b90 )
by
unknown
9s
created

BaseCommand::getBinaryVersion()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * GitElephant - An abstraction layer for git written in PHP
4
 * Copyright (C) 2013  Matteo Giachino
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see [http://www.gnu.org/licenses/].
18
 */
19
20
namespace GitElephant\Command;
21
22
use \GitElephant\Repository;
23
use \PhpCollection\Map;
24
25
/**
26
 * BaseCommand
27
 *
28
 * The base class for all the command generators
29
 *
30
 * @author Matteo Giachino <[email protected]>
31
 */
32
class BaseCommand
33
{
34
    /**
35
     * the command name
36
     *
37
     * @var string
38
     */
39
    private $commandName = null;
40
41
    /**
42
     * config options
43
     *
44
     * @var array
45
     */
46
    private $configs = array();
47
48
    /**
49
     * global configs
50
     *
51
     * @var array
52
     */
53
    private $globalConfigs = array();
54
55
    /**
56
     * global options
57
     *
58
     * @var array
59
     */
60
    private $globalOptions = array();
61
62
    /**
63
     * the command arguments
64
     *
65
     * @var array
66
     */
67
    private $commandArguments = array();
68
69
    /**
70
     * the global command arguments
71
     *
72
     * @var array
73
     */
74
    private $globalCommandArguments = array();
75
76
    /**
77
     * the command subject
78
     *
79
     * @var string|SubCommandCommand
80
     */
81
    private $commandSubject = null;
82
83
    /**
84
     * the command second subject (i.e. for branch)
85
     *
86
     * @var string|SubCommandCommand
87
     */
88
    private $commandSubject2 = null;
89
90
    /**
91
     * the path
92
     *
93
     * @var string
94
     */
95
    private $path = null;
96
97
    /**
98
     * @var string
99
     */
100
    private $binaryVersion;
101
102
    /**
103
     * @var Repository
104
     */
105
    private $repo;
106
107
    /**
108
     * constructor
109
     *
110
     * should be called by all child classes' constructors to permit use of
111
     * global configs, options and command arguments
112
     *
113
     * @param null|\GitElephant\Repository $repo The repo object to read
114
     */
115 130
    public function __construct(Repository $repo = null)
116
    {
117 130
        if (!is_null($repo)) {
118 99
            $this->addGlobalConfigs($repo->getGlobalConfigs());
119 99
            $this->addGlobalOptions($repo->getGlobalOptions());
120
121 99
            $arguments = $repo->getGlobalCommandArguments();
122 99
            if (!empty($arguments)) {
123 1
                foreach ($arguments as $argument) {
124 1
                    $this->addGlobalCommandArgument($argument);
125
                }
126
            }
127 99
            $this->repo = $repo;
128
        }
129 130
    }
130
131
    /**
132
     * Clear all previous variables
133
     */
134 115
    public function clearAll()
135
    {
136 115
        $this->commandName = null;
137 115
        $this->configs = array();
138 115
        $this->commandArguments = array();
139 115
        $this->commandSubject = null;
140 115
        $this->commandSubject2 = null;
141 115
        $this->path = null;
142 115
        $this->binaryVersion = null;
143 115
    }
144
145 120
    public static function getInstance(Repository $repo = null)
146
    {
147 120
        return new static($repo);
148
    }
149
150
    /**
151
     * Add the command name
152
     *
153
     * @param string $commandName the command name
154
     */
155 116
    protected function addCommandName($commandName)
156
    {
157 116
        $this->commandName = $commandName;
158 116
    }
159
160
    /**
161
     * Get command name
162
     *
163
     * @return string
164
     */
165 11
    protected function getCommandName()
166
    {
167 11
        return $this->commandName;
168
    }
169
170
    /**
171
     * Set Configs
172
     *
173
     * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" }
174
     */
175 3
    public function addConfigs($configs)
176
    {
177 3
        foreach ($configs as $config => $value) {
178 3
            $this->configs[$config] = $value;
179
        }
180 3
    }
181
182
    /**
183
     * Set global configs
184
     *
185
     * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" }
186
     */
187 99
    protected function addGlobalConfigs($configs)
188
    {
189 99
        if (!empty($configs)) {
190 1
            foreach ($configs as $config => $value) {
191 1
                $this->globalConfigs[$config] = $value;
192
            }
193
        }
194 99
    }
195
196
    /**
197
     * Set global option
198
     *
199
     * @param array|Map $options a global option
200
     */
201 99
    protected function addGlobalOptions($options)
202
    {
203 99
        if (!empty($options)) {
204 1
            foreach ($options as $name => $value) {
205 1
                $this->globalOptions[$name] = $value;
206
            }
207
        }
208 99
    }
209
210
    /**
211
     * Get Configs
212
     *
213
     * @return array
214
     */
215
    public function getConfigs()
216
    {
217
        return $this->configs;
218
    }
219
220
    /**
221
     * Add a command argument
222
     *
223
     * @param string $commandArgument the command argument
224
     */
225 107
    protected function addCommandArgument($commandArgument)
226
    {
227 107
        $this->commandArguments[] = $commandArgument;
228 107
    }
229
230
    /**
231
     * Add a global command argument
232
     *
233
     * @param string $commandArgument the command argument
234
     */
235 1
    protected function addGlobalCommandArgument($commandArgument)
236
    {
237 1
        if (!empty($commandArgument)) {
238 1
            $this->globalCommandArguments[] = $commandArgument;
239
        }
240 1
    }
241
242
    /**
243
     * Get all added command arguments
244
     *
245
     * @return array
246
     */
247 11
    protected function getCommandArguments()
248
    {
249 11
        return ($this->commandArguments) ? $this->commandArguments : array();
250
    }
251
252
    /**
253
     * Add a command subject
254
     *
255
     * @param SubCommandCommand|array|string $commandSubject the command subject
256
     */
257 105
    protected function addCommandSubject($commandSubject)
258
    {
259 105
        $this->commandSubject = $commandSubject;
0 ignored issues
show
Documentation Bug introduced by
It seems like $commandSubject can also be of type array. However, the property $commandSubject is declared as type string|object<GitElephan...mand\SubCommandCommand>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
260 105
    }
261
262
    /**
263
     * Add a second command subject
264
     *
265
     * @param SubCommandCommand|array|string $commandSubject2 the second command subject
266
     */
267 22
    protected function addCommandSubject2($commandSubject2)
268
    {
269 22
        $this->commandSubject2 = $commandSubject2;
0 ignored issues
show
Documentation Bug introduced by
It seems like $commandSubject2 can also be of type array. However, the property $commandSubject2 is declared as type string|object<GitElephan...mand\SubCommandCommand>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
270 22
    }
271
272
    /**
273
     * Add a path to the git command
274
     *
275
     * @param string $path path
276
     */
277 19
    protected function addPath($path)
278
    {
279 19
        $this->path = $path;
280 19
    }
281
282
    /**
283
     * Normalize any valid option to its long name
284
     * an provide a structure that can be more intelligently
285
     * handled by other routines
286
     *
287
     * @param array $options       command options
288
     * @param array $switchOptions list of valid options that are switch like
289
     * @param array $valueOptions  list of valid options that must have a value assignment
290
     *
291
     * @return array Associative array of valid, normalized command options
292
     */
293 15
    public function normalizeOptions(array $options = array(), array $switchOptions = array(), $valueOptions = array())
294
    {
295 15
        $normalizedOptions = array();
296
297 15
        foreach ($options as $option) {
298 7
            if (array_key_exists($option, $switchOptions)) {
299 7
                $normalizedOptions[$switchOptions[$option]] = $switchOptions[$option];
300
            } else {
301 1
                $parts = preg_split('/([\s=])+/', $option, 2, PREG_SPLIT_DELIM_CAPTURE);
302 1
                if (count($parts)) {
303 1
                    $optionName = $parts[0];
304 1
                    if (in_array($optionName, $valueOptions)) {
305 1
                        $value = ($parts[1] == '=') ? $option : array($parts[0], $parts[2]);
306 7
                        $normalizedOptions[$optionName] = $value;
307
                    }
308
                }
309
            }
310
        }
311
312 15
        return $normalizedOptions;
313
    }
314
315
    /**
316
     * Get the current command
317
     *
318
     * @return string
319
     * @throws \RuntimeException
320
     */
321 117
    public function getCommand()
322
    {
323 117
        if (is_null($this->commandName)) {
324 1
            throw new \RuntimeException("You should pass a commandName to execute a command");
325
        }
326
327 116
        $command = '';
328 116
        $command .= $this->getCLIConfigs();
329 116
        $command .= $this->getCLIGlobalOptions();
330 116
        $command .= $this->getCLICommandName();
331 116
        $command .= $this->getCLICommandArguments();
332 116
        $command .= $this->getCLISubjects();
333 116
        $command .= $this->getCLIPath();
334
335 116
        $command = preg_replace('/\\s{2,}/', ' ', $command);
336
337 116
        return trim($command);
338
    }
339
340
    /**
341
     * get a string of CLI-formatted command arguments
342
     *
343
     * @return string The command argument string
344
     */
345 117
    private function getCLICommandArguments()
346
    {
347 117
        $command = '';
348 117
        $combinedArguments = array_merge($this->globalCommandArguments, $this->commandArguments);
349 117
        if (count($combinedArguments) > 0) {
350 107
            $command .= ' ' . implode(' ', array_map('escapeshellarg', $combinedArguments));
351
        }
352 117
        return $command;
353
    }
354
355
    /**
356
     * get a string of CLI-formatted command name
357
     *
358
     * @return string The command name string
359
     */
360 117
    private function getCLICommandName()
361
    {
362 117
        return ' ' . $this->commandName;
363
    }
364
365
    /**
366
     * get a string of CLI-formatted configs
367
     *
368
     * @return string The config string
369
     */
370 117
    private function getCLIConfigs()
371
    {
372 117
        $command = '';
373 117
        $combinedConfigs = array_merge($this->globalConfigs, $this->configs);
374 117
        if (count($combinedConfigs)) {
375 4
            foreach ($combinedConfigs as $config => $value) {
376 4
                $command .= sprintf(
377 4
                    ' %s %s=%s',
378 4
                    escapeshellarg('-c'),
379 4
                    escapeshellarg($config),
380 4
                    escapeshellarg($value)
381
                );
382
            }
383
        }
384 117
        return $command;
385
    }
386
387
    /**
388
     * get a string of CLI-formatted global options
389
     *
390
     * @return string The global options string
391
     */
392 117
    private function getCLIGlobalOptions()
393
    {
394 117
        $command = '';
395 117
        if (count($this->globalOptions) > 0) {
396 1
            foreach ($this->globalOptions as $name => $value) {
397 1
                $command .= sprintf(' %s=%s', escapeshellarg($name), escapeshellarg($value));
398
            }
399
        }
400 117
        return $command;
401
    }
402
403
    /**
404
     * get a string of CLI-formatted path
405
     *
406
     * @return string The path string
407
     */
408 117
    private function getCLIPath()
409
    {
410 117
        $command = '';
411 117
        if (!is_null($this->path)) {
412 17
            $command .= sprintf(' -- %s', escapeshellarg($this->path));
413
        }
414 117
        return $command;
415
    }
416
417
    /**
418
     * get a string of CLI-formatted subjects
419
     *
420
     * @throws \RuntimeException
421
     * @return string The subjects string
422
     */
423 117
    private function getCLISubjects()
424
    {
425 117
        $command = '';
426 117
        if (!is_null($this->commandSubject)) {
427 106
            $command .= ' ';
428 106
            if ($this->commandSubject instanceof SubCommandCommand) {
429 10
                $command .= $this->commandSubject->getCommand();
430
            } else {
431 105
                if (is_array($this->commandSubject)) {
432 1
                    $command .= implode(' ', array_map('escapeshellarg', $this->commandSubject));
433
                } else {
434 104
                    $command .= escapeshellarg($this->commandSubject);
435
                }
436
            }
437
        }
438 117
        if (!is_null($this->commandSubject2)) {
439 23
            $command .= ' ';
440 23
            if ($this->commandSubject2 instanceof SubCommandCommand) {
441
                $command .= $this->commandSubject2->getCommand();
442
            } else {
443 23
                if (is_array($this->commandSubject2)) {
444
                    $command .= implode(' ', array_map('escapeshellarg', $this->commandSubject2));
445
                } else {
446 23
                    $command .= escapeshellarg($this->commandSubject2);
447
                }
448
            }
449
        }
450 117
        return $command;
451
    }
452
453
    /**
454
     * @return string|null
455
     */
456 4
    public function getBinaryVersion()
457
    {
458 4
        if (is_null($this->binaryVersion)) {
459 4
            $this->binaryVersion = $this->repo->getCaller()->getBinaryVersion();
460
        }
461 4
        return $this->binaryVersion;
462
    }
463
}
464