From 8b28afa0f69f941ea26a988693a39147faa48aa6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 8 Feb 2017 23:46:33 +0100 Subject: [PATCH] [Finder] Add double-star matching to Glob::toRegex() --- src/Symfony/Component/Finder/CHANGELOG.md | 5 +++ src/Symfony/Component/Finder/Glob.php | 18 +++++----- .../Component/Finder/Tests/Fixtures/.dot/a | 0 .../Finder/Tests/Fixtures/.dot/b/c.neon | 0 .../Finder/Tests/Fixtures/.dot/b/d.neon | 0 .../Component/Finder/Tests/GlobTest.php | 35 +++++++++++++++++++ 6 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/Symfony/Component/Finder/Tests/Fixtures/.dot/a create mode 100644 src/Symfony/Component/Finder/Tests/Fixtures/.dot/b/c.neon create mode 100644 src/Symfony/Component/Finder/Tests/Fixtures/.dot/b/d.neon diff --git a/src/Symfony/Component/Finder/CHANGELOG.md b/src/Symfony/Component/Finder/CHANGELOG.md index 67f557bddc80c..cf19de6930ed5 100644 --- a/src/Symfony/Component/Finder/CHANGELOG.md +++ b/src/Symfony/Component/Finder/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.3.0 +----- + + * added double-star matching to Glob::toRegex() + 3.0.0 ----- diff --git a/src/Symfony/Component/Finder/Glob.php b/src/Symfony/Component/Finder/Glob.php index 953a0b3e9004b..8a439411fbb6c 100644 --- a/src/Symfony/Component/Finder/Glob.php +++ b/src/Symfony/Component/Finder/Glob.php @@ -54,16 +54,18 @@ public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardS $sizeGlob = strlen($glob); for ($i = 0; $i < $sizeGlob; ++$i) { $car = $glob[$i]; - if ($firstByte) { - if ($strictLeadingDot && '.' !== $car) { - $regex .= '(?=[^\.])'; - } - - $firstByte = false; + if ($firstByte && $strictLeadingDot && '.' !== $car) { + $regex .= '(?=[^\.])'; } - if ('/' === $car) { - $firstByte = true; + $firstByte = '/' === $car; + + if ($firstByte && $strictWildcardSlash && isset($glob[$i + 3]) && '**/' === $glob[$i + 1].$glob[$i + 2].$glob[$i + 3]) { + $car = $strictLeadingDot ? '/((?=[^\.])[^/]+/)*' : '/([^/]+/)*'; + $i += 3; + if ('/' === $delimiter) { + $car = str_replace('/', '\\/', $car); + } } if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) { diff --git a/src/Symfony/Component/Finder/Tests/Fixtures/.dot/a b/src/Symfony/Component/Finder/Tests/Fixtures/.dot/a new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Symfony/Component/Finder/Tests/Fixtures/.dot/b/c.neon b/src/Symfony/Component/Finder/Tests/Fixtures/.dot/b/c.neon new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Symfony/Component/Finder/Tests/Fixtures/.dot/b/d.neon b/src/Symfony/Component/Finder/Tests/Fixtures/.dot/b/d.neon new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Symfony/Component/Finder/Tests/GlobTest.php b/src/Symfony/Component/Finder/Tests/GlobTest.php index dd73e257ba826..1c8817b499f8a 100755 --- a/src/Symfony/Component/Finder/Tests/GlobTest.php +++ b/src/Symfony/Component/Finder/Tests/GlobTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Finder\Tests; +use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\Glob; class GlobTest extends \PHPUnit_Framework_TestCase @@ -22,4 +23,38 @@ public function testGlobToRegexDelimiters() $this->assertEquals('^\.[^/]*$', Glob::toRegex('.*', true, true, '')); $this->assertEquals('/^\.[^/]*$/', Glob::toRegex('.*', true, true, '/')); } + + public function testGlobToRegexDoubleStarStrictDots() + { + $finder = new Finder(); + $finder->ignoreDotFiles(false); + $regex = Glob::toRegex('/**/*.neon'); + + foreach ($finder->in(__DIR__) as $k => $v) { + $k = str_replace(DIRECTORY_SEPARATOR, '/', $k); + if (preg_match($regex, substr($k, strlen(__DIR__)))) { + $match[] = substr($k, 10 + strlen(__DIR__)); + } + } + sort($match); + + $this->assertSame(array('one/b/c.neon', 'one/b/d.neon'), $match); + } + + public function testGlobToRegexDoubleStarNonStrictDots() + { + $finder = new Finder(); + $finder->ignoreDotFiles(false); + $regex = Glob::toRegex('/**/*.neon', false); + + foreach ($finder->in(__DIR__) as $k => $v) { + $k = str_replace(DIRECTORY_SEPARATOR, '/', $k); + if (preg_match($regex, substr($k, strlen(__DIR__)))) { + $match[] = substr($k, 10 + strlen(__DIR__)); + } + } + sort($match); + + $this->assertSame(array('.dot/b/c.neon', '.dot/b/d.neon', 'one/b/c.neon', 'one/b/d.neon'), $match); + } }