[Finder] added Finder::ignoreUnreadableDirs() method

This commit is contained in:
Jean-François Simon 2013-03-29 15:47:08 +01:00
parent ea79360fba
commit a63b30b5ce
7 changed files with 87 additions and 10 deletions

View File

@ -33,6 +33,7 @@ abstract class AbstractAdapter implements AdapterInterface
protected $sort = false; protected $sort = false;
protected $paths = array(); protected $paths = array();
protected $notPaths = array(); protected $notPaths = array();
protected $ignoreUnreadableDirs = false;
private static $areSupported = array(); private static $areSupported = array();
@ -210,6 +211,16 @@ abstract class AbstractAdapter implements AdapterInterface
return $this; return $this;
} }
/**
* {@inheritdoc}
*/
public function ignoreUnreadableDirs($ignore = true)
{
$this->ignoreUnreadableDirs = (Boolean) $ignore;
return $this;
}
/** /**
* Returns whether the adapter is supported in the current environment. * Returns whether the adapter is supported in the current environment.
* *

View File

@ -92,9 +92,12 @@ abstract class AbstractFindAdapter extends AbstractAdapter
$this->buildSorting($command, $this->sort); $this->buildSorting($command, $this->sort);
} }
$command->setErrorHandler(function ($stderr) { $command->setErrorHandler(
throw new AccessDeniedException($stderr); $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()); $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
$iterator = new Iterator\FilePathsIterator($paths, $dir); $iterator = new Iterator\FilePathsIterator($paths, $dir);

View File

@ -114,6 +114,13 @@ interface AdapterInterface
*/ */
public function setNotPath(array $notPaths); public function setNotPath(array $notPaths);
/**
* @param boolean $ignore
*
* @return AdapterInterface Current instance
*/
public function ignoreUnreadableDirs($ignore = true);
/** /**
* @param string $dir * @param string $dir
* *

View File

@ -32,7 +32,7 @@ class PhpAdapter extends AbstractAdapter
} }
$iterator = new \RecursiveIteratorIterator( $iterator = new \RecursiveIteratorIterator(
new Iterator\RecursiveDirectoryIterator($dir, $flags), new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs),
\RecursiveIteratorIterator::SELF_FIRST \RecursiveIteratorIterator::SELF_FIRST
); );

View File

@ -55,6 +55,7 @@ class Finder implements \IteratorAggregate, \Countable
private $adapters = array(); private $adapters = array();
private $paths = array(); private $paths = array();
private $notPaths = array(); private $notPaths = array();
private $ignoreUnreadableDirs = false;
private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'); 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; 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. * Searches files and directories which match defined rules.
* *
@ -794,7 +811,8 @@ class Finder implements \IteratorAggregate, \Countable
->setFilters($this->filters) ->setFilters($this->filters)
->setSort($this->sort) ->setSort($this->sort)
->setPath($this->paths) ->setPath($this->paths)
->setNotPath($this->notPaths); ->setNotPath($this->notPaths)
->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
} }
/** /**

View File

@ -21,13 +21,28 @@ use Symfony\Component\Finder\SplFileInfo;
*/ */
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator 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)) { if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
throw new \RuntimeException('This iterator only support returning current as fileinfo.'); throw new \RuntimeException('This iterator only support returning current as fileinfo.');
} }
parent::__construct($path, $flags); parent::__construct($path, $flags);
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
} }
/** /**
@ -41,7 +56,7 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
} }
/** /**
* @return mixed object * @return \RecursiveIterator
* *
* @throws AccessDeniedException * @throws AccessDeniedException
*/ */
@ -50,7 +65,12 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
try { try {
return parent::getChildren(); return parent::getChildren();
} catch (\UnexpectedValueException $e) { } 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);
}
} }
} }
} }

View File

@ -725,16 +725,34 @@ class FinderTest extends Iterator\RealIteratorTestCase
$finder = $this->buildFinder($adapter); $finder = $this->buildFinder($adapter);
$finder->files()->in(self::$tmpDir); $finder->files()->in(self::$tmpDir);
// make 'foo' directory non-openable // make 'foo' directory non-readable
chmod(self::$tmpDir.DIRECTORY_SEPARATOR.'foo', 0333); chmod(self::$tmpDir.DIRECTORY_SEPARATOR.'foo', 0333);
try { 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.'); $this->fail('Finder should throw an exception when opening a non-readable directory.');
} catch (\Exception $e) { } catch (\Exception $e) {
$this->assertEquals('Symfony\\Component\\Finder\\Exception\\AccessDeniedException', get_class($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); chmod(self::$tmpDir.DIRECTORY_SEPARATOR.'foo', 0777);
} }