Completed
Push — master ( 236d2e...a95984 )
by Sebastian
03:12
created

Cli::detectCmdLocationInPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
ccs 6
cts 6
cp 1
cc 2
eloc 6
nc 2
nop 2
crap 2
1
<?php
2
namespace phpbu\App\Util;
3
4
use RuntimeException;
5
6
/**
7
 * Cli utility
8
 *
9
 * @package    phpbu
10
 * @subpackage Util
11
 * @author     Sebastian Feldmann <[email protected]>
12
 * @copyright  Sebastian Feldmann <[email protected]>
13
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
14
 * @link       http://phpbu.de/
15
 * @since      Class available since Release 1.0.0
16
 */
17
abstract class Cli
18
{
19
    /**
20
     * List of console color codes.
21
     *
22
     * @var array
23
     */
24
    private static $ansiCodes = [
25
        'bold'       => 1,
26
        'fg-black'   => 30,
27
        'fg-red'     => 31,
28
        'fg-green'   => 32,
29
        'fg-yellow'  => 33,
30
        'fg-cyan'    => 36,
31
        'fg-white'   => 37,
32
        'bg-red'     => 41,
33
        'bg-green'   => 42,
34
        'bg-yellow'  => 43
35
    ];
36
37
    /**
38
     * Optional command locations
39
     *
40
     * @var array
41
     */
42
    private static $optionalCommandLocations = [
43
        'mongodump' => [],
44
        'mysqldump' => [
45
            '/usr/local/mysql/bin', // Mac OS X
46
            '/usr/mysql/bin',       // Linux
47
        ],
48
        'tar'       => [],
49
    ];
50
51
    /**
52
     * Adds a new 'path' to the list of optional command locations.
53
     *
54
     * @param string $command
55
     * @param string $path
56
     */
57 1
    public static function addCommandLocation($command, $path)
58
    {
59 1
        self::$optionalCommandLocations[$command][] = $path;
60 1
    }
61
62
    /**
63
     * Returns the list of optional 'mysqldump' locations.
64
     *
65
     * @param  string $command
66
     * @return array
67
     */
68 216
    public static function getCommandLocations($command) : array
69
    {
70 216
        return isset(self::$optionalCommandLocations[$command]) ? self::$optionalCommandLocations[$command] : [];
71
    }
72
73
    /**
74
     * Detect a given command's location.
75
     *
76
     * @param  string $cmd               The command to locate
77
     * @param  string $path              Directory where the command should be
78
     * @param  array  $optionalLocations Some fallback locations where to search for the command
79
     * @return string                    Absolute path to detected command including command itself
80
     * @throws \RuntimeException
81
     */
82
    public static function detectCmdLocation(string $cmd, string $path = '', array $optionalLocations = []) : string
83
    {
84
        $detectionSteps = [
85 219
            function($cmd) use ($path) {
86 219
                if (!empty($path)) {
87 213
                    return self::detectCmdLocationInPath($cmd, $path);
88
                }
89 6
                return '';
90 219
            },
91 219
            function($cmd) {
92 6
                return self::detectCmdLocationWithWhich($cmd);
93 219
            },
94 219
            function($cmd) {
95 2
                $paths = explode(PATH_SEPARATOR, self::getEnvPath());
96 2
                return self::detectCmdLocationInPaths($cmd, $paths);
97 219
            },
98 219
            function($cmd) use ($optionalLocations) {
99 2
                return self::detectCmdLocationInPaths($cmd, $optionalLocations);
100 219
            }
101
        ];
102
103 219
        foreach ($detectionSteps as $step) {
104 219
            $bin = $step($cmd);
105 218
            if (!empty($bin)) {
106 218
                return $bin;
107
            }
108
        }
109
110 1
        throw new RuntimeException(sprintf('\'%s\' was nowhere to be found please specify the correct path', $cmd));
111
    }
112
113
    /**
114
     * Detect a command in a given path.
115
     *
116
     * @param  string $cmd
117
     * @param  string $path
118
     * @return string
119
     * @throws \RuntimeException
120
     */
121 213
    public static function detectCmdLocationInPath(string $cmd, string $path) : string
122
    {
123 213
        $command = $path . DIRECTORY_SEPARATOR . $cmd;
124 213
        $bin     = self::isExecutable($command);
125 213
        if (empty($bin)) {
126 1
            throw new RuntimeException(sprintf('wrong path specified for \'%s\': %s', $cmd, $path));
127
        }
128 212
        return $bin;
129
    }
130
131
    /**
132
     * Detect command location using which cli command.
133
     *
134
     * @param  string $cmd
135
     * @return string
136
     */
137 6
    public static function detectCmdLocationWithWhich($cmd) : string
138
    {
139 6
        $bin = '';
140
        // on nx systems use 'which' command.
141 6
        if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
142 6
            $command = trim(`which $cmd`);
143 6
            $bin     = self::isExecutable($command);
144
        }
145 6
        return $bin;
146
147
    }
