Completed
Push — master ( 0c38e0...116503 )
by Sebastian
03:25
created

Cli::getBase()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
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 paths
21
     *
22
     * @var array
23
     */
24
    private static $basePaths = [];
0 ignored issues
show
Unused Code introduced by
The property $basePaths is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
25
26
    /**
27
     * List of console color codes.
28
     *
29
     * @var array
30
     */
31
    private static $ansiCodes = [
32
        'bold'       => 1,
33
        'fg-black'   => 30,
34
        'fg-red'     => 31,
35
        'fg-yellow'  => 33,
36
        'fg-cyan'    => 36,
37
        'fg-white'   => 37,
38
        'bg-red'     => 41,
39
        'bg-green'   => 42,
40
        'bg-yellow'  => 43
41
    ];
42
43
    /**
44
     * Optional command locations
45
     *
46
     * @var array
47 3
     */
48
    private static $optionalCommandLocations = [
49 3
        'mongodump' => [],
50 1
        'mysqldump' => [
51
            '/usr/local/mysql/bin', // Mac OS X
52 2
            '/usr/mysql/bin',       // Linux
53 2
        ],
54
        'tar'       => [],
55
    ];
56
57
    /**
58
     * Adds a new 'path' to the list of optional command locations.
59
     *
60
     * @param string $command
61
     * @param string $path
62 1
     */
63
    public static function addCommandLocation($command, $path)
64 1
    {
65 1
        self::$optionalCommandLocations[$command][] = $path;
66
    }
67
68
    /**
69
     * Returns the list of optional 'mysqldump' locations.
70
     *
71
     * @param  string $command
72
     * @return array
73 125
     */
74
    public static function getCommandLocations($command)
75 125
    {
76
        return isset(self::$optionalCommandLocations[$command]) ? self::$optionalCommandLocations[$command] : [];
77
    }
78
79
    /**
80
     * Detect a given command's location.
81
     *
82
     * @param  string $cmd               The command to locate
83
     * @param  string $path              Directory where the command should be
84
     * @param  array  $optionalLocations Some fallback locations where to search for the command
85 3
     * @return string                    Absolute path to detected command including command itself
86
     * @throws \RuntimeException
87 3
     */
88 1
    public static function detectCmdLocation($cmd, $path = null, $optionalLocations = [])
89
    {
90 2
        $detectionSteps = [
91
            function($cmd) use ($path) {
92
                if (null !== $path) {
93
                    return self::detectCmdLocationInPath($cmd, $path);
94
                }
95
                return null;
96
            },
97
            function($cmd) {
98
                return self::detectCmdLocationWithWhich($cmd);
99
            },
100
            function($cmd) {
101
                $paths = explode(PATH_SEPARATOR, self::getEnvPath());
102 128
                return self::detectCmdLocationInPaths($cmd, $paths);
103
            },
104
            function($cmd) use ($optionalLocations) {
105 128
                return self::detectCmdLocationInPaths($cmd, $optionalLocations);
106 120
            }
107 120
        ];
108 120
109 1
        foreach ($detectionSteps as $step) {
110
            $bin = $step($cmd);
111 119
            if (null !== $bin) {
112
                return $bin;
113
            }
114
        }
115 8
116 8
        throw new RuntimeException(sprintf('\'%s\' was nowhere to be found please specify the correct path', $cmd));
117 8
    }
118 8
119
    /**
120
     * Detect a command in a given path.
121 8
     *
122
     * @param  string $cmd
123
     * @param  string $path
124 8
     * @return string
125 8
     */
126 8
    public static function detectCmdLocationInPath($cmd, $path)
127 8
    {
128 8
        $command = $path . DIRECTORY_SEPARATOR . $cmd;
129 6
        $bin     = self::isExecutable($command);
130
        if (null === $bin) {
131 8
            throw new RuntimeException(sprintf('wrong path specified for \'%s\': %s', $cmd, $path));
132
        }
133
        return $bin;
134 2
    }
135 1
136 1
    /**
137 1
     * Detect command location using which cli command.
138 1
     *
139
     * @param  string $cmd
140 1
     * @return null|string
141 1
     */
142
    public static function detectCmdLocationWithWhich($cmd)
143
    {
144
        $bin = null;
145
        // on nx systems use 'which' command.
146
        if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
147
            $command = `which $cmd`;
148
            $bin     = self::isExecutable($command);
149
        }
150 9
        return $bin;
151
152
    }
153 9
154 9
    /**
155 8
     * Check path list for executable command.
156
     *
157 1
     * @param string $cmd
158 1
     * @param array  $paths
159
     * @return null|string
160
     */
161
    public static function detectCmdLocationInPaths($cmd, array $paths)
162
    {
163
        foreach ($paths as $path) {
164
            $command = $path . DIRECTORY_SEPARATOR . $cmd;
165
            $bin     = self::isExecutable($command);
166
            if (null !== $bin) {
167
                return $bin;
168 128
            }
169
        }
170 128
        return null;
171 126
    }
172
173
    /**
174 9
     * Return local $PATH variable.
175
     *
176
     * @return string
177
     * @throws \RuntimeException
178
     */
179
    public static function getEnvPath()
180 9
    {
181
        // check for unix and windows case $_SERVER index
182
        foreach (['PATH', 'Path', 'path'] as $index) {
183
            if (isset($_SERVER[$index])) {
184
                return $_SERVER[$index];
185
            }
186
        }
187
        throw new RuntimeException('cant find local PATH variable');
188
    }
189 21
190
    /**
191
     * Returns the executable command if the command is executable, null otherwise.
192 21
     * Search for $command.exe on Windows systems.
193 4
     *
194
     * @param  string $command
195
     * @return string
196
     */
197
    public static function isExecutable($command)
198
    {
199
        if (is_executable($command)) {
200
            return $command;
201
        }
202
        // on windows check the .exe suffix
203
        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
204 17
            $command .= '.exe';
205
            if (is_executable($command)) {
206
                return $command;
207
            }
208
        }
209 17
        return null;
210 1
    }
211
212
    /**
213 16
     * Is given path absolute.
214
     *
215
     * @param  string $path
216
     * @return boolean
217
     */
218
    public static function isAbsolutePath($path)
219
    {
220
        // path already absolute?
221
        if ($path[0] === '/') {
222 3
            return true;
223
        }
224 3
225
        // Matches the following on Windows:
226
        //  - \\NetworkComputer\Path
227
        //  - \\.\D:
228
        //  - \\.\c:
229
        //  - C:\Windows
230
        //  - C:\windows
231
        //  - C:/windows
232
        //  - c:/windows
233
        if (defined('PHP_WINDOWS_VERSION_BUILD') && self::isAbsoluteWindowsPath($path)) {
234
            return true;
235 17
        }
236
237 17
        // Stream
238 3
        if (strpos($path, '://') !== false) {
239
            return true;
240
        }
241 14
242
        return false;
243 14
    }
244 1
245 1
    /**
246 1
     * Is given path an absolute windows path.
247 1
     *
248 1
     * @param  string $path
249 14
     * @return bool
250
     */
251
    public static function isAbsoluteWindowsPath($path)
252
    {
253
        return ($path[0] === '\\' || (strlen($path) >= 3 && preg_match('#^[A-Z]\:[/\\\]#i', substr($path, 0, 3))));
254
    }
255
256
    /**
257 1
     * Converts a path to an absolute one if necessary relative to a given base path.
258
     *
259 1
     * @param  string  $path
260 1
     * @param  string  $base
261 1
     * @param  boolean $useIncludePath
262
     * @return string
263 1
     */
264 1
    public static function toAbsolutePath($path, $base, $useIncludePath = false)
265 1
    {
266 1
        if (self::isAbsolutePath($path)) {
267
            return $path;
268 1
        }
269 1
270 1
        $file = $base . DIRECTORY_SEPARATOR . $path;
271
272
        if ($useIncludePath && !file_exists($file)) {
273
            $includePathFile = stream_resolve_include_path($path);
274
            if ($includePathFile) {
275
                $file = $includePathFile;
276
            }
277
        }
278
        return $file;
279
    }
280
281
    /**
282
     * Formats a buffer with a specified ANSI color sequence if colors are enabled.
283
     *
284
     * @author Sebastian Bergmann <[email protected]>
285
     * @param  string $color
286
     * @param  string $buffer
287
     * @return string
288
     */
289
    public static function formatWithColor($color, $buffer)
290
    {
291
        $codes   = array_map('trim', explode(',', $color));
292
        $lines   = explode("\n", $buffer);
293
        $padding = max(array_map('strlen', $lines));
294
295
        $styles = [];
296
        foreach ($codes as $code) {
297
            $styles[] = self::$ansiCodes[$code];
298
        }
299
        $style = sprintf("\x1b[%sm", implode(';', $styles));
300
301
        $styledLines = [];
302
        foreach ($lines as $line) {
303
            $styledLines[] = strlen($line) ? $style . str_pad($line, $padding) . "\x1b[0m" : '';
304
        }
305
306
        return implode(PHP_EOL, $styledLines);
307
    }
308
309
    /**
310
     * Fills up a text buffer with '*' to consume 72 chars.
311
     *
312
     * @param  string $buffer
313
     * @param  int    $length
314
     * @return string
315
     */
316
    public static function formatWithAsterisk($buffer, $length = 75)
317
    {
318
        return $buffer . str_repeat('*', $length - strlen($buffer)) . PHP_EOL;
319
    }
320
321
    /**
322
     * Can command pipe operator be used.
323
     *
324
     * @return bool
325
     */
326
    public static function canPipe()
327
    {
328
        return !defined('PHP_WINDOWS_VERSION_BUILD');
329
    }
330
331
    /**
332
     * Removes a directory that is not empty.
333
     *
334
     * @param $dir
335
     */
336
    public static function removeDir($dir)
337
    {
338
        foreach (scandir($dir) as $file) {
339
            if ('.' === $file || '..' === $file) {
340
                continue;
341
            }
342
            if (is_dir($dir . '/' . $file)) {
343
                self::removeDir($dir . '/' . $file);
344
            } else {
345
                unlink($dir . '/' . $file);
346
            }
347
        }
348
        rmdir($dir);
349
    }
350
}
351