merged branch jfsimon/issue-6981 (PR #7518)
This PR was merged into the master branch.
Discussion
----------
[Finder] adds a way to ignore AccessDeniedException
This PR adds a `Finder::ignoreUnreadableDirs()` method which tells `Finder` to ignore unreadable directories instead of throwing an `AccessDeniedException`.
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #6981
Commits
-------
a63b30b
[Finder] added Finder::ignoreUnreadableDirs() method
This commit is contained in:
commit
b58f9fdbd6
@ -33,6 +33,7 @@ abstract class AbstractAdapter implements AdapterInterface
|
||||
protected $sort = false;
|
||||
protected $paths = array();
|
||||
protected $notPaths = array();
|
||||
protected $ignoreUnreadableDirs = false;
|
||||
|
||||
private static $areSupported = array();
|
||||
|
||||
@ -210,6 +211,16 @@ abstract class AbstractAdapter implements AdapterInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function ignoreUnreadableDirs($ignore = true)
|
||||
{
|
||||
$this->ignoreUnreadableDirs = (Boolean) $ignore;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the adapter is supported in the current environment.
|
||||
*
|
||||
|
@ -92,9 +92,12 @@ abstract class AbstractFindAdapter extends AbstractAdapter
|
||||
$this->buildSorting($command, $this->sort);
|
||||
}
|
||||
|
||||
$command->setErrorHandler(function ($stderr) {
|
||||
throw new AccessDeniedException($stderr);
|
||||
});
|
||||
$command->setErrorHandler(
|
||||
$this->ignoreUnreadableDirs
|
||||
// If directory is unreadable and finder is set to ignore it, `stderr` is ignored.
|
||||
? function ($stderr) { return; }
|
||||
: function ($stderr) { throw new AccessDeniedException($stderr); }
|
||||
);
|
||||
|
||||
$paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
|
||||
$iterator = new Iterator\FilePathsIterator($paths, $dir);
|
||||
|
@ -114,6 +114,13 @@ interface AdapterInterface
|
||||
*/
|
||||
public function setNotPath(array $notPaths);
|
||||
|
||||
/**
|
||||
* @param boolean $ignore
|
||||
*
|
||||
* @return AdapterInterface Current instance
|
||||
*/
|
||||
public function ignoreUnreadableDirs($ignore = true);
|
||||
|
||||
/**
|
||||
* @param string $dir
|
||||
*
|
||||
|
@ -32,7 +32,7 @@ class PhpAdapter extends AbstractAdapter
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new Iterator\RecursiveDirectoryIterator($dir, $flags),
|
||||
new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs),
|
||||
\RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
|
||||
|
@ -55,6 +55,7 @@ class Finder implements \IteratorAggregate, \Countable
|
||||
private $adapters = array();
|
||||
private $paths = array();
|
||||
private $notPaths = array();
|
||||
private $ignoreUnreadableDirs = false;
|
||||
|
||||
private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
|
||||
|
||||
@ -626,6 +627,22 @@ class Finder implements \IteratorAggregate, \Countable
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells finder to ignore unreadable directories.
|
||||
*
|
||||
* By default, scanning unreadable directories content throws an AccessDeniedException.
|
||||
*
|
||||
* @param boolean $ignore
|
||||
*
|
||||
* @return Finder The current Finder instance
|
||||
*/
|
||||
public function ignoreUnreadableDirs($ignore = true)
|
||||
{
|
||||
$this->ignoreUnreadableDirs = (Boolean) $ignore;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches files and directories which match defined rules.
|
||||
*
|
||||
@ -794,7 +811,8 @@ class Finder implements \IteratorAggregate, \Countable
|
||||
->setFilters($this->filters)
|
||||
->setSort($this->sort)
|
||||
->setPath($this->paths)
|
||||
->setNotPath($this->notPaths);
|
||||
->setNotPath($this->notPaths)
|
||||
->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,13 +21,28 @@ use Symfony\Component\Finder\SplFileInfo;
|
||||
*/
|
||||
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||
{
|
||||
public function __construct($path, $flags)
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $ignoreUnreadableDirs;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $flags
|
||||
* @param boolean $ignoreUnreadableDirs
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function __construct($path, $flags, $ignoreUnreadableDirs = false)
|
||||
{
|
||||
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
|
||||
throw new \RuntimeException('This iterator only support returning current as fileinfo.');
|
||||
}
|
||||
|
||||
parent::__construct($path, $flags);
|
||||
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,7 +56,7 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed object
|
||||
* @return \RecursiveIterator
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
*/
|
||||
@ -50,7 +65,12 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||
try {
|
||||
return parent::getChildren();
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
|
||||
if ($this->ignoreUnreadableDirs) {
|
||||
// If directory is unreadable and finder is set to ignore it, a fake empty content is returned.
|
||||
return new \RecursiveArrayIterator(array());
|
||||
} else {
|
||||
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -725,16 +725,34 @@ class FinderTest extends Iterator\RealIteratorTestCase
|
||||
$finder = $this->buildFinder($adapter);
|
||||
$finder->files()->in(self::$tmpDir);
|
||||
|
||||
// make 'foo' directory non-openable
|
||||
// make 'foo' directory non-readable
|
||||
chmod(self::$tmpDir.DIRECTORY_SEPARATOR.'foo', 0333);
|
||||
|
||||
try {
|
||||
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->getIterator());
|
||||
$this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
|
||||
$this->fail('Finder should throw an exception when opening a non-readable directory.');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Symfony\\Component\\Finder\\Exception\\AccessDeniedException', get_class($e));
|
||||
}
|
||||
|
||||
// restore original permissions
|
||||
chmod(self::$tmpDir.DIRECTORY_SEPARATOR.'foo', 0777);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getAdaptersTestData
|
||||
*/
|
||||
public function testIgnoredAccessDeniedException(Adapter\AdapterInterface $adapter)
|
||||
{
|
||||
$finder = $this->buildFinder($adapter);
|
||||
$finder->files()->ignoreUnreadableDirs()->in(self::$tmpDir);
|
||||
|
||||
// make 'foo' directory non-readable
|
||||
chmod(self::$tmpDir.DIRECTORY_SEPARATOR.'foo', 0333);
|
||||
|
||||
$this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
|
||||
|
||||
// restore original permissions
|
||||
chmod(self::$tmpDir.DIRECTORY_SEPARATOR.'foo', 0777);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user