Skip to content

Commit 6c5c4fb

Browse files
milodg
authored andcommitted
Helpers: added findCommonDirectory()
1 parent 5787f67 commit 6c5c4fb

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

src/Framework/Helpers.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,35 @@ public static function purge(string $dir): void
3636
}
3737

3838

39+
/**
40+
* Find common directory for given paths. All files or directories must exist.
41+
* @return string Empty when not found. Slash and back slash chars normalized to DIRECTORY_SEPARATOR.
42+
*/
43+
public static function findCommonDirectory(array $paths): string
44+
{
45+
$splitPaths = array_map(function ($s) {
46+
$real = realpath($s);
47+
if ($s === '') {
48+
throw new \RuntimeException("Path must not be empty.");
49+
} elseif ($real === false) {
50+
throw new \RuntimeException("File or directory '$s' does not exist.");
51+
}
52+
return explode(DIRECTORY_SEPARATOR, $real);
53+
}, $paths);
54+
55+
$first = (array) array_shift($splitPaths);
56+
for ($i = 0; $i < count($first); $i++) {
57+
foreach ($splitPaths as $s) {
58+
if ($first[$i] !== ($s[$i] ?? null)) {
59+
break 2;
60+
}
61+
}
62+
}
63+
$common = implode(DIRECTORY_SEPARATOR, array_slice($first, 0, $i));
64+
return is_dir($common) ? $common : dirname($common);
65+
}
66+
67+
3968
/**
4069
* Parse phpDoc comment.
4170
* @internal
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Tester\Assert;
6+
use Tester\Helpers;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
Assert::same('', Helpers::findCommonDirectory([]));
11+
12+
Assert::match(__DIR__ . DIRECTORY_SEPARATOR . 'fixtures.helpers', Helpers::findCommonDirectory([
13+
__DIR__ . '/fixtures.helpers/a',
14+
__DIR__ . '/fixtures.helpers/aa',
15+
]));
16+
17+
Assert::match(__DIR__ . DIRECTORY_SEPARATOR . 'fixtures.helpers', Helpers::findCommonDirectory([
18+
__DIR__ . '/fixtures.helpers/a/file.txt',
19+
__DIR__ . '/fixtures.helpers/aa/file.txt',
20+
]));
21+
22+
Assert::match(__DIR__ . DIRECTORY_SEPARATOR . 'fixtures.helpers' . DIRECTORY_SEPARATOR . 'a', Helpers::findCommonDirectory([
23+
__DIR__ . '/fixtures.helpers/a/',
24+
__DIR__ . '/fixtures.helpers/a/file.txt',
25+
]));
26+
27+
Assert::match(getcwd(), Helpers::findCommonDirectory([
28+
'.',
29+
]));
30+
31+
Assert::match(dirname(getcwd()), Helpers::findCommonDirectory([
32+
'..',
33+
]));
34+
35+
36+
// Root directories always end by directory separator.
37+
if (is_dir('C:/')) {
38+
Assert::match('C:\\', Helpers::findCommonDirectory([
39+
'C:',
40+
]));
41+
}
42+
43+
if (is_dir('/')) {
44+
Assert::match(realpath('/'), Helpers::findCommonDirectory([ // realpath() - may point to C:\ in Cygwin
45+
'/',
46+
]));
47+
}
48+
49+
50+
Assert::exception(function () {
51+
Helpers::findCommonDirectory(['']);
52+
}, RuntimeException::class, 'Path must not be empty.');
53+
54+
Assert::exception(function () {
55+
Helpers::findCommonDirectory(['does-not-exist']);
56+
}, RuntimeException::class, "File or directory 'does-not-exist' does not exist.");

tests/Framework/fixtures.helpers/a/file.txt

Whitespace-only changes.

tests/Framework/fixtures.helpers/aa/file.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)