Passed
Push — master ( d5c1f5...3b22a1 )
by Tom
05:09 queued 02:51
created

Lib::fsFileLookUp()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 10
nc 6
nop 2
dl 0
loc 18
ccs 10
cts 10
cp 1
crap 6
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines;
6
7
8
class Lib
9
{
10
    /**
11
     * @return string UUID version 4
12
     */
13 1
    public static function generateUuid()
14
    {
15 1
        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
16
17
            // 32 bits for "time_low"
18 1
            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
19
20
            // 16 bits for "time_mid"
21 1
            mt_rand(0, 0xffff),
22
23
            // 16 bits for "time_hi_and_version",
24
            // four most significant bits holds version number 4
25 1
            mt_rand(0, 0x0fff) | 0x4000,
26
27
            // 16 bits, 8 bits for "clk_seq_hi_res",
28
            // 8 bits for "clk_seq_low",
29
            // two most significant bits holds zero and one for variant DCE1.1
30 1
            mt_rand(0, 0x3fff) | 0x8000,
31
32
            // 48 bits for "node"
33 1
            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
34
        );
35
    }
36
37 2
    public static function cmd($command, array $arguments)
38
    {
39 2
        $buffer = $command;
40
41 2
        $arguments = call_user_func_array('self::merge', $arguments);
42
43 2
        foreach ($arguments as $argument) {
44 2
            $buffer .= ' ' . self::quoteArg($argument);
45
        }
46
47 2
        return $buffer;
48
    }
49
50
    /**
51
     * quote an argument to preserve its value verbatim when used as
52
     * a utility argument in shell
53
     *
54
     * @param string $argument
55
     * @return string
56
     */
57 8
    public static function quoteArg($argument)
58
    {
59 8
        $parts = explode("'", $argument);
60
61 8
        $buffer = '';
62 8
        foreach ($parts as $index => $part) {
63 8
            $index && $buffer .= "\\'";
64 8
            $safe = preg_match('~^[a-zA-Z0-9,._+@%/-]*$~', $part);
65 8
            $buffer .= $safe ? $part : "'$part'";
66
        }
67
68 8
        if ($buffer === "") {
0 ignored issues
show
introduced by
The condition $buffer === '' can never be false.
Loading history...
69 1
            $buffer = "''";
70
        }
71
72 8
        return $buffer;
73
    }
74
75
    /**
76
     * Turn multi-line string into an array of lines.
77
     *
78
     * Handles no newline at the end of buffer
79
     *
80
     * @param string $buffer
81
     * @return array
82
     */
83 1
    public static function lines($buffer)
84
    {
85 1
        $lines = explode("\n", $buffer);
86 1
        if ($c = count($lines) and '' === $lines[$c - 1]) {
87 1
            array_pop($lines);
88
        }
89
90 1
        return $lines;
91
    }
92
93
    /**
94
     * merge n parameters, if a scalar, turned into array, otherwise must be an array
95
     */
96 4
    public static function merge()
97
    {
98 4
        if (!$arrays = func_get_args()) {
99 1
            return $arrays;
100
        }
101
102 3
        foreach ($arrays as $key => $value) {
103 3
            if (!is_array($value)) {
104 3
                $arrays[$key] = (array)$value;
105
            }
106
        }
107
108 3
        return call_user_func_array('array_merge', $arrays);
109
    }
110
111
    /**
112
     * expand brace "{}" in pattern
113
     *
114
     * @param string $pattern
115
     * @return array of all patterns w/o braces, no duplicates
116
     */
117 17
    public static function expandBrace($pattern)
118
    {
119 17
        $stack = array($pattern);
120
121 17
        for ($i = 0; isset($stack[$i]); $i++) {
122 17
            $subject = $stack[$i];
123 17
            $result = self::expandBraceInnerMatch($subject, $matches);
124 17
            if (0 === $result) {
125 17
                continue;
126
            }
127
            // match
128 9
            $segments = preg_split('~\\\\.(*SKIP)(*FAIL)|,~', $matches[2]);
129 9
            $segments = array_unique(/** @scrutinizer ignore-type */ $segments);
130 9
            foreach ($segments as $segment) {
131 9
                $permutation = $matches[1] . $segment . $matches[3];
132 9
                in_array($permutation, $stack, true) || $stack[] = $permutation;
133
            }
134 9
            unset($stack[$i]);
135
        }
136
137
        // inline escaped brace characters
138 17
        $stack = array_map(function ($str) {
139 17
            return strtr($str, array(
140 17
                '\\\\' => '\\\\',
141
                '\\{' => '{', '\\}' => '}', '\\,' => ','
142
            ));
143 17
        }, $stack);
144
145 17
        return array_values($stack);
146
    }
