Caller   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 97.62%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 2
dl 0
loc 130
ccs 41
cts 42
cp 0.9762
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 3
B execute() 0 43 7
A getOutput() 0 4 1
A getOutputLines() 0 15 4
A getRawOutput() 0 4 1
1
<?php
2
3
/**
4
 * GitElephant - An abstraction layer for git written in PHP
5
 * Copyright (C) 2013  Matteo Giachino
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see [http://www.gnu.org/licenses/].
19
 */
20
21
namespace GitElephant\Command\Caller;
22
23
use GitElephant\Exception\InvalidRepositoryPathException;
24
use Symfony\Component\Process\Process;
25
26
/**
27
 * Caller
28
 *
29
 * @author Matteo Giachino <[email protected]>
30
 * @author Tim Bernhard <[email protected]>
31
 */
32
class Caller extends AbstractCaller
33
{
34
    /**
35
     * the repository path
36
     *
37
     * @var string
38
     */
39
    private $repositoryPath;
40
41
    /**
42
     * Class constructor
43
     *
44
     * @param string|null   $gitPath the physical path to the git binary
45
     * @param string        $repositoryPath the physical base path for the repository
46
     */
47 108
    public function __construct($gitPath, $repositoryPath)
48
    {
49 108
        if (is_null($gitPath)) {
50
            // unix only!
51 108
            $gitPath = exec('which git');
52
        }
53 108
        $this->setBinaryPath($gitPath);
54 108
        if (!is_dir($repositoryPath)) {
55 1
            throw new InvalidRepositoryPathException($repositoryPath);
56
        }
57 108
        $this->repositoryPath = $repositoryPath;
58 108
    }
59
60
    /**
61
     * Executes a command
62
     *
63
     * @param string $cmd               the command to execute
64
     * @param bool   $git               if the command is git or a generic command
65
     * @param string $cwd               the directory where the command must be executed
66
     * @param array  $acceptedExitCodes exit codes accepted to consider the command execution successful
67
     *
68
     * @throws \RuntimeException
69
     * @throws \Symfony\Component\Process\Exception\InvalidArgumentException
70
     * @throws \Symfony\Component\Process\Exception\ProcessTimedOutException
71
     * @throws \Symfony\Component\Process\Exception\RuntimeException
72
     * @throws \Symfony\Component\Process\Exception\LogicException
73
     * @return Caller
74
     */
75 103
    public function execute(
76
        string $cmd,
77
        bool $git = true,
78
        string $cwd = null,
79
        array $acceptedExitCodes = [0]
80
    ): CallerInterface {
81 103
        if ($git) {
82 103
            $cmd = $this->getBinaryPath() . ' ' . $cmd;
83
        }
84
85 103
        if (stripos(PHP_OS, 'WIN') !== 0) {
86
            // We rely on the C locale in all output we parse.
87 103
            $cmd = 'LC_ALL=C ' . $cmd;
88
        }
89
90 103
        if (is_null($cwd) || !is_dir($cwd)) {
91 103
            $cwd = $this->repositoryPath;
92
        }
93
94 103
        if (method_exists(Process::class, 'fromShellCommandline')) {
95 103
            $process = Process::fromShellCommandline($cmd, $cwd);
96
        } else {
97
            // compatibility fix required for symfony/process versions prior to v4.2.
98
            $process = new Process($cmd, $cwd);
99
        }
100
101 103
        $process->setTimeout(15000);
102 103
        $process->run();
103 103
        if (!in_array($process->getExitCode(), $acceptedExitCodes)) {
104 1
            $text = 'Exit code: ' . $process->getExitCode();
105 1
            $text .= ' while executing: "' . $cmd;
106 1
            $text .= '" with reason: ' . $process->getErrorOutput();
107 1
            $text .= "\n" . $process->getOutput();
108 1
            throw new \RuntimeException($text);
109
        }
110
        
111 102
        $this->rawOutput = $process->getOutput();
112
        // rtrim values
113 102
        $values = array_map('rtrim', explode(PHP_EOL, $process->getOutput()));
114 102
        $this->outputLines = $values;
115
116 102
        return $this;
117
    }
118
119
    /**
120
     * returns the output of the last executed command
121
     *
122
     * @return string
123
     */
124 7
    public function getOutput(): string
125
    {
126 7
        return implode("\n", $this->outputLines);
127
    }
128
129
    /**
130
     * returns the output of the last executed command as an array of lines
131
     *
132
     * @param bool $stripBlankLines remove the blank lines
133
     *
134
     * @return array
135
     */
136 92
    public function getOutputLines(bool $stripBlankLines = false): array
137
    {
138 92
        if ($stripBlankLines) {
139 82
            $output = [];
140 82
            foreach ($this->outputLines as $line) {
141 82
                if ('' !== $line) {
142 82
                    $output[] = $line;
143
                }
144
            }
145
146 82
            return $output;
147
        }
148
149 45
        return $this->outputLines;
150
    }
151
152
    /**
153
     * Get RawOutput
154
     *
155
     * @return string
156
     */
157 1
    public function getRawOutput(): string
158
    {
159 1
        return $this->rawOutput;
160
    }
161
}
162