148
149
    /**
150
     * Check path list for executable command.
151
     *
152
     * @param  string $cmd
153
     * @param  array  $paths
154
     * @return string
155
     */
156 2
    public static function detectCmdLocationInPaths($cmd, array $paths) : string
157
    {
158 2
        foreach ($paths as $path) {
159 2
            $command = $path . DIRECTORY_SEPARATOR . $cmd;
160 2
            $bin     = self::isExecutable($command);
161 2
            if (!empty($bin)) {
162 2
                return $bin;
163
            }
164
        }
165 2
        return '';
166
    }
167
168
    /**
169
     * Return local $PATH variable.
170
     *
171
     * @return string
172
     * @throws \RuntimeException
173
     */
174 3
    public static function getEnvPath() : string
175
    {
176
        // check for unix and windows case $_SERVER index
177 3
        foreach (['PATH', 'Path', 'path'] as $index) {
178 3
            if (isset($_SERVER[$index])) {
179 3
                return $_SERVER[$index];
180
            }
181
        }
182 1
        throw new RuntimeException('cant find local PATH variable');
183
    }
184
185
    /**
186
     * Returns the executable command if the command is executable, null otherwise.
187
     * Search for $command.exe on Windows systems.
188
     *
189
     * @param  string $command
190
     * @return string
191
     */
192 219
    public static function isExecutable($command) : string
193
    {
194 219
        if (is_executable($command)) {
195 217
            return $command;
196
        }
197
        // on windows check the .exe suffix
198 3
        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
199
            $command .= '.exe';
200
            if (is_executable($command)) {
201
                return $command;
202
            }
203
        }
204 3
        return '';
205
    }
206
207
    /**
208
     * Formats a buffer with a specified ANSI color sequence if colors are enabled.
209
     *
210
     * @author Sebastian Bergmann <[email protected]>
211
     * @param  string $color
212
     * @param  string $buffer
213
     * @return string
214
     */
215 3
    public static function formatWithColor(string $color, string $buffer) : string
216
    {
217 3
        $codes   = array_map('trim', explode(',', $color));
218 3
        $lines   = explode("\n", $buffer);
219 3
        $padding = max(array_map('strlen', $lines));
220
221 3
        $styles = [];
222 3
        foreach ($codes as $code) {
223 3
            $styles[] = self::$ansiCodes[$code];
224
        }
225 3
        $style = sprintf("\x1b[%sm", implode(';', $styles));
226
227 3
        $styledLines = [];
228 3
        foreach ($lines as $line) {
229 3
            $styledLines[] = strlen($line) ? $style . str_pad($line, $padding) . "\x1b[0m" : '';
230
        }
231
232 3
        return implode(PHP_EOL, $styledLines);
233
    }
234
235
    /**
236
     * Fills up a text buffer with '*' to consume 72 chars.
237
     *
238
     * @param  string $buffer
239
     * @param  int    $length
240
     * @return string
241
     */
242 14
    public static function formatWithAsterisk(string $buffer, int $length = 75) : string
243
    {
244 14
        return $buffer . str_repeat('*', $length - strlen($buffer)) . PHP_EOL;
245
    }
246
247
    /**
248
     * Can command pipe operator be used.
249
     *
250
     * @return bool
251
     */
252 3
    public static function canPipe() : bool
253
    {
254 3
        return !defined('PHP_WINDOWS_VERSION_BUILD');
255
    }
256
257
    /**
258
     * Removes a directory that is not empty.
259
     *
260
     * @param string $dir
261
     */
262 1
    public static function removeDir(string $dir)
263
    {
264 1
        foreach (scandir($dir) as $file) {
265 1
            if ('.' === $file || '..' === $file) {
266 1
                continue;
267
            }
268 1
            if (is_dir($dir . '/' . $file)) {
269 1
                self::removeDir($dir . '/' . $file);
270
            } else {
271 1
                unlink($dir . '/' . $file);
272
            }
273
        }
274 1
        rmdir($dir);
275 1
    }
276
}
277