From e5fe0730123430fa5202c8ce1b03e4efdd1c0277 Mon Sep 17 00:00:00 2001 From: Jeroeny Date: Sat, 11 Jul 2020 17:12:08 +0200 Subject: [PATCH] [Finder] Fix GitIgnore parser when dealing with (sub)directories and take order of lines into account --- Gitignore.php | 88 +++++++++++++++++++++++++++-------------- Tests/GitignoreTest.php | 14 ++++++- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/Gitignore.php b/Gitignore.php index 5ffe585f..9e7ba4d7 100644 --- a/Gitignore.php +++ b/Gitignore.php @@ -27,42 +27,56 @@ public static function toRegex(string $gitignoreFileContent): string { $gitignoreFileContent = preg_replace('/^[^\\\r\n]*#.*/m', '', $gitignoreFileContent); $gitignoreLines = preg_split('/\r\n|\r|\n/', $gitignoreFileContent); - $gitignoreLines = array_map('trim', $gitignoreLines); - $gitignoreLines = array_filter($gitignoreLines); - $ignoreLinesPositive = array_filter($gitignoreLines, function (string $line) { - return !preg_match('/^!/', $line); - }); - - $ignoreLinesNegative = array_filter($gitignoreLines, function (string $line) { - return preg_match('/^!/', $line); - }); + $positives = []; + $negatives = []; + foreach ($gitignoreLines as $i => $line) { + $line = trim($line); + if ('' === $line) { + continue; + } - $ignoreLinesNegative = array_map(function (string $line) { - return preg_replace('/^!(.*)/', '${1}', $line); - }, $ignoreLinesNegative); - $ignoreLinesNegative = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesNegative); + if (1 === preg_match('/^!/', $line)) { + $positives[$i] = null; + $negatives[$i] = self::getRegexFromGitignore(preg_replace('/^!(.*)/', '${1}', $line), true); - $ignoreLinesPositive = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesPositive); - if (empty($ignoreLinesPositive)) { - return '/^$/'; + continue; + } + $negatives[$i] = null; + $positives[$i] = self::getRegexFromGitignore($line); } - if (empty($ignoreLinesNegative)) { - return sprintf('/%s/', implode('|', $ignoreLinesPositive)); + $index = 0; + $patterns = []; + foreach ($positives as $pattern) { + if (null === $pattern) { + continue; + } + + $negativesAfter = array_filter(\array_slice($negatives, ++$index)); + if ($negativesAfter !== []) { + $pattern .= sprintf('(?'.$regex.'($|\/.*))'; } } diff --git a/Tests/GitignoreTest.php b/Tests/GitignoreTest.php index 9f9ed738..ae1cfb99 100644 --- a/Tests/GitignoreTest.php +++ b/Tests/GitignoreTest.php @@ -47,6 +47,7 @@ public function provider(): array [ ' * + !/bin !/bin/bash ', ['bin/cat', 'abc/bin/cat'], @@ -99,8 +100,8 @@ public function provider(): array ], [ 'app/cache/', - ['app/cache/file.txt', 'app/cache/dir1/dir2/file.txt', 'a/app/cache/file.txt'], - [], + ['app/cache/file.txt', 'app/cache/dir1/dir2/file.txt'], + ['a/app/cache/file.txt'], ], [ ' @@ -133,6 +134,15 @@ public function provider(): array ['app/cache/file.txt', 'app/cache/subdir/ile.txt', '#file.txt', 'another_file.txt'], ['a/app/cache/file.txt', 'IamComment', '#IamComment'], ], + [ + ' + /app/** + !/app/bin + !/app/bin/test + ', + ['app/test/file', 'app/bin/file'], + ['app/bin/test'], + ], ]; } }