merged branch vicb/finder-adapters (PR #6253)

This PR was squashed before being merged into the master branch (closes #6253).

Commits
-------

e62b5f7 [Finder] cleanup, fixes, improvements

Discussion
----------

[Finder] cleanup, fixes, improvements
This commit is contained in:
Fabien Potencier 2012-12-10 14:52:40 +01:00
commit 1ec59f174e
12 changed files with 198 additions and 167 deletions

View File

@ -34,6 +34,22 @@ abstract class AbstractAdapter implements AdapterInterface
protected $paths = array(); protected $paths = array();
protected $notPaths = array(); protected $notPaths = array();
private static $areSupported = array();
/**
* {@inheritDoc}
*/
public function isSupported()
{
$name = $this->getName();
if (!array_key_exists($name, self::$areSupported)) {
self::$areSupported[$name] = $this->canBeUsed();
}
return self::$areSupported[$name];
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -193,4 +209,17 @@ abstract class AbstractAdapter implements AdapterInterface
return $this; return $this;
} }
/**
* Returns whether the adapter is supported in the current environment.
*
* This method should be implemented in all adapters. Do not implement
* isSupported in the adapters as the generic implementation provides a cache
* layer.
*
* @see isSupported
*
* @return Boolean Whether the adapter is supported
*/
abstract protected function canBeUsed();
} }

View File