147
148
    /**
149
     * @param string $subject
150
     * @param array $matches
151
     * @return false|int
152
     */
153 17
    private static function expandBraceInnerMatch($subject, &$matches)
154
    {
155 17
        $result = preg_match_all(
156 17
            '~(\\\\.(*SKIP)(*FAIL)|(?P<token>[,{}]))~',
157 17
            $subject,
158 17
            $lookup,
159 17
            PREG_OFFSET_CAPTURE
160
        );
161
162 17
        if (false === $result) {
0 ignored issues
show
introduced by
The condition false === $result can never be true.
Loading history...
163
            throw new \UnexpectedValueException('regex pattern failure'); // @codeCoverageIgnore
164
        }
165
166 17
        if (0 === $result) {
167 13
            return $result;
168
        }
169
170 11
        $open = null;
171 11
        $comma = null;
172
173 11
        foreach ($lookup['token'] as $token) {
174 11
            list($type, $pos) = $token;
175 11
            if ($type === '{') {
176 10
                $open = $token;
177 10
                $comma = null;
178 11
            } elseif ($type === ',') {
179 10
                $comma = $token;
180 11
            } elseif ($open && $comma) {
181
                $matches = array(
182 9
                    $subject,
183 9
                    substr($subject, 0, $open[1]),
184 9
                    substr($subject, $open[1] + 1, $pos - $open[1] - 1),
185 9
                    substr($subject, $pos + 1),
186
                );
187 11
                return 1;
188
            }
189
        }
190 4
        return 0;
191
    }
192
193
    /**
194
     * check if path is absolute
195
     *
196
     * @param string $path
197
     * @return bool
198
     */
199 8
    public static function fsIsAbsolutePath($path)
200
    {
201
        // TODO: a variant with PHP stream wrapper prefix support
202
203 8
        $count = strspn($path, '/', 0, 3) % 2;
204
205 8
        return (bool)$count;
206
    }
207
208
    /**
209
     * check if path is basename
210
     *
211
     * @param string $path
212
     * @return bool
213
     */
214 5
    public static function fsIsBasename($path)
215
    {
216 5
        if (in_array($path, array('', '.', '..'), true)) {
217 1
            return false;
218
        }
219
220 4
        if (false !== strpos($path, '/')) {
221 3
            return false;
222
        }
223
224 1
        return true;
225
    }
226
227
    /**
228
     * create directory if not yet exists
229
     *
230
     * @param string $path
231
     */
232 2
    public static function fsMkdir($path)
233
    {
234 2
        if (!is_dir($path)) {
235 2
            mkdir($path, 0777, true);
236
        }
237 2
    }
238
239
    /**
240
     * @param string $link
241
     */
242 1
    public static function fsUnlink($link)
243
    {
244 1
        if (is_link($link)) {
245 1
            unlink($link);
246
        }
247 1
    }
248
249
    /**
250
     * create symbolic link, recreate if it exists
251
     *
252
     * @param string $target
253
     * @param string $link
254
     */
255 1
    public static function fsSymlink($target, $link)
256
    {
257 1
        self::fsUnlink($link);
258 1
        symlink($target, $link);
259 1
    }
260
261
    /**
262
     * locate (readable) file by basename upward all parent directories
263
     *
264
     * @param string $basename
265
     * @param string $directory [optional] directory to operate from, defaults
266
     *               to "." (relative path of present working directory)
267
     * @return string
268
     */
269 4
    public static function fsFileLookUp($basename, $directory = null)
270
    {
271 4
        if ("" === $directory || null === $directory) {
272 1
            $directory = ".";
273
        }
274
275
        for (
276 4
            $dirName = $directory, $old = null;
277 4
            $old !== $dirName;
278 2
            $old = $dirName, $dirName = dirname($dirName)
279
        ) {
280 4
            $test = $dirName . '/' . $basename;
281 4
            if (is_file($test) && is_readable($test)) {
282 3
                return $test;
283
            }
284
        }
285
286 1
        return null;
287
    }
288
}
289