Completed
Push — master ( ac786e...a9b395 )
by Sebastian
09:39
created

Cli::formatWithAsterisk()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
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 paths
21
     *
22
     * @var array
23
     */
24
    private static $basePaths = [];
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/mysqldump', // Mac OS X
52 2
            '/usr/mysql/bin/mysqldump',       // Linux
53 2
        ],
54
        'tar'       => [],
55
    ];
56
57
    /**
58
     * Register a base path.
59
     *
60
     * @param  string $name
61
     * @param  string $path
62 1
     * @throws \RuntimeException
63
     */
64 1
    public static function registerBase($name, $path)
65 1
    {
66
        if (!self::isAbsolutePath($path)) {
67
            throw new RuntimeException(sprintf('path has to be absolute: %s', $path));
68
        }
69
        self::$basePaths[$name] = $path;
70
    }
71
72
73 125
    /**
74
     * Adds a new 'path' to the list of optional command locations.
75 125
     *
76
     * @param string $command
77
     * @param string $path
78
     */
79
    public static function addCommandLocation($command, $path)
80
    {
81
        self::$optionalCommandLocations[$command][] = $path;
82
    }
83
84
    /**
85 3
     * Returns the list of optional 'mysqldump' locations.
86
     *
87 3
     * @param  string $command
88 1
     * @return array
89
     */
90 2
    public static function getCommandLocations($command)
91
    {
92
        return isset(self::$optionalCommandLocations[$command]) ? self::$optionalCommandLocations[$command] : [];
93
    }
94
95
    /**
96
     * Retrieve a registered path.
97
     *
98
     * @param  string $name
99
     * @return string array
100
     * @throws \RuntimeException
101
     */
102 128
    public static function getBase($name)
103
    {
104
        if (!isset(self::$basePaths[$name])) {
105 128
            throw new RuntimeException(sprintf('base not registered: %s', $name));
106 120
        }
107 120
        return self::$basePaths[$name];
108 120
    }
109 1
110
    /**
111 119
     * Detect a given commands location.
112
     *
113
     * @param  string $cmd               The command to be located
114
     * @param  string $path              Directory where the command should be located
115 8
     * @param  array  $optionalLocations Some fallback locations where to investigate
116 8
     * @return string                    Absolute path to detected command including command itself
117 8
     * @throws \RuntimeException
118 8
     */
119
    public static function detectCmdLocation($cmd, $path = null, $optionalLocations = [])
120
    {
121 8
        // explicit path given, so check it out
122
        if (null !== $path) {
123
            $command = $path . DIRECTORY_SEPARATOR . $cmd;
124 8
            $bin     = self::isExecutable($command);
125 8
            if (null === $bin) {
126 8
                throw new RuntimeException(sprintf('wrong path specified for \'%s\': %s', $cmd, $path));
127 8
            }
128 8
            return $bin;
129 6
        }
130
131 8
        // on nx systems use 'which' command.
132
        if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
133
            $command = `which $cmd`;
134 2
            $bin     = self::isExecutable($command);
135 1
            if (null !== $bin) {
136 1
                return $bin;
137 1
            }
138 1
        }
139
140 1
        // checking environment variable.
141 1
        $pathList = explode(PATH_SEPARATOR, self::getEnvPath());
142 View Code Duplication
        foreach ($pathList as $path) {
143
            $command = $path . DIRECTORY_SEPARATOR . $cmd;
144
            $bin     = self::isExecutable($command);
145
            if (null !== $bin) {
146
                return $bin;
147
            }
148
        }
149
150 9
        // some more paths we came across that where added manually
151 View Code Duplication
        foreach ($optionalLocations as $path) {
152
            $command = $path . DIRECTORY_SEPARATOR . $cmd;
153 9
            $bin     = self::isExecutable($command);
154 9
            if (null !== $bin) {
155 8
                return $bin;
156
            }
157 1
        }
158 1
        throw new RuntimeException(sprintf('\'%s\' was nowhere to be found please specify the correct path', $cmd));
159
    }
160
161
    /**
162
     * Return local $PATH variable.
163
     *
164
     * @return string
165
     * @throws \RuntimeException
166
     */
167
    public static function getEnvPath()
168 128
    {
169
        // check for unix and windows case $_SERVER index
170 128
        foreach (['PATH', 'Path', 'path'] as $index) {
171 126
            if (isset($_SERVER[$index])) {
172
                return $_SERVER[$index];
173
            }
174 9
        }
175
        throw new RuntimeException('cant find local PATH variable');
176
    }
177
178
    /**
179
     * Returns the executable command if the command is executable, null otherwise.
180 9
     * Search for $command.exe on Windows systems.
181
     *
182
     * @param  string $command
183
     * @return string
184
     */
185
    public static function isExecutable($command)
186
    {
187
        if (is_executable($command)) {
188
            return $command;
189 21
        }
190
        // on windows check the .exe suffix
191
        if (defined('PHP_WINDOWS_VERSION_BUILD')) {
192 21
            $command .= '.exe';
193 4
            if (is_executable($command)) {
194
                return $command;
195
            }
196
        }
197
        return null;
198
    }
199
200
    /**
201
     * Is given path absolute.
202
     *
203
     * @param  string $path
204 17
     * @return boolean
205
     */
206
    public static function isAbsolutePath($path)
207
    {
208
        // path already absolute?
209 17
        if ($path[0] === '/') {
210 1
            return true;
211
        }
212
213 16
        // Matches the following on Windows:
214
        //  - \\NetworkComputer\Path
215
        //  - \\.\D:
216
        //  - \\.\c:
217
        //  - C:\Windows
218
        //  - C:\windows
219
        //  - C:/windows
220
        //  - c:/windows
221
        if (defined('PHP_WINDOWS_VERSION_BUILD') && self::isAbsoluteWindowsPath($path)) {
222 3
            return true;
223
        }
224 3
225
        // Stream
226
        if (strpos($path, '://') !== false) {
227
            return true;
228
        }
229
230
        return false;
231
    }
232
233
    /**
234
     * Is given path an absolute windows path.
235 17
     *
236
     * @param  string $path
237 17
     * @return bool
238 3
     */
239
    public static function isAbsoluteWindowsPath($path)
240
    {
241 14
        return ($path[0] === '\\' || (strlen($path) >= 3 && preg_match('#^[A-Z]\:[/\\\]#i', substr($path, 0, 3))));
242
    }
243 14
244 1
    /**
245 1
     * Converts a path to an absolute one if necessary relative to a given base path.
246 1
     *
247 1
     * @param  string  $path
248 1
     * @param  string  $base
249 14
     * @param  boolean $useIncludePath
250
     * @return string
251
     */
252
    public static function toAbsolutePath($path, $base, $useIncludePath = false)
253
    {
254
        if (self::isAbsolutePath($path)) {
255
            return $path;
256
        }
257 1
258
        $file = $base . DIRECTORY_SEPARATOR . $path;
259 1
260 1
        if ($useIncludePath && !file_exists($file)) {
261 1
            $includePathFile = stream_resolve_include_path($path);
262
            if ($includePathFile) {
263 1
                $file = $includePathFile;
264 1
            }
265 1
        }
266 1
        return $file;
267
    }
268 1
269 1
    /**
270 1
     * Formats a buffer with a specified ANSI color sequence if colors are enabled.
271
     *
272
     * @author Sebastian Bergmann <[email protected]>
273
     * @param  string $color
274
     * @param  string $buffer
275
     * @return string
276
     */
277
    public static function formatWithColor($color, $buffer)
278
    {
279
        $codes   = array_map('trim', explode(',', $color));
280
        $lines   = explode("\n", $buffer);
281
        $padding = max(array_map('strlen', $lines));
282
283
        $styles = [];
284
        foreach ($codes as $code) {
285
            $styles[] = self::$ansiCodes[$code];
286
        }
287
        $style = sprintf("\x1b[%sm", implode(';', $styles));
288
289
        $styledLines = [];
290
        foreach ($lines as $line) {
291
            $styledLines[] = strlen($line) ? $style . str_pad($line, $padding) . "\x1b[0m" : '';
292
        }
293
294
        return implode(PHP_EOL, $styledLines);
295
    }
296
297
    /**
298
     * Fills up a text buffer with '*' to consume 72 chars.
299
     *
300
     * @param  string $buffer
301
     * @param  int    $length
302
     * @return string
303
     */
304
    public static function formatWithAsterisk($buffer, $length = 75)
305
    {
306
        return $buffer . str_repeat('*', $length - strlen($buffer)) . PHP_EOL;
307
    }
308
309
    /**
310
     * Removes a directory that is not empty.
311
     *
312
     * @param $dir
313
     */
314
    public static function removeDir($dir)
315
    {
316
        foreach (scandir($dir) as $file) {
317
            if ('.' === $file || '..' === $file) {
318
                continue;
319
            }
320
            if (is_dir($dir . '/' . $file)) {
321
                self::removeDir($dir . '/' . $file);
322
            } else {
323
                unlink($dir . '/' . $file);
324
            }
325
        }
326
        rmdir($dir);
327
    }
328
}
329