@ -59,11 +59,11 @@ abstract class AbstractFindAdapter extends AbstractAdapter
$find->add('-follow'); $find->add('-follow');
} }
$find->add('-mindepth')->add($this->minDepth+1); $find->add('-mindepth')->add($this->minDepth + 1);
// warning! INF < INF => true ; INF == INF => false ; INF === INF => true // warning! INF < INF => true ; INF == INF => false ; INF === INF => true
// https://bugs.php.net/bug.php?id=9118 // https://bugs.php.net/bug.php?id=9118
if (INF !== $this->maxDepth) { if (INF !== $this->maxDepth) {
$find->add('-maxdepth')->add($this->maxDepth+1); $find->add('-maxdepth')->add($this->maxDepth + 1);
} }
if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) { if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
@ -118,13 +118,14 @@ abstract class AbstractFindAdapter extends AbstractAdapter
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isSupported() protected function canBeUsed()
{ {
return $this->shell->testCommand('find'); return $this->shell->testCommand('find');
} }
/** /**
* @param Command $command * @param Command $command
* @param string $dir
* *
* @return Command * @return Command
*/ */
@ -140,7 +141,7 @@ abstract class AbstractFindAdapter extends AbstractAdapter
/** /**
* @param Command $command * @param Command $command
* @param string[] $names * @param string[] $names
* @param bool $not * @param Boolean $not
*/ */
private function buildNamesFiltering(Command $command, array $names, $not = false) private function buildNamesFiltering(Command $command, array $names, $not = false)
{ {
@ -183,7 +184,8 @@ abstract class AbstractFindAdapter extends AbstractAdapter
* @param Command $command * @param Command $command
* @param string $dir * @param string $dir
* @param string[] $paths * @param string[] $paths
* @param bool $not * @param Boolean $not
*
* @return void * @return void
*/ */
private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false) private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
@ -226,33 +228,23 @@ abstract class AbstractFindAdapter extends AbstractAdapter
foreach ($sizes as $i => $size) { foreach ($sizes as $i => $size) {
$command->add($i > 0 ? '-and' : null); $command->add($i > 0 ? '-and' : null);
if ('<=' === $size->getOperator()) { switch ($size->getOperator()) {
$command->add('-size -'.($size->getTarget()+1).'c'); case '<=':
continue; $command->add('-size -' . ($size->getTarget() + 1) . 'c');
break;
case '>=':
$command->add('-size +'. ($size->getTarget() - 1) . 'c');
break;
case '>':
$command->add('-size +' . $size->getTarget() . 'c');
break;
case '!=':
$command->add('-size -' . $size->getTarget() . 'c');
$command->add('-size +' . $size->getTarget() . 'c');
case '<':
default:
$command->add('-size -' . $size->getTarget() . 'c');
} }
if ('<' === $size->getOperator()) {
$command->add('-size -'.$size->getTarget().'c');
continue;
}
if ('>=' === $size->getOperator()) {
$command->add('-size +'.($size->getTarget()-1).'c');
continue;
}
if ('>' === $size->getOperator()) {
$command->add('-size +'.$size->getTarget().'c');
continue;
}
if ('!=' === $size->getOperator()) {
$command->add('-size -'.$size->getTarget().'c');
$command->add('-size +'.$size->getTarget().'c');
continue;
}
$command->add('-size '.$size->getTarget().'c');
} }
} }
@ -265,7 +257,7 @@ abstract class AbstractFindAdapter extends AbstractAdapter
foreach ($dates as $i => $date) { foreach ($dates as $i => $date) {
$command->add($i > 0 ? '-and' : null); $command->add($i > 0 ? '-and' : null);
$mins = (int) round((time()-$date->getTarget())/60); $mins = (int) round((time()-$date->getTarget()) / 60);
if (0 > $mins) { if (0 > $mins) {
// mtime is in the future // mtime is in the future
@ -274,39 +266,30 @@ abstract class AbstractFindAdapter extends AbstractAdapter
return; return;
} }
if ('<=' === $date->getOperator()) { switch ($date->getOperator()) {
$command->add('-mmin +'.($mins-1)); case '<=':
continue; $command->add('-mmin +' . ($mins - 1));
break;
case '>=':
$command->add('-mmin -' . ($mins + 1));
break;
case '>':
$command->add('-mmin -' . $mins);
break;
case '!=':
$command->add('-mmin +' . $mins.' -or -mmin -' . $mins);
break;
case '<':
default:
$command->add('-mmin +' . $mins);
} }
if ('<' === $date->getOperator()) {
$command->add('-mmin +'.$mins);
continue;
}
if ('>=' === $date->getOperator()) {
$command->add('-mmin -'.($mins+1));
continue;
}
if ('>' === $date->getOperator()) {
$command->add('-mmin -'.$mins);
continue;
}
if ('!=' === $date->getOperator()) {
$command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
continue;
}
$command->add('-mmin '.$mins);
} }
} }
/** /**
* @param Command $command * @param Command $command
* @param array $contains * @param array $contains
* @param bool $not * @param Boolean $not
*/ */
private function buildContentFiltering(Command $command, array $contains, $not = false) private function buildContentFiltering(Command $command, array $contains, $not = false)
{ {
@ -323,8 +306,9 @@ abstract class AbstractFindAdapter extends AbstractAdapter
} }
/** /**
* @param \Symfony\Component\Finder\Shell\Command $command * @param Command $command
* @param string $sort * @param string $sort
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
private function buildSorting(Command $command, $sort) private function buildSorting(Command $command, $sort)

View File

@ -17,14 +17,14 @@ namespace Symfony\Component\Finder\Adapter;
interface AdapterInterface interface AdapterInterface
{ {
/** /**
* @param bool $followLinks * @param Boolean $followLinks
* *
* @return AdapterInterface Current instance * @return AdapterInterface Current instance
*/ */
public function setFollowLinks($followLinks); public function setFollowLinks($followLinks);
/** /**
* @param int $mode * @param integer $mode
* *
* @return AdapterInterface Current instance * @return AdapterInterface Current instance
*/ */
@ -94,14 +94,14 @@ interface AdapterInterface
public function setFilters(array $filters); public function setFilters(array $filters);
/** /**
* @param \Closure|int $sort * @param \Closure|integer $sort
* *
* @return AdapterInterface Current instance * @return AdapterInterface Current instance
*/ */
public function setSort($sort); public function setSort($sort);
/** /**
* @param array $path * @param array $paths
* *
* @return AdapterInterface Current instance * @return AdapterInterface Current instance
*/ */
@ -124,7 +124,7 @@ interface AdapterInterface
/** /**
* Tests adapter support for current platform. * Tests adapter support for current platform.
* *
* @return bool * @return Boolean
*/ */
public function isSupported(); public function isSupported();

View File

@ -22,14 +22,6 @@ use Symfony\Component\Finder\Shell\Command;
*/ */
class BsdFindAdapter extends AbstractFindAdapter class BsdFindAdapter extends AbstractFindAdapter
{ {
/**
* {@inheritdoc}
*/
public function isSupported()
{
return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::isSupported();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -38,12 +30,25 @@ class BsdFindAdapter extends AbstractFindAdapter
return 'bsd_find'; return 'bsd_find';
} }
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function buildFormatSorting(Command $command, $format) protected function buildFormatSorting(Command $command, $format)
{ {
$command->get('find')->add('-print0 | xargs -0 stat -f')->arg($format.' %h/%f\\n') $command
->add('| sort | cut')->arg('-d ')->arg('-f2-'); ->get('find')
->add('-print0 | xargs -0 stat -f')
->arg($format.' %h/%f\\n')
->add('| sort | cut')
->arg('-d ')
->arg('-f2-');
} }
} }

View File

@ -22,14 +22,6 @@ use Symfony\Component\Finder\Shell\Command;
*/ */
class GnuFindAdapter extends AbstractFindAdapter class GnuFindAdapter extends AbstractFindAdapter
{ {
/**
* {@inheritdoc}
*/
public function isSupported()
{
return $this->shell->getType() === Shell::TYPE_UNIX && parent::isSupported();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -43,8 +35,22 @@ class GnuFindAdapter extends AbstractFindAdapter
*/ */
protected function buildFormatSorting(Command $command, $format) protected function buildFormatSorting(Command $command, $format)
{ {
$command->get('find')->add('-printf')->arg($format.' %h/%f\\n') $command
->add('| sort | cut')->arg('-d ')->arg('-f2-'); ->get('find')
->add('-printf')
->arg($format.' %h/%f\\n')
->add('| sort | cut')
->arg('-d ')
->arg('-f2-')
;
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return $this->shell->getType() === Shell::TYPE_UNIX && parent::canBeUsed();
} }
/** /**

View File

@ -83,16 +83,16 @@ class PhpAdapter extends AbstractAdapter
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isSupported() public function getName()
{ {
return true; return 'php';
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getName() protected function canBeUsed()
{ {
return 'php'; return true;
} }
} }

View File

@ -65,9 +65,11 @@ class Finder implements \IteratorAggregate, \Countable
{ {
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES; $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
$this->addAdapter(new GnuFindAdapter()); $this
$this->addAdapter(new BsdFindAdapter()); ->addAdapter(new GnuFindAdapter())
$this->addAdapter(new PhpAdapter(), -50); ->addAdapter(new BsdFindAdapter())
->addAdapter(new PhpAdapter(), -50)
;
} }
/** /**
@ -86,7 +88,7 @@ class Finder implements \IteratorAggregate, \Countable
* Registers a finder engine implementation. * Registers a finder engine implementation.
* *
* @param AdapterInterface $adapter An adapter instance * @param AdapterInterface $adapter An adapter instance
* @param int $priority Highest is selected first * @param integer $priority Highest is selected first
* *
* @return Finder The current Finder instance * @return Finder The current Finder instance
*/ */
@ -418,9 +420,20 @@ class Finder implements \IteratorAggregate, \Countable
return $this; return $this;
} }
/**
* Adds VCS patterns.
*
* @see ignoreVCS
*
* @param string|string[] $pattern VCS patterns to ignore
*/
public static function addVCSPattern($pattern) public static function addVCSPattern($pattern)
{ {
self::$vcsPatterns[] = $pattern; foreach ((array) $pattern as $p) {
self::$vcsPatterns[] = $p;
}
self::$vcsPatterns = array_unique(self::$vcsPatterns);
} }
/** /**
@ -691,6 +704,8 @@ class Finder implements \IteratorAggregate, \Countable
* @param $dir * @param $dir
* *
* @return \Iterator * @return \Iterator
*
* @throws \RuntimeException When none of the adapters are supported
*/ */
private function searchInDirectory($dir) private function searchInDirectory($dir)
{ {
@ -703,16 +718,12 @@ class Finder implements \IteratorAggregate, \Countable
} }
foreach ($this->adapters as $adapter) { foreach ($this->adapters as $adapter) {
if (!$adapter['adapter']->isSupported()) { if ($adapter['adapter']->isSupported()) {
continue; try {
} return $this
->buildAdapter($adapter['adapter'])
try { ->searchInDirectory($dir);
return $this } catch(ExceptionInterface $e) {}
->buildAdapter($adapter['adapter'])
->searchInDirectory($dir);
} catch(ExceptionInterface $e) {
continue;
} }
} }

View File

@ -42,16 +42,16 @@ class DummyAdapter extends AbstractAdapter
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isSupported() public function getName()
{ {
return true; return 'yes';
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getName() protected function canBeUsed()
{ {
return 'yes'; return true;
} }
} }

View File

@ -30,16 +30,16 @@ class FailingAdapter extends AbstractAdapter
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isSupported() public function getName()
{ {
return true; return 'failing';
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
function getName() protected function canBeUsed()
{ {
return 'failing'; return true;
} }
} }

View File

@ -42,16 +42,16 @@ class NamedAdapter extends AbstractAdapter
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isSupported() public function getName()
{ {
return true; return $this->name;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
function getName() protected function canBeUsed()
{ {
return $this->name; return true;
} }
} }

View File

@ -29,16 +29,16 @@ class UnsupportedAdapter extends AbstractAdapter
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isSupported() public function getName()
{ {
return false; return 'unsupported';
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
function getName() protected function canBeUsed()
{ {
return 'unsupported'; return false;
} }
} }

View File

@ -356,9 +356,7 @@ class FinderTest extends Iterator\RealIteratorTestCase
*/ */
public function testRelativePath($adapter) public function testRelativePath($adapter)
{ {
$finder = $this->buildFinder($adapter); $finder = $this->buildFinder($adapter)->in(self::$tmpDir);
$finder->in(self::$tmpDir);
$paths = array(); $paths = array();
@ -379,9 +377,7 @@ class FinderTest extends Iterator\RealIteratorTestCase
*/ */
public function testRelativePathname($adapter) public function testRelativePathname($adapter)
{ {
$finder = $this->buildFinder($adapter); $finder = $this->buildFinder($adapter)->in(self::$tmpDir)->sortByName();
$finder->in(self::$tmpDir)->sortByName();
$paths = array(); $paths = array();
@ -450,8 +446,7 @@ class FinderTest extends Iterator\RealIteratorTestCase
public function testCountDirectories() public function testCountDirectories()
{ {
$finder = new Finder(); $directory = Finder::create()->directories()->in(self::$tmpDir);
$directory = $finder->directories()->in(self::$tmpDir);
$i = 0; $i = 0;
foreach ($directory as $dir) { foreach ($directory as $dir) {
@ -463,8 +458,7 @@ class FinderTest extends Iterator\RealIteratorTestCase
public function testCountFiles() public function testCountFiles()
{ {
$finder = new Finder(); $files = Finder::create()->files()->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$files = $finder->files()->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$i = 0; $i = 0;
foreach ($files as $file) { foreach ($files as $file) {
@ -474,17 +468,13 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertCount($i, $files); $this->assertCount($i, $files);
} }
/**
* @expectedException \LogicException
*/
public function testCountWithoutIn() public function testCountWithoutIn()
{ {
$finder = new Finder(); $finder = Finder::create()->files();
$finder->files(); count($finder);
try {
count($finder);
$this->fail('Countable makes use of the getIterator command');
} catch (\Exception $e) {
$this->assertInstanceOf('LogicException', $e, '->getIterator() throws \LogicException when no logic has been entered');
}
} }
protected function toAbsolute($files) protected function toAbsolute($files)
@ -641,37 +631,10 @@ class FinderTest extends Iterator\RealIteratorTestCase
return $this->buildTestData($tests); return $this->buildTestData($tests);
} }
private function buildFinder(Adapter\AdapterInterface $adapter)
{
return Finder::create()
->removeAdapters()
->addAdapter($adapter);
}
private function getValidAdapters()
{
return array_filter(
array(new Adapter\GnuFindAdapter(), new Adapter\PhpAdapter()),
function (Adapter\AdapterInterface $adapter) { return $adapter->isSupported(); }
);
}
private function buildTestData(array $tests)
{
$data = array();
foreach ($this->getValidAdapters() as $adapter) {
foreach ($tests as $test) {
$data[] = array_merge(array($adapter), $test);
}
}
return $data;
}
/** /**
* @dataProvider getTestPathData * @dataProvider getTestPathData
*/ */
public function testPath(Adapter\AdapterInterface $adapter, $matchPatterns, $noMatchPatterns, $expected) public function testPath(Adapter\AdapterInterface $adapter, $matchPatterns, $noMatchPatterns, array $expected)
{ {
$finder = $this->buildFinder($adapter); $finder = $this->buildFinder($adapter);
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures') $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
@ -722,4 +685,37 @@ class FinderTest extends Iterator\RealIteratorTestCase
return $this->buildTestData($tests); return $this->buildTestData($tests);
} }
private function buildTestData(array $tests)
{
$data = array();
foreach ($this->getValidAdapters() as $adapter) {
foreach ($tests as $test) {
$data[] = array_merge(array($adapter), $test);
}
}
return $data;
}
private function buildFinder(Adapter\AdapterInterface $adapter)
{
return Finder::create()
->removeAdapters()
->addAdapter($adapter);
}
private function getValidAdapters()
{
return array_filter(
array(
new Adapter\BsdFindAdapter(),
new Adapter\GnuFindAdapter(),
new Adapter\PhpAdapter()
),
function (Adapter\AdapterInterface $adapter) {
return $adapter->isSupported();
}
);
}
} }