bug #29394 [Config] fix path exclusion during glob discovery (nicolas-grekas)

This PR was merged into the 4.2 branch.

Discussion
----------

[Config] fix path exclusion during glob discovery

| Q             | A
| ------------- | ---
| Branch?       | 4.2
| Bug fix?      | yes
| New feature?  | -
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

Something we missed in #28200 - reported on Slack.

Commits
-------

4ada4dca43 [Config] fix path exclusion during glob discovery
This commit is contained in:
Nicolas Grekas 2018-12-01 09:12:16 +01:00
commit cb507a5b05
3 changed files with 45 additions and 24 deletions

View File

@ -96,9 +96,19 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface,
if (!file_exists($this->prefix) || (!$this->recursive && '' === $this->pattern)) {
return;
}
$prefix = str_replace('\\', '/', $this->prefix);
if (0 !== strpos($this->prefix, 'phar://') && false === strpos($this->pattern, '/**/') && (\defined('GLOB_BRACE') || false === strpos($this->pattern, '{'))) {
foreach (glob($this->prefix.$this->pattern, \defined('GLOB_BRACE') ? GLOB_BRACE : 0) as $path) {
if ($this->excludedPrefixes) {
$normalizedPath = str_replace('\\', '/', $path);
do {
if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) {
continue 2;
}
} while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
}
if (is_file($path)) {
yield $path => new \SplFileInfo($path);
}
@ -145,9 +155,19 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface,
$prefixLen = \strlen($this->prefix);
foreach ($finder->followLinks()->sortByName()->in($this->prefix) as $path => $info) {
if (preg_match($regex, substr(str_replace('\\', '/', $path), $prefixLen)) && $info->isFile()) {
yield $path => $info;
$normalizedPath = str_replace('\\', '/', $path);
if (!preg_match($regex, substr($normalizedPath, $prefixLen)) || !$info->isFile()) {
continue;
}
if ($this->excludedPrefixes) {
do {
if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) {
continue 2;
}
} while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
}
yield $path => $info;
}
}

View File

@ -73,6 +73,20 @@ class GlobResourceTest extends TestCase
$this->assertArrayNotHasKey($file, $paths);
}
public function testIteratorSkipsSubfoldersForGivenExcludedPrefixes()
{
$dir = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures';
$resource = new GlobResource($dir, '/*Exclude/*', true, false, array($dir.\DIRECTORY_SEPARATOR.'Exclude' => true));
$paths = iterator_to_array($resource);
$file = $dir.\DIRECTORY_SEPARATOR.'Exclude'.\DIRECTORY_SEPARATOR.'AnExcludedFile.txt';
$this->assertArrayNotHasKey($file, $paths);
$file = $dir.\DIRECTORY_SEPARATOR.'Exclude'.\DIRECTORY_SEPARATOR.'ExcludeToo'.\DIRECTORY_SEPARATOR.'AnotheExcludedFile.txt';
$this->assertArrayNotHasKey($file, $paths);
}
public function testIteratorSkipsFoldersWithForwardSlashForGivenExcludedPrefixes()
{
$dir = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures';

View File

@ -18,7 +18,6 @@ use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Loader\FileLoader;
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
@ -217,32 +216,20 @@ class FileLoaderTest extends TestCase
}
/**
* @dataProvider getIncompatibleExcludeTests
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
* @expectedExceptionMessage Invalid "exclude" pattern when importing classes for "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\": make sure your "exclude" pattern (yaml/*) is a subset of the "resource" pattern (Prototype/*)
*/
public function testRegisterClassesWithIncompatibleExclude($resourcePattern, $excludePattern)
public function testRegisterClassesWithIncompatibleExclude()
{
$container = new ContainerBuilder();
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));
try {
$loader->registerClasses(
new Definition(),
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
$resourcePattern,
$excludePattern
);
} catch (InvalidArgumentException $e) {
$this->assertEquals(
sprintf('Invalid "exclude" pattern when importing classes for "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s)', $excludePattern, $resourcePattern),
$e->getMessage()
);
}
}
public function getIncompatibleExcludeTests()
{
yield array('Prototype/*', 'yaml/*', false);
yield array('Prototype/OtherDir/*', 'Prototype/*', false);
$loader->registerClasses(
new Definition(),
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
'Prototype/*',
'yaml/*'
);
}
}