update v 1.0.7.5

This commit is contained in:
Sujit Prasad
2016-06-13 20:41:55 +05:30
parent aa9786d829
commit 283d97e3ea
5078 changed files with 339851 additions and 175995 deletions

View File

@@ -1,6 +1,16 @@
CHANGELOG
=========
3.0.0
-----
* removed deprecated classes
2.8.0
-----
* deprecated adapters and related classes
2.5.0
-----
* added support for GLOB_BRACE in the paths passed to Finder::in()

View File

@@ -11,13 +11,8 @@
namespace Symfony\Component\Finder;
use Symfony\Component\Finder\Adapter\AdapterInterface;
use Symfony\Component\Finder\Adapter\GnuFindAdapter;
use Symfony\Component\Finder\Adapter\BsdFindAdapter;
use Symfony\Component\Finder\Adapter\PhpAdapter;
use Symfony\Component\Finder\Comparator\DateComparator;
use Symfony\Component\Finder\Comparator\NumberComparator;
use Symfony\Component\Finder\Exception\ExceptionInterface;
use Symfony\Component\Finder\Iterator\CustomFilterIterator;
use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
@@ -39,8 +34,6 @@ use Symfony\Component\Finder\Iterator\SortableIterator;
* $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Finder implements \IteratorAggregate, \Countable
{
@@ -62,7 +55,6 @@ class Finder implements \IteratorAggregate, \Countable
private $iterators = array();
private $contains = array();
private $notContains = array();
private $adapters = array();
private $paths = array();
private $notPaths = array();
private $ignoreUnreadableDirs = false;
@@ -75,109 +67,22 @@ class Finder implements \IteratorAggregate, \Countable
public function __construct()
{
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
$this
->addAdapter(new GnuFindAdapter())
->addAdapter(new BsdFindAdapter())
->addAdapter(new PhpAdapter(), -50)
->setAdapter('php')
;
}
/**
* Creates a new Finder.
*
* @return Finder A new Finder instance
*
* @api
*/
public static function create()
{
return new static();
}
/**
* Registers a finder engine implementation.
*
* @param AdapterInterface $adapter An adapter instance
* @param int $priority Highest is selected first
*
* @return Finder The current Finder instance
*/
public function addAdapter(AdapterInterface $adapter, $priority = 0)
{
$this->adapters[$adapter->getName()] = array(
'adapter' => $adapter,
'priority' => $priority,
'selected' => false,
);
return $this->sortAdapters();
}
/**
* Sets the selected adapter to the best one according to the current platform the code is run on.
*
* @return Finder The current Finder instance
*/
public function useBestAdapter()
{
$this->resetAdapterSelection();
return $this->sortAdapters();
}
/**
* Selects the adapter to use.
*
* @param string $name
*
* @throws \InvalidArgumentException
*
* @return Finder The current Finder instance
*/
public function setAdapter($name)
{
if (!isset($this->adapters[$name])) {
throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
}
$this->resetAdapterSelection();
$this->adapters[$name]['selected'] = true;
return $this->sortAdapters();
}
/**
* Removes all adapters registered in the finder.
*
* @return Finder The current Finder instance
*/
public function removeAdapters()
{
$this->adapters = array();
return $this;
}
/**
* Returns registered adapters ordered by priority without extra information.
*
* @return AdapterInterface[]
*/
public function getAdapters()
{
return array_values(array_map(function (array $adapter) {
return $adapter['adapter'];
}, $this->adapters));
}
/**
* Restricts the matching to directories only.
*
* @return Finder The current Finder instance
*
* @api
* @return Finder|SplFileInfo[] The current Finder instance
*/
public function directories()
{
@@ -189,9 +94,7 @@ class Finder implements \IteratorAggregate, \Countable
/**
* Restricts the matching to files only.
*
* @return Finder The current Finder instance
*
* @api
* @return Finder|SplFileInfo[] The current Finder instance
*/
public function files()
{
@@ -210,12 +113,10 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param int $level The depth level expression
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see DepthRangeFilterIterator
* @see NumberComparator
*
* @api
*/
public function depth($level)
{
@@ -236,13 +137,11 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $date A date range string
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see strtotime
* @see DateRangeFilterIterator
* @see DateComparator
*
* @api
*/
public function date($date)
{
@@ -262,11 +161,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $pattern A pattern (a regexp, a glob, or a string)
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see FilenameFilterIterator
*
* @api
*/
public function name($pattern)
{
@@ -280,11 +177,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $pattern A pattern (a regexp, a glob, or a string)
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see FilenameFilterIterator
*
* @api
*/
public function notName($pattern)
{
@@ -303,7 +198,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $pattern A pattern (string or regexp)
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see FilecontentFilterIterator
*/
@@ -324,7 +219,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $pattern A pattern (string or regexp)
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see FilecontentFilterIterator
*/
@@ -347,7 +242,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $pattern A pattern (a regexp or a string)
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see FilenameFilterIterator
*/
@@ -370,7 +265,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $pattern A pattern (a regexp or a string)
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see FilenameFilterIterator
*/
@@ -390,12 +285,10 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string $size A size range string
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see SizeRangeFilterIterator
* @see NumberComparator
*
* @api
*/
public function size($size)
{
@@ -409,11 +302,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string|array $dirs A directory path or an array of directories
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see ExcludeDirectoryFilterIterator
*
* @api
*/
public function exclude($dirs)
{
@@ -427,11 +318,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param bool $ignoreDotFiles Whether to exclude "hidden" files or not
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see ExcludeDirectoryFilterIterator
*
* @api
*/
public function ignoreDotFiles($ignoreDotFiles)
{
@@ -449,11 +338,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param bool $ignoreVCS Whether to exclude VCS files or not
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see ExcludeDirectoryFilterIterator
*
* @api
*/
public function ignoreVCS($ignoreVCS)
{
@@ -491,11 +378,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param \Closure $closure An anonymous function
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see SortableIterator
*
* @api
*/
public function sort(\Closure $closure)
{
@@ -509,11 +394,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see SortableIterator
*
* @api
*/
public function sortByName()
{
@@ -527,11 +410,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see SortableIterator
*
* @api
*/
public function sortByType()
{
@@ -547,11 +428,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see SortableIterator
*
* @api
*/
public function sortByAccessedTime()
{
@@ -569,11 +448,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see SortableIterator
*
* @api
*/
public function sortByChangedTime()
{
@@ -589,11 +466,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* This can be slow as all the matching files and directories must be retrieved for comparison.
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see SortableIterator
*
* @api
*/
public function sortByModifiedTime()
{
@@ -610,11 +485,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param \Closure $closure An anonymous function
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @see CustomFilterIterator
*
* @api
*/
public function filter(\Closure $closure)
{
@@ -626,9 +499,7 @@ class Finder implements \IteratorAggregate, \Countable
/**
* Forces the following of symlinks.
*
* @return Finder The current Finder instance
*
* @api
* @return Finder|SplFileInfo[] The current Finder instance
*/
public function followLinks()
{
@@ -644,7 +515,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param bool $ignore
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*/
public function ignoreUnreadableDirs($ignore = true)
{
@@ -658,11 +529,9 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param string|array $dirs A directory path or an array of directories
*
* @return Finder The current Finder instance
* @return Finder|SplFileInfo[] The current Finder instance
*
* @throws \InvalidArgumentException if one of the directories does not exist
*
* @api
*/
public function in($dirs)
{
@@ -721,7 +590,7 @@ class Finder implements \IteratorAggregate, \Countable
*
* @param mixed $iterator
*
* @return Finder The finder
* @return Finder|SplFileInfo[] The finder
*
* @throws \InvalidArgumentException When the given argument is not iterable.
*/
@@ -754,28 +623,10 @@ class Finder implements \IteratorAggregate, \Countable
return iterator_count($this->getIterator());
}
/**
* @return Finder The current Finder instance
*/
private function sortAdapters()
{
uasort($this->adapters, function (array $a, array $b) {
if ($a['selected'] || $b['selected']) {
return $a['selected'] ? -1 : 1;
}
return $a['priority'] > $b['priority'] ? -1 : 1;
});
return $this;
}
/**
* @param $dir
*
* @return \Iterator
*
* @throws \RuntimeException When none of the adapters are supported
*/
private function searchInDirectory($dir)
{
@@ -787,54 +638,79 @@ class Finder implements \IteratorAggregate, \Countable
$this->notPaths[] = '#(^|/)\..+(/|$)#';
}
foreach ($this->adapters as $adapter) {
if ($adapter['adapter']->isSupported()) {
try {
return $this
->buildAdapter($adapter['adapter'])
->searchInDirectory($dir);
} catch (ExceptionInterface $e) {
}
$minDepth = 0;
$maxDepth = PHP_INT_MAX;
foreach ($this->depths as $comparator) {
switch ($comparator->getOperator()) {
case '>':
$minDepth = $comparator->getTarget() + 1;
break;
case '>=':
$minDepth = $comparator->getTarget();
break;
case '<':
$maxDepth = $comparator->getTarget() - 1;
break;
case '<=':
$maxDepth = $comparator->getTarget();
break;
default:
$minDepth = $maxDepth = $comparator->getTarget();
}
}
throw new \RuntimeException('No supported adapter found.');
}
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
/**
* @param AdapterInterface $adapter
*
* @return AdapterInterface
*/
private function buildAdapter(AdapterInterface $adapter)
{
return $adapter
->setFollowLinks($this->followLinks)
->setDepths($this->depths)
->setMode($this->mode)
->setExclude($this->exclude)
->setNames($this->names)
->setNotNames($this->notNames)
->setContains($this->contains)
->setNotContains($this->notContains)
->setSizes($this->sizes)
->setDates($this->dates)
->setFilters($this->filters)
->setSort($this->sort)
->setPath($this->paths)
->setNotPath($this->notPaths)
->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
}
if ($this->followLinks) {
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
}
/**
* Unselects all adapters.
*/
private function resetAdapterSelection()
{
$this->adapters = array_map(function (array $properties) {
$properties['selected'] = false;
$iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
return $properties;
}, $this->adapters);
if ($this->exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
}
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
}
if ($this->mode) {
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
}
if ($this->names || $this->notNames) {
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
}
if ($this->contains || $this->notContains) {
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
}
if ($this->sizes) {
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
}
if ($this->dates) {
$iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
}
if ($this->filters) {
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
}
if ($this->paths || $this->notPaths) {
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
}
if ($this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}
return $iterator;
}
}

View File

@@ -41,10 +41,11 @@ class Glob
* @param string $glob The glob pattern
* @param bool $strictLeadingDot
* @param bool $strictWildcardSlash
* @param string $delimiter Optional delimiter
*
* @return string regex The regexp
*/
public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true)
public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
{
$firstByte = true;
$escaping = false;
@@ -65,7 +66,7 @@ class Glob
$firstByte = true;
}
if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
$regex .= "\\$car";
} elseif ('*' === $car) {
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
@@ -98,6 +99,6 @@ class Glob
$escaping = false;
}
return '#^'.$regex.'$#';
return $delimiter.'^'.$regex.'$'.$delimiter;
}
}

View File

@@ -26,8 +26,8 @@ class CustomFilterIterator extends FilterIterator
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $filters An array of PHP callbacks
* @param \Iterator $iterator The Iterator to filter
* @param callable[] $filters An array of PHP callbacks
*
* @throws \InvalidArgumentException
*/

View File

@@ -0,0 +1,85 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* ExcludeDirectoryFilterIterator filters out directories.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
{
private $iterator;
private $isRecursive;
private $excludedDirs = array();
private $excludedPattern;
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $directories An array of directories to exclude
*/
public function __construct(\Iterator $iterator, array $directories)
{
$this->iterator = $iterator;
$this->isRecursive = $iterator instanceof \RecursiveIterator;
$patterns = array();
foreach ($directories as $directory) {
if (!$this->isRecursive || false !== strpos($directory, '/')) {
$patterns[] = preg_quote($directory, '#');
} else {
$this->excludedDirs[$directory] = true;
}
}
if ($patterns) {
$this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
}
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return bool true if the value should be kept, false otherwise
*/
public function accept()
{
if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
return false;
}
if ($this->excludedPattern) {
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
$path = str_replace('\\', '/', $path);
return !preg_match($this->excludedPattern, $path);
}
return true;
}
public function hasChildren()
{
return $this->isRecursive && $this->iterator->hasChildren();
}
public function getChildren()
{
$children = new self($this->iterator->getChildren(), array());
$children->excludedDirs = $this->excludedDirs;
$children->excludedPattern = $this->excludedPattern;
return $children;
}
}

View File

@@ -41,25 +41,7 @@ class FilecontentFilterIterator extends MultiplePcreFilterIterator
return false;
}
// should at least not match one rule to exclude
foreach ($this->noMatchRegexps as $regex) {
if (preg_match($regex, $content)) {
return false;
}
}
// should at least match one rule
$match = true;
if ($this->matchRegexps) {
$match = false;
foreach ($this->matchRegexps as $regex) {
if (preg_match($regex, $content)) {
return true;
}
}
}
return $match;
return $this->isAccepted($content);
}
/**

View File

@@ -11,7 +11,7 @@
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Expression\Expression;
use Symfony\Component\Finder\Glob;
/**
* FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
@@ -27,27 +27,7 @@ class FilenameFilterIterator extends MultiplePcreFilterIterator
*/
public function accept()
{
$filename = $this->current()->getFilename();
// should at least not match one rule to exclude
foreach ($this->noMatchRegexps as $regex) {
if (preg_match($regex, $filename)) {
return false;
}
}
// should at least match one rule
$match = true;
if ($this->matchRegexps) {
$match = false;
foreach ($this->matchRegexps as $regex) {
if (preg_match($regex, $filename)) {
return true;
}
}
}
return $match;
return $this->isAccepted($this->current()->getFilename());
}
/**
@@ -62,6 +42,6 @@ class FilenameFilterIterator extends MultiplePcreFilterIterator
*/
protected function toRegex($str)
{
return Expression::create($str)->getRegex()->render();
return $this->isRegex($str) ? $str : Glob::toRegex($str);
}
}

View File

@@ -12,9 +12,10 @@
namespace Symfony\Component\Finder\Iterator;
/**
* This iterator just overrides the rewind method in order to correct a PHP bug.
* This iterator just overrides the rewind method in order to correct a PHP bug,
* which existed before version 5.5.23/5.6.7.
*
* @see https://bugs.php.net/bug.php?id=49104
* @see https://bugs.php.net/68557
*
* @author Alex Bogomazov
*/
@@ -28,20 +29,28 @@ abstract class FilterIterator extends \FilterIterator
*/
public function rewind()
{
if (PHP_VERSION_ID > 50607 || (PHP_VERSION_ID > 50523 && PHP_VERSION_ID < 50600)) {
parent::rewind();
return;
}
$iterator = $this;
while ($iterator instanceof \OuterIterator) {
$innerIterator = $iterator->getInnerIterator();
if ($innerIterator instanceof RecursiveDirectoryIterator) {
// this condition is necessary for iterators to work properly with non-local filesystems like ftp
if ($innerIterator->isRewindable()) {
$innerIterator->next();
$innerIterator->rewind();
}
} elseif ($iterator->getInnerIterator() instanceof \FilesystemIterator) {
$iterator->getInnerIterator()->next();
$iterator->getInnerIterator()->rewind();
} elseif ($innerIterator instanceof \FilesystemIterator) {
$innerIterator->next();
$innerIterator->rewind();
}
$iterator = $iterator->getInnerIterator();
$iterator = $innerIterator;
}
parent::rewind();

View File

@@ -11,8 +11,6 @@
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Expression\Expression;
/**
* MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
*
@@ -43,6 +41,41 @@ abstract class MultiplePcreFilterIterator extends FilterIterator
parent::__construct($iterator);
}
/**
* Checks whether the string is accepted by the regex filters.
*
* If there is no regexps defined in the class, this method will accept the string.
* Such case can be handled by child classes before calling the method if they want to
* apply a different behavior.
*
* @param string $string The string to be matched against filters
*
* @return bool
*/
protected function isAccepted($string)
{
// should at least not match one rule to exclude
foreach ($this->noMatchRegexps as $regex) {
if (preg_match($regex, $string)) {
return false;
}
}
// should at least match one rule
if ($this->matchRegexps) {
foreach ($this->matchRegexps as $regex) {
if (preg_match($regex, $string)) {
return true;
}
}
return false;
}
// If there is no match rules, the file is accepted
return true;
}
/**
* Checks whether the string is a regex.
*
@@ -52,7 +85,22 @@ abstract class MultiplePcreFilterIterator extends FilterIterator
*/
protected function isRegex($str)
{
return Expression::create($str)->isRegex();
if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
$start = substr($m[1], 0, 1);
$end = substr($m[1], -1);
if ($start === $end) {
return !preg_match('/[*?[:alnum:] \\\\]/', $start);
}
foreach (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
if ($start === $delimiters[0] && $end === $delimiters[1]) {
return true;
}
}
}
return false;
}
/**

View File

@@ -29,28 +29,10 @@ class PathFilterIterator extends MultiplePcreFilterIterator
$filename = $this->current()->getRelativePathname();
if ('\\' === DIRECTORY_SEPARATOR) {
$filename = strtr($filename, '\\', '/');
$filename = str_replace('\\', '/', $filename);
}
// should at least not match one rule to exclude
foreach ($this->noMatchRegexps as $regex) {
if (preg_match($regex, $filename)) {
return false;
}
}
// should at least match one rule
$match = true;
if ($this->matchRegexps) {
$match = false;
foreach ($this->matchRegexps as $regex) {
if (preg_match($regex, $filename)) {
return true;
}
}
}
return $match;
return $this->isAccepted($filename);
}
/**

View File

@@ -31,6 +31,11 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
*/
private $rewindable;
// these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
private $rootPath;
private $subPath;
private $directorySeparator = '/';
/**
* Constructor.
*
@@ -48,6 +53,10 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
parent::__construct($path, $flags);
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
$this->rootPath = $path;
if ('/' !== DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
$this->directorySeparator = DIRECTORY_SEPARATOR;
}
}
/**
@@ -57,7 +66,17 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
*/
public function current()
{
return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
// the logic here avoids redoing the same work in all iterations
if (null === $subPathname = $this->subPath) {
$subPathname = $this->subPath = (string) $this->getSubPath();
}
if ('' !== $subPathname) {
$subPathname .= $this->directorySeparator;
}
$subPathname .= $this->getFilename();
return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname);
}
/**
@@ -73,6 +92,10 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
if ($children instanceof self) {
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
// performance optimization to avoid redoing the same work in all children
$children->rewindable = &$this->rewindable;
$children->rootPath = $this->rootPath;
}
return $children;
@@ -95,8 +118,10 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
return;
}
// @see https://bugs.php.net/bug.php?id=49104
parent::next();
// @see https://bugs.php.net/68557
if (PHP_VERSION_ID < 50523 || PHP_VERSION_ID >= 50600 && PHP_VERSION_ID < 50607) {
parent::next();
}
parent::rewind();
}

View File

@@ -55,15 +55,15 @@ class SortableIterator implements \IteratorAggregate
};
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
$this->sort = function ($a, $b) {
return ($a->getATime() - $b->getATime());
return $a->getATime() - $b->getATime();
};
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
$this->sort = function ($a, $b) {
return ($a->getCTime() - $b->getCTime());
return $a->getCTime() - $b->getCTime();
};
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
$this->sort = function ($a, $b) {
return ($a->getMTime() - $b->getMTime());
return $a->getMTime() - $b->getMTime();
};
} elseif (is_callable($sort)) {
$this->sort = $sort;

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

14
vendor/symfony/finder/README.md vendored Normal file
View File

@@ -0,0 +1,14 @@
Finder Component
================
The Finder component finds files and directories via an intuitive fluent
interface.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/finder.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -38,6 +38,8 @@ class SplFileInfo extends \SplFileInfo
/**
* Returns the relative path.
*
* This path does not contain the file name.
*
* @return string the relative path
*/
public function getRelativePath()
@@ -48,6 +50,8 @@ class SplFileInfo extends \SplFileInfo
/**
* Returns the relative path name.
*
* This path contains the file name.
*
* @return string the relative path name
*/
public function getRelativePathname()

View File

@@ -1,236 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Adapter;
/**
* Interface for finder engine implementations.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
abstract class AbstractAdapter implements AdapterInterface
{
protected $followLinks = false;
protected $mode = 0;
protected $minDepth = 0;
protected $maxDepth = PHP_INT_MAX;
protected $exclude = array();
protected $names = array();
protected $notNames = array();
protected $contains = array();
protected $notContains = array();
protected $sizes = array();
protected $dates = array();
protected $filters = array();
protected $sort = false;
protected $paths = array();
protected $notPaths = array();
protected $ignoreUnreadableDirs = false;
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}
*/
public function setFollowLinks($followLinks)
{
$this->followLinks = $followLinks;
return $this;
}
/**
* {@inheritdoc}
*/
public function setMode($mode)
{
$this->mode = $mode;
return $this;
}
/**
* {@inheritdoc}
*/
public function setDepths(array $depths)
{
$this->minDepth = 0;
$this->maxDepth = PHP_INT_MAX;
foreach ($depths as $comparator) {
switch ($comparator->getOperator()) {
case '>':
$this->minDepth = $comparator->getTarget() + 1;
break;
case '>=':
$this->minDepth = $comparator->getTarget();
break;
case '<':
$this->maxDepth = $comparator->getTarget() - 1;
break;
case '<=':
$this->maxDepth = $comparator->getTarget();
break;
default:
$this->minDepth = $this->maxDepth = $comparator->getTarget();
}
}
return $this;
}
/**
* {@inheritdoc}
*/
public function setExclude(array $exclude)
{
$this->exclude = $exclude;
return $this;
}
/**
* {@inheritdoc}
*/
public function setNames(array $names)
{
$this->names = $names;
return $this;
}
/**
* {@inheritdoc}
*/
public function setNotNames(array $notNames)
{
$this->notNames = $notNames;
return $this;
}
/**
* {@inheritdoc}
*/
public function setContains(array $contains)
{
$this->contains = $contains;
return $this;
}
/**
* {@inheritdoc}
*/
public function setNotContains(array $notContains)
{
$this->notContains = $notContains;
return $this;
}
/**
* {@inheritdoc}
*/
public function setSizes(array $sizes)
{
$this->sizes = $sizes;
return $this;
}
/**
* {@inheritdoc}
*/
public function setDates(array $dates)
{
$this->dates = $dates;
return $this;
}
/**
* {@inheritdoc}
*/
public function setFilters(array $filters)
{
$this->filters = $filters;
return $this;
}
/**
* {@inheritdoc}
*/
public function setSort($sort)
{
$this->sort = $sort;
return $this;
}
/**
* {@inheritdoc}
*/
public function setPath(array $paths)
{
$this->paths = $paths;
return $this;
}
/**
* {@inheritdoc}
*/
public function setNotPath(array $notPaths)
{
$this->notPaths = $notPaths;
return $this;
}
/**
* {@inheritdoc}
*/
public function ignoreUnreadableDirs($ignore = true)
{
$this->ignoreUnreadableDirs = (bool) $ignore;
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 bool Whether the adapter is supported
*/
abstract protected function canBeUsed();
}

View File

@@ -1,327 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Adapter;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Shell\Shell;
use Symfony\Component\Finder\Expression\Expression;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Comparator\NumberComparator;
use Symfony\Component\Finder\Comparator\DateComparator;
/**
* Shell engine implementation using GNU find command.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
abstract class AbstractFindAdapter extends AbstractAdapter
{
/**
* @var Shell
*/
protected $shell;
/**
* Constructor.
*/
public function __construct()
{
$this->shell = new Shell();
}
/**
* {@inheritdoc}
*/
public function searchInDirectory($dir)
{
// having "/../" in path make find fail
$dir = realpath($dir);
// searching directories containing or not containing strings leads to no result
if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
return new Iterator\FilePathsIterator(array(), $dir);
}
$command = Command::create();
$find = $this->buildFindCommand($command, $dir);
if ($this->followLinks) {
$find->add('-follow');
}
$find->add('-mindepth')->add($this->minDepth + 1);
if (PHP_INT_MAX !== $this->maxDepth) {
$find->add('-maxdepth')->add($this->maxDepth + 1);
}
if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
$find->add('-type d');
} elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
$find->add('-type f');
}
$this->buildNamesFiltering($find, $this->names);
$this->buildNamesFiltering($find, $this->notNames, true);
$this->buildPathsFiltering($find, $dir, $this->paths);
$this->buildPathsFiltering($find, $dir, $this->notPaths, true);
$this->buildSizesFiltering($find, $this->sizes);
$this->buildDatesFiltering($find, $this->dates);
$useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
$useSort = is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
if ($useGrep && ($this->contains || $this->notContains)) {
$grep = $command->ins('grep');
$this->buildContentFiltering($grep, $this->contains);
$this->buildContentFiltering($grep, $this->notContains, true);
}
if ($useSort) {
$this->buildSorting($command, $this->sort);
}
$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);
if ($this->exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
}
if (!$useGrep && ($this->contains || $this->notContains)) {
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
}
if ($this->filters) {
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
}
if (!$useSort && $this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}
return $iterator;
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return $this->shell->testCommand('find');
}
/**
* @param Command $command
* @param string $dir
*
* @return Command
*/
protected function buildFindCommand(Command $command, $dir)
{
return $command
->ins('find')
->add('find ')
->arg($dir)
->add('-noleaf'); // the -noleaf option is required for filesystems that don't follow the '.' and '..' conventions
}
/**
* @param Command $command
* @param string[] $names
* @param bool $not
*/
private function buildNamesFiltering(Command $command, array $names, $not = false)
{
if (0 === count($names)) {
return;
}
$command->add($not ? '-not' : null)->cmd('(');
foreach ($names as $i => $name) {
$expr = Expression::create($name);
// Find does not support expandable globs ("*.{a,b}" syntax).
if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
$expr = Expression::create($expr->getGlob()->toRegex(false));
}
// Fixes 'not search' and 'full path matching' regex problems.
// - Jokers '.' are replaced by [^/].
// - We add '[^/]*' before and after regex (if no ^|$ flags are present).
if ($expr->isRegex()) {
$regex = $expr->getRegex();
$regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
->setStartFlag(false)
->setStartJoker(true)
->replaceJokers('[^/]');
if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
$regex->setEndJoker(false)->append('[^/]*');
}
}
$command
->add($i > 0 ? '-or' : null)
->add($expr->isRegex()
? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
: ($expr->isCaseSensitive() ? '-name' : '-iname')
)
->arg($expr->renderPattern());
}
$command->cmd(')');
}
/**
* @param Command $command
* @param string $dir
* @param string[] $paths
* @param bool $not
*/
private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
{
if (0 === count($paths)) {
return;
}
$command->add($not ? '-not' : null)->cmd('(');
foreach ($paths as $i => $path) {
$expr = Expression::create($path);
// Find does not support expandable globs ("*.{a,b}" syntax).
if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
$expr = Expression::create($expr->getGlob()->toRegex(false));
}
// Fixes 'not search' regex problems.
if ($expr->isRegex()) {
$regex = $expr->getRegex();
$regex->prepend($regex->hasStartFlag() ? preg_quote($dir).DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
} else {
$expr->prepend('*')->append('*');
}
$command
->add($i > 0 ? '-or' : null)
->add($expr->isRegex()
? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
: ($expr->isCaseSensitive() ? '-path' : '-ipath')
)
->arg($expr->renderPattern());
}
$command->cmd(')');
}
/**
* @param Command $command
* @param NumberComparator[] $sizes
*/
private function buildSizesFiltering(Command $command, array $sizes)
{
foreach ($sizes as $i => $size) {
$command->add($i > 0 ? '-and' : null);
switch ($size->getOperator()) {
case '<=':
$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');
break;
case '<':
default:
$command->add('-size -'.$size->getTarget().'c');
}
}
}
/**
* @param Command $command
* @param DateComparator[] $dates
*/
private function buildDatesFiltering(Command $command, array $dates)
{
foreach ($dates as $i => $date) {
$command->add($i > 0 ? '-and' : null);
$mins = (int) round((time() - $date->getTarget()) / 60);
if (0 > $mins) {
// mtime is in the future
$command->add(' -mmin -0');
// we will have no result so we don't need to continue
return;
}
switch ($date->getOperator()) {
case '<=':
$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);
}
}
}
/**
* @param Command $command
* @param string $sort
*
* @throws \InvalidArgumentException
*/
private function buildSorting(Command $command, $sort)
{
$this->buildFormatSorting($command, $sort);
}
/**
* @param Command $command
* @param string $sort
*/
abstract protected function buildFormatSorting(Command $command, $sort);
/**
* @param Command $command
* @param array $contains
* @param bool $not
*/
abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
}

View File

@@ -1,144 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Adapter;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
interface AdapterInterface
{
/**
* @param bool $followLinks
*
* @return AdapterInterface Current instance
*/
public function setFollowLinks($followLinks);
/**
* @param int $mode
*
* @return AdapterInterface Current instance
*/
public function setMode($mode);
/**
* @param array $exclude
*
* @return AdapterInterface Current instance
*/
public function setExclude(array $exclude);
/**
* @param array $depths
*
* @return AdapterInterface Current instance
*/
public function setDepths(array $depths);
/**
* @param array $names
*
* @return AdapterInterface Current instance
*/
public function setNames(array $names);
/**
* @param array $notNames
*
* @return AdapterInterface Current instance
*/
public function setNotNames(array $notNames);
/**
* @param array $contains
*
* @return AdapterInterface Current instance
*/
public function setContains(array $contains);
/**
* @param array $notContains
*
* @return AdapterInterface Current instance
*/
public function setNotContains(array $notContains);
/**
* @param array $sizes
*
* @return AdapterInterface Current instance
*/
public function setSizes(array $sizes);
/**
* @param array $dates
*
* @return AdapterInterface Current instance
*/
public function setDates(array $dates);
/**
* @param array $filters
*
* @return AdapterInterface Current instance
*/
public function setFilters(array $filters);
/**
* @param \Closure|int $sort
*
* @return AdapterInterface Current instance
*/
public function setSort($sort);
/**
* @param array $paths
*
* @return AdapterInterface Current instance
*/
public function setPath(array $paths);
/**
* @param array $notPaths
*
* @return AdapterInterface Current instance
*/
public function setNotPath(array $notPaths);
/**
* @param bool $ignore
*
* @return AdapterInterface Current instance
*/
public function ignoreUnreadableDirs($ignore = true);
/**
* @param string $dir
*
* @return \Iterator Result iterator
*/
public function searchInDirectory($dir);
/**
* Tests adapter support for current platform.
*
* @return bool
*/
public function isSupported();
/**
* Returns adapter name.
*
* @return string
*/
public function getName();
}

View File

@@ -1,103 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Adapter;
use Symfony\Component\Finder\Shell\Shell;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Iterator\SortableIterator;
use Symfony\Component\Finder\Expression\Expression;
/**
* Shell engine implementation using BSD find command.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class BsdFindAdapter extends AbstractFindAdapter
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'bsd_find';
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
}
/**
* {@inheritdoc}
*/
protected function buildFormatSorting(Command $command, $sort)
{
switch ($sort) {
case SortableIterator::SORT_BY_NAME:
$command->ins('sort')->add('| sort');
return;
case SortableIterator::SORT_BY_TYPE:
$format = '%HT';
break;
case SortableIterator::SORT_BY_ACCESSED_TIME:
$format = '%a';
break;
case SortableIterator::SORT_BY_CHANGED_TIME:
$format = '%c';
break;
case SortableIterator::SORT_BY_MODIFIED_TIME:
$format = '%m';
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
}
$command
->add('-print0 | xargs -0 stat -f')
->arg($format.'%t%N')
->add('| sort | cut -f 2');
}
/**
* {@inheritdoc}
*/
protected function buildFindCommand(Command $command, $dir)
{
parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);
return $command;
}
/**
* {@inheritdoc}
*/
protected function buildContentFiltering(Command $command, array $contains, $not = false)
{
foreach ($contains as $contain) {
$expr = Expression::create($contain);
// todo: avoid forking process for each $pattern by using multiple -e options
$command
->add('| grep -v \'^$\'')
->add('| xargs -I{} grep -I')
->add($expr->isCaseSensitive() ? null : '-i')
->add($not ? '-L' : '-l')
->add('-Ee')->arg($expr->renderPattern())
->add('{}')
;
}
}
}

View File

@@ -1,104 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Adapter;
use Symfony\Component\Finder\Shell\Shell;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Iterator\SortableIterator;
use Symfony\Component\Finder\Expression\Expression;
/**
* Shell engine implementation using GNU find command.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class GnuFindAdapter extends AbstractFindAdapter
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'gnu_find';
}
/**
* {@inheritdoc}
*/
protected function buildFormatSorting(Command $command, $sort)
{
switch ($sort) {
case SortableIterator::SORT_BY_NAME:
$command->ins('sort')->add('| sort');
return;
case SortableIterator::SORT_BY_TYPE:
$format = '%y';
break;
case SortableIterator::SORT_BY_ACCESSED_TIME:
$format = '%A@';
break;
case SortableIterator::SORT_BY_CHANGED_TIME:
$format = '%C@';
break;
case SortableIterator::SORT_BY_MODIFIED_TIME:
$format = '%T@';
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
}
$command
->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();
}
/**
* {@inheritdoc}
*/
protected function buildFindCommand(Command $command, $dir)
{
return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
}
/**
* {@inheritdoc}
*/
protected function buildContentFiltering(Command $command, array $contains, $not = false)
{
foreach ($contains as $contain) {
$expr = Expression::create($contain);
// todo: avoid forking process for each $pattern by using multiple -e options
$command
->add('| xargs -I{} -r grep -I')
->add($expr->isCaseSensitive() ? null : '-i')
->add($not ? '-L' : '-l')
->add('-Ee')->arg($expr->renderPattern())
->add('{}')
;
}
}
}

View File

@@ -1,98 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Adapter;
use Symfony\Component\Finder\Iterator;
/**
* PHP finder engine implementation.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class PhpAdapter extends AbstractAdapter
{
/**
* {@inheritdoc}
*/
public function searchInDirectory($dir)
{
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
if ($this->followLinks) {
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
}
$iterator = new \RecursiveIteratorIterator(
new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs),
\RecursiveIteratorIterator::SELF_FIRST
);
if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
}
if ($this->mode) {
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
}
if ($this->exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
}
if ($this->names || $this->notNames) {
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
}
if ($this->contains || $this->notContains) {
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
}
if ($this->sizes) {
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
}
if ($this->dates) {
$iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
}
if ($this->filters) {
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
}
if ($this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}
if ($this->paths || $this->notPaths) {
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
}
return $iterator;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'php';
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return true;
}
}

View File

@@ -1,46 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Exception;
use Symfony\Component\Finder\Adapter\AdapterInterface;
/**
* Base exception for all adapter failures.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class AdapterFailureException extends \RuntimeException implements ExceptionInterface
{
/**
* @var \Symfony\Component\Finder\Adapter\AdapterInterface
*/
private $adapter;
/**
* @param AdapterInterface $adapter
* @param string|null $message
* @param \Exception|null $previous
*/
public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
{
$this->adapter = $adapter;
parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
}
/**
* {@inheritdoc}
*/
public function getAdapter()
{
return $this->adapter;
}
}

View File

@@ -1,19 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Exception;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class OperationNotPermitedException extends AdapterFailureException
{
}

View File

@@ -1,45 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Exception;
use Symfony\Component\Finder\Adapter\AdapterInterface;
use Symfony\Component\Finder\Shell\Command;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class ShellCommandFailureException extends AdapterFailureException
{
/**
* @var Command
*/
private $command;
/**
* @param AdapterInterface $adapter
* @param Command $command
* @param \Exception|null $previous
*/
public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
{
$this->command = $command;
parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
}
/**
* @return Command
*/
public function getCommand()
{
return $this->command;
}
}

View File

@@ -1,146 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Expression;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class Expression implements ValueInterface
{
const TYPE_REGEX = 1;
const TYPE_GLOB = 2;
/**
* @var ValueInterface
*/
private $value;
/**
* @param string $expr
*
* @return Expression
*/
public static function create($expr)
{
return new self($expr);
}
/**
* @param string $expr
*/
public function __construct($expr)
{
try {
$this->value = Regex::create($expr);
} catch (\InvalidArgumentException $e) {
$this->value = new Glob($expr);
}
}
/**
* @return string
*/
public function __toString()
{
return $this->render();
}
/**
* {@inheritdoc}
*/
public function render()
{
return $this->value->render();
}
/**
* {@inheritdoc}
*/
public function renderPattern()
{
return $this->value->renderPattern();
}
/**
* @return bool
*/
public function isCaseSensitive()
{
return $this->value->isCaseSensitive();
}
/**
* @return int
*/
public function getType()
{
return $this->value->getType();
}
/**
* {@inheritdoc}
*/
public function prepend($expr)
{
$this->value->prepend($expr);
return $this;
}
/**
* {@inheritdoc}
*/
public function append($expr)
{
$this->value->append($expr);
return $this;
}
/**
* @return bool
*/
public function isRegex()
{
return self::TYPE_REGEX === $this->value->getType();
}
/**
* @return bool
*/
public function isGlob()
{
return self::TYPE_GLOB === $this->value->getType();
}
/**
* @throws \LogicException
*
* @return Glob
*/
public function getGlob()
{
if (self::TYPE_GLOB !== $this->value->getType()) {
throw new \LogicException('Regex can\'t be transformed to glob.');
}
return $this->value;
}
/**
* @return Regex
*/
public function getRegex()
{
return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
}
}

View File

@@ -1,157 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Expression;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class Glob implements ValueInterface
{
/**
* @var string
*/
private $pattern;
/**
* @param string $pattern
*/
public function __construct($pattern)
{
$this->pattern = $pattern;
}
/**
* {@inheritdoc}
*/
public function render()
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function renderPattern()
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return Expression::TYPE_GLOB;
}
/**
* {@inheritdoc}
*/
public function isCaseSensitive()
{
return true;
}
/**
* {@inheritdoc}
*/
public function prepend($expr)
{
$this->pattern = $expr.$this->pattern;
return $this;
}
/**
* {@inheritdoc}
*/
public function append($expr)
{
$this->pattern .= $expr;
return $this;
}
/**
* Tests if glob is expandable ("*.{a,b}" syntax).
*
* @return bool
*/
public function isExpandable()
{
return false !== strpos($this->pattern, '{')
&& false !== strpos($this->pattern, '}');
}
/**
* @param bool $strictLeadingDot
* @param bool $strictWildcardSlash
*
* @return Regex
*/
public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
{
$firstByte = true;
$escaping = false;
$inCurlies = 0;
$regex = '';
$sizeGlob = strlen($this->pattern);
for ($i = 0; $i < $sizeGlob; ++$i) {
$car = $this->pattern[$i];
if ($firstByte) {
if ($strictLeadingDot && '.' !== $car) {
$regex .= '(?=[^\.])';
}
$firstByte = false;
}
if ('/' === $car) {
$firstByte = true;
}
if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
$regex .= "\\$car";
} elseif ('*' === $car) {
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
} elseif ('?' === $car) {
$regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
} elseif ('{' === $car) {
$regex .= $escaping ? '\\{' : '(';
if (!$escaping) {
++$inCurlies;
}
} elseif ('}' === $car && $inCurlies) {
$regex .= $escaping ? '}' : ')';
if (!$escaping) {
--$inCurlies;
}
} elseif (',' === $car && $inCurlies) {
$regex .= $escaping ? ',' : '|';
} elseif ('\\' === $car) {
if ($escaping) {
$regex .= '\\\\';
$escaping = false;
} else {
$escaping = true;
}
continue;
} else {
$regex .= $car;
}
$escaping = false;
}
return new Regex('^'.$regex.'$');
}
}

View File

@@ -1,321 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Expression;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class Regex implements ValueInterface
{
const START_FLAG = '^';
const END_FLAG = '$';
const BOUNDARY = '~';
const JOKER = '.*';
const ESCAPING = '\\';
/**
* @var string
*/
private $pattern;
/**
* @var array
*/
private $options;
/**
* @var bool
*/
private $startFlag;
/**
* @var bool
*/
private $endFlag;
/**
* @var bool
*/
private $startJoker;
/**
* @var bool
*/
private $endJoker;
/**
* @param string $expr
*
* @return Regex
*
* @throws \InvalidArgumentException
*/
public static function create($expr)
{
if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
$start = substr($m[1], 0, 1);
$end = substr($m[1], -1);
if (
($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
|| ($start === '{' && $end === '}')
|| ($start === '(' && $end === ')')
) {
return new self(substr($m[1], 1, -1), $m[2], $end);
}
}
throw new \InvalidArgumentException('Given expression is not a regex.');
}
/**
* @param string $pattern
* @param string $options
* @param string $delimiter
*/
public function __construct($pattern, $options = '', $delimiter = null)
{
if (null !== $delimiter) {
// removes delimiter escaping
$pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
}
$this->parsePattern($pattern);
$this->options = $options;
}
/**
* @return string
*/
public function __toString()
{
return $this->render();
}
/**
* {@inheritdoc}
*/
public function render()
{
return self::BOUNDARY
.$this->renderPattern()
.self::BOUNDARY
.$this->options;
}
/**
* {@inheritdoc}
*/
public function renderPattern()
{
return ($this->startFlag ? self::START_FLAG : '')
.($this->startJoker ? self::JOKER : '')
.str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
.($this->endJoker ? self::JOKER : '')
.($this->endFlag ? self::END_FLAG : '');
}
/**
* {@inheritdoc}
*/
public function isCaseSensitive()
{
return !$this->hasOption('i');
}
/**
* {@inheritdoc}
*/
public function getType()
{
return Expression::TYPE_REGEX;
}
/**
* {@inheritdoc}
*/
public function prepend($expr)
{
$this->pattern = $expr.$this->pattern;
return $this;
}
/**
* {@inheritdoc}
*/
public function append($expr)
{
$this->pattern .= $expr;
return $this;
}
/**
* @param string $option
*
* @return bool
*/
public function hasOption($option)
{
return false !== strpos($this->options, $option);
}
/**
* @param string $option
*
* @return Regex
*/
public function addOption($option)
{
if (!$this->hasOption($option)) {
$this->options .= $option;
}
return $this;
}
/**
* @param string $option
*
* @return Regex
*/
public function removeOption($option)
{
$this->options = str_replace($option, '', $this->options);
return $this;
}
/**
* @param bool $startFlag
*
* @return Regex
*/
public function setStartFlag($startFlag)
{
$this->startFlag = $startFlag;
return $this;
}
/**
* @return bool
*/
public function hasStartFlag()
{
return $this->startFlag;
}
/**
* @param bool $endFlag
*
* @return Regex
*/
public function setEndFlag($endFlag)
{
$this->endFlag = (bool) $endFlag;
return $this;
}
/**
* @return bool
*/
public function hasEndFlag()
{
return $this->endFlag;
}
/**
* @param bool $startJoker
*
* @return Regex
*/
public function setStartJoker($startJoker)
{
$this->startJoker = $startJoker;
return $this;
}
/**
* @return bool
*/
public function hasStartJoker()
{
return $this->startJoker;
}
/**
* @param bool $endJoker
*
* @return Regex
*/
public function setEndJoker($endJoker)
{
$this->endJoker = (bool) $endJoker;
return $this;
}
/**
* @return bool
*/
public function hasEndJoker()
{
return $this->endJoker;
}
/**
* @param array $replacement
*
* @return Regex
*/
public function replaceJokers($replacement)
{
$replace = function ($subject) use ($replacement) {
$subject = $subject[0];
$replace = 0 === substr_count($subject, '\\') % 2;
return $replace ? str_replace('.', $replacement, $subject) : $subject;
};
$this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);
return $this;
}
/**
* @param string $pattern
*/
private function parsePattern($pattern)
{
if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
$pattern = substr($pattern, 1);
}
if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
$pattern = substr($pattern, 2);
}
if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
$pattern = substr($pattern, 0, -1);
}
if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
$pattern = substr($pattern, 0, -2);
}
$this->pattern = $pattern;
}
}

View File

@@ -1,60 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Expression;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
interface ValueInterface
{
/**
* Renders string representation of expression.
*
* @return string
*/
public function render();
/**
* Renders string representation of pattern.
*
* @return string
*/
public function renderPattern();
/**
* Returns value case sensitivity.
*
* @return bool
*/
public function isCaseSensitive();
/**
* Returns expression type.
*
* @return int
*/
public function getType();
/**
* @param string $expr
*
* @return ValueInterface
*/
public function prepend($expr);
/**
* @param string $expr
*
* @return ValueInterface
*/
public function append($expr);
}

View File

@@ -1,55 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
/**
* ExcludeDirectoryFilterIterator filters out directories.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExcludeDirectoryFilterIterator extends FilterIterator
{
private $patterns = array();
/**
* Constructor.
*
* @param \Iterator $iterator The Iterator to filter
* @param array $directories An array of directories to exclude
*/
public function __construct(\Iterator $iterator, array $directories)
{
foreach ($directories as $directory) {
$this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
}
parent::__construct($iterator);
}
/**
* Filters the iterator values.
*
* @return bool true if the value should be kept, false otherwise
*/
public function accept()
{
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
$path = strtr($path, '\\', '/');
foreach ($this->patterns as $pattern) {
if (preg_match($pattern, $path)) {
return false;
}
}
return true;
}
}

View File

@@ -1,131 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\SplFileInfo;
/**
* Iterate over shell command result.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class FilePathsIterator extends \ArrayIterator
{
/**
* @var string
*/
private $baseDir;
/**
* @var int
*/
private $baseDirLength;
/**
* @var string
*/
private $subPath;
/**
* @var string
*/
private $subPathname;
/**
* @var SplFileInfo
*/
private $current;
/**
* @param array $paths List of paths returned by shell command
* @param string $baseDir Base dir for relative path building
*/
public function __construct(array $paths, $baseDir)
{
$this->baseDir = $baseDir;
$this->baseDirLength = strlen($baseDir);
parent::__construct($paths);
}
/**
* @param string $name
* @param array $arguments
*
* @return mixed
*/
public function __call($name, array $arguments)
{
return call_user_func_array(array($this->current(), $name), $arguments);
}
/**
* Return an instance of SplFileInfo with support for relative paths.
*
* @return SplFileInfo File information
*/
public function current()
{
return $this->current;
}
/**
* @return string
*/
public function key()
{
return $this->current->getPathname();
}
public function next()
{
parent::next();
$this->buildProperties();
}
public function rewind()
{
parent::rewind();
$this->buildProperties();
}
/**
* @return string
*/
public function getSubPath()
{
return $this->subPath;
}
/**
* @return string
*/
public function getSubPathname()
{
return $this->subPathname;
}
private function buildProperties()
{
$absolutePath = parent::current();
if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
$this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
$dir = dirname($this->subPathname);
$this->subPath = '.' === $dir ? '' : $dir;
} else {
$this->subPath = $this->subPathname = '';
}
$this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
}
}

View File

@@ -1,53 +0,0 @@
Finder Component
================
Finder finds files and directories via an intuitive fluent interface.
```php
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$iterator = $finder
->files()
->name('*.php')
->depth(0)
->size('>= 1K')
->in(__DIR__);
foreach ($iterator as $file) {
print $file->getRealpath()."\n";
}
```
The iterator returns instances of [Symfony\Component\Finder\SplFileInfo\SplFileInfo][1].
Besides the build-in methods inherited from [\SplFileInfo][2] (`getPerms()`, `getSize()`, ...),
you can also use `getRelativePath()` and `getRelativePathname()`. Read the
[official documentation][3] for more information.
But you can also use it to find files stored remotely like in this example where
we are looking for files on Amazon S3:
```php
$s3 = new \Zend_Service_Amazon_S3($key, $secret);
$s3->registerStreamWrapper("s3");
$finder = new Finder();
$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
foreach ($finder->in('s3://bucket-name') as $file) {
print $file->getFilename()."\n";
}
```
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/Finder/
$ composer install
$ phpunit
[1]: http://api.symfony.com/2.5/Symfony/Component/Finder/SplFileInfo.html
[2]: http://php.net/splfileinfo
[3]: https://symfony.com/doc/current/components/finder.html#usage

View File

@@ -1,294 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Shell;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class Command
{
/**
* @var Command|null
*/
private $parent;
/**
* @var array
*/
private $bits = array();
/**
* @var array
*/
private $labels = array();
/**
* @var \Closure|null
*/
private $errorHandler;
/**
* Constructor.
*
* @param Command|null $parent Parent command
*/
public function __construct(Command $parent = null)
{
$this->parent = $parent;
}
/**
* Returns command as string.
*
* @return string
*/
public function __toString()
{
return $this->join();
}
/**
* Creates a new Command instance.
*
* @param Command|null $parent Parent command
*
* @return Command New Command instance
*/
public static function create(Command $parent = null)
{
return new self($parent);
}
/**
* Escapes special chars from input.
*
* @param string $input A string to escape
*
* @return string The escaped string
*/
public static function escape($input)
{
return escapeshellcmd($input);
}
/**
* Quotes input.
*
* @param string $input An argument string
*
* @return string The quoted string
*/
public static function quote($input)
{
return escapeshellarg($input);
}
/**
* Appends a string or a Command instance.
*
* @param string|Command $bit
*
* @return Command The current Command instance
*/
public function add($bit)
{
$this->bits[] = $bit;
return $this;
}
/**
* Prepends a string or a command instance.
*
* @param string|Command $bit
*
* @return Command The current Command instance
*/
public function top($bit)
{
array_unshift($this->bits, $bit);
foreach ($this->labels as $label => $index) {
$this->labels[$label] += 1;
}
return $this;
}
/**
* Appends an argument, will be quoted.
*
* @param string $arg
*
* @return Command The current Command instance
*/
public function arg($arg)
{
$this->bits[] = self::quote($arg);
return $this;
}
/**
* Appends escaped special command chars.
*
* @param string $esc
*
* @return Command The current Command instance
*/
public function cmd($esc)
{
$this->bits[] = self::escape($esc);
return $this;
}
/**
* Inserts a labeled command to feed later.
*
* @param string $label The unique label
*
* @return Command The current Command instance
*
* @throws \RuntimeException If label already exists
*/
public function ins($label)
{
if (isset($this->labels[$label])) {
throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
}
$this->bits[] = self::create($this);
$this->labels[$label] = count($this->bits) - 1;
return $this->bits[$this->labels[$label]];
}
/**
* Retrieves a previously labeled command.
*
* @param string $label
*
* @return Command The labeled command
*
* @throws \RuntimeException
*/
public function get($label)
{
if (!isset($this->labels[$label])) {
throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
}
return $this->bits[$this->labels[$label]];
}
/**
* Returns parent command (if any).
*
* @return Command Parent command
*
* @throws \RuntimeException If command has no parent
*/
public function end()
{
if (null === $this->parent) {
throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
}
return $this->parent;
}
/**
* Counts bits stored in command.
*
* @return int The bits count
*/
public function length()
{
return count($this->bits);
}
/**
* @param \Closure $errorHandler
*
* @return Command
*/
public function setErrorHandler(\Closure $errorHandler)
{
$this->errorHandler = $errorHandler;
return $this;
}
/**
* @return \Closure|null
*/
public function getErrorHandler()
{
return $this->errorHandler;
}
/**
* Executes current command.
*
* @return array The command result
*
* @throws \RuntimeException
*/
public function execute()
{
if (null === $errorHandler = $this->errorHandler) {
exec($this->join(), $output);
} else {
$process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
$output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);
if ($error = stream_get_contents($pipes[2])) {
$errorHandler($error);
}
proc_close($process);
}
return $output ?: array();
}
/**
* Joins bits.
*
* @return string
*/
public function join()
{
return implode(' ', array_filter(
array_map(function ($bit) {
return $bit instanceof Command ? $bit->join() : ($bit ?: null);
}, $this->bits),
function ($bit) { return null !== $bit; }
));
}
/**
* Insert a string or a Command instance before the bit at given position $index (index starts from 0).
*
* @param string|Command $bit
* @param int $index
*
* @return Command The current Command instance
*/
public function addAtIndex($bit, $index)
{
array_splice($this->bits, $index, 0, $bit instanceof self ? array($bit) : $bit);
return $this;
}
}

View File

@@ -1,97 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Shell;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class Shell
{
const TYPE_UNIX = 1;
const TYPE_DARWIN = 2;
const TYPE_CYGWIN = 3;
const TYPE_WINDOWS = 4;
const TYPE_BSD = 5;
/**
* @var string|null
*/
private $type;
/**
* Returns guessed OS type.
*
* @return int
*/
public function getType()
{
if (null === $this->type) {
$this->type = $this->guessType();
}
return $this->type;
}
/**
* Tests if a command is available.
*
* @param string $command
*
* @return bool
*/
public function testCommand($command)
{
if (!function_exists('exec')) {
return false;
}
// todo: find a better way (command could not be available)
$testCommand = 'which ';
if (self::TYPE_WINDOWS === $this->type) {
$testCommand = 'where ';
}
$command = escapeshellcmd($command);
exec($testCommand.$command, $output, $code);
return 0 === $code && count($output) > 0;
}
/**
* Guesses OS type.
*
* @return int
*/
private function guessType()
{
$os = strtolower(PHP_OS);
if (false !== strpos($os, 'cygwin')) {
return self::TYPE_CYGWIN;
}
if (false !== strpos($os, 'darwin')) {
return self::TYPE_DARWIN;
}
if (false !== strpos($os, 'bsd')) {
return self::TYPE_BSD;
}
if (0 === strpos($os, 'win')) {
return self::TYPE_WINDOWS;
}
return self::TYPE_UNIX;
}
}

View File

@@ -1,68 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Expression;
use Symfony\Component\Finder\Expression\Expression;
class ExpressionTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider getTypeGuesserData
*/
public function testTypeGuesser($expr, $type)
{
$this->assertEquals($type, Expression::create($expr)->getType());
}
/**
* @dataProvider getCaseSensitiveData
*/
public function testCaseSensitive($expr, $isCaseSensitive)
{
$this->assertEquals($isCaseSensitive, Expression::create($expr)->isCaseSensitive());
}
/**
* @dataProvider getRegexRenderingData
*/
public function testRegexRendering($expr, $body)
{
$this->assertEquals($body, Expression::create($expr)->renderPattern());
}
public function getTypeGuesserData()
{
return array(
array('{foo}', Expression::TYPE_REGEX),
array('/foo/', Expression::TYPE_REGEX),
array('foo', Expression::TYPE_GLOB),
array('foo*', Expression::TYPE_GLOB),
);
}
public function getCaseSensitiveData()
{
return array(
array('{foo}m', true),
array('/foo/i', false),
array('foo*', true),
);
}
public function getRegexRenderingData()
{
return array(
array('{foo}m', 'foo'),
array('/foo/i', 'foo'),
);
}
}

View File

@@ -1,47 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Expression;
use Symfony\Component\Finder\Expression\Expression;
class GlobTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider getToRegexData
*/
public function testGlobToRegex($glob, $match, $noMatch)
{
foreach ($match as $m) {
$this->assertRegExp(Expression::create($glob)->getRegex()->render(), $m, '::toRegex() converts a glob to a regexp');
}
foreach ($noMatch as $m) {
$this->assertNotRegExp(Expression::create($glob)->getRegex()->render(), $m, '::toRegex() converts a glob to a regexp');
}
}
public function getToRegexData()
{
return array(
array('', array(''), array('f', '/')),
array('*', array('foo'), array('foo/', '/foo')),
array('foo.*', array('foo.php', 'foo.a', 'foo.'), array('fooo.php', 'foo.php/foo')),
array('fo?', array('foo', 'fot'), array('fooo', 'ffoo', 'fo/')),
array('fo{o,t}', array('foo', 'fot'), array('fob', 'fo/')),
array('foo(bar|foo)', array('foo(bar|foo)'), array('foobar', 'foofoo')),
array('foo,bar', array('foo,bar'), array('foo', 'bar')),
array('fo{o,\\,}', array('foo', 'fo,'), array()),
array('fo{o,\\\\}', array('foo', 'fo\\'), array()),
array('/foo', array('/foo'), array('foo')),
);
}
}

View File

@@ -1,143 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Expression;
use Symfony\Component\Finder\Expression\Expression;
class RegexTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider getHasFlagsData
*/
public function testHasFlags($regex, $start, $end)
{
$expr = new Expression($regex);
$this->assertEquals($start, $expr->getRegex()->hasStartFlag());
$this->assertEquals($end, $expr->getRegex()->hasEndFlag());
}
/**
* @dataProvider getHasJokersData
*/
public function testHasJokers($regex, $start, $end)
{
$expr = new Expression($regex);
$this->assertEquals($start, $expr->getRegex()->hasStartJoker());
$this->assertEquals($end, $expr->getRegex()->hasEndJoker());
}
/**
* @dataProvider getSetFlagsData
*/
public function testSetFlags($regex, $start, $end, $expected)
{
$expr = new Expression($regex);
$expr->getRegex()->setStartFlag($start)->setEndFlag($end);
$this->assertEquals($expected, $expr->render());
}
/**
* @dataProvider getSetJokersData
*/
public function testSetJokers($regex, $start, $end, $expected)
{
$expr = new Expression($regex);
$expr->getRegex()->setStartJoker($start)->setEndJoker($end);
$this->assertEquals($expected, $expr->render());
}
public function testOptions()
{
$expr = new Expression('~abc~is');
$expr->getRegex()->removeOption('i')->addOption('m');
$this->assertEquals('~abc~sm', $expr->render());
}
public function testMixFlagsAndJokers()
{
$expr = new Expression('~^.*abc.*$~is');
$expr->getRegex()->setStartFlag(false)->setEndFlag(false)->setStartJoker(false)->setEndJoker(false);
$this->assertEquals('~abc~is', $expr->render());
$expr->getRegex()->setStartFlag(true)->setEndFlag(true)->setStartJoker(true)->setEndJoker(true);
$this->assertEquals('~^.*abc.*$~is', $expr->render());
}
/**
* @dataProvider getReplaceJokersTestData
*/
public function testReplaceJokers($regex, $expected)
{
$expr = new Expression($regex);
$expr = $expr->getRegex()->replaceJokers('@');
$this->assertEquals($expected, $expr->renderPattern());
}
public function getHasFlagsData()
{
return array(
array('~^abc~', true, false),
array('~abc$~', false, true),
array('~abc~', false, false),
array('~^abc$~', true, true),
array('~^abc\\$~', true, false),
);
}
public function getHasJokersData()
{
return array(
array('~.*abc~', true, false),
array('~abc.*~', false, true),
array('~abc~', false, false),
array('~.*abc.*~', true, true),
array('~.*abc\\.*~', true, false),
);
}
public function getSetFlagsData()
{
return array(
array('~abc~', true, false, '~^abc~'),
array('~abc~', false, true, '~abc$~'),
array('~abc~', false, false, '~abc~'),
array('~abc~', true, true, '~^abc$~'),
);
}
public function getSetJokersData()
{
return array(
array('~abc~', true, false, '~.*abc~'),
array('~abc~', false, true, '~abc.*~'),
array('~abc~', false, false, '~abc~'),
array('~abc~', true, true, '~.*abc.*~'),
);
}
public function getReplaceJokersTestData()
{
return array(
array('~.abc~', '@abc'),
array('~\\.abc~', '\\.abc'),
array('~\\\\.abc~', '\\\\@abc'),
array('~\\\\\\.abc~', '\\\\\\.abc'),
);
}
}

View File

@@ -1,57 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\FakeAdapter;
use Symfony\Component\Finder\Adapter\AbstractAdapter;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class DummyAdapter extends AbstractAdapter
{
/**
* @var \Iterator
*/
private $iterator;
/**
* @param \Iterator $iterator
*/
public function __construct(\Iterator $iterator)
{
$this->iterator = $iterator;
}
/**
* {@inheritdoc}
*/
public function searchInDirectory($dir)
{
return $this->iterator;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'yes';
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return true;
}
}

View File

@@ -1,45 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\FakeAdapter;
use Symfony\Component\Finder\Adapter\AbstractAdapter;
use Symfony\Component\Finder\Exception\AdapterFailureException;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class FailingAdapter extends AbstractAdapter
{
/**
* {@inheritdoc}
*/
public function searchInDirectory($dir)
{
throw new AdapterFailureException($this);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'failing';
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return true;
}
}

View File

@@ -1,57 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\FakeAdapter;
use Symfony\Component\Finder\Adapter\AbstractAdapter;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class NamedAdapter extends AbstractAdapter
{
/**
* @var string
*/
private $name;
/**
* @param string $name
*/
public function __construct($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function searchInDirectory($dir)
{
return new \ArrayIterator(array());
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return true;
}
}

View File

@@ -1,44 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\FakeAdapter;
use Symfony\Component\Finder\Adapter\AbstractAdapter;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class UnsupportedAdapter extends AbstractAdapter
{
/**
* {@inheritdoc}
*/
public function searchInDirectory($dir)
{
return new \ArrayIterator(array());
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'unsupported';
}
/**
* {@inheritdoc}
*/
protected function canBeUsed()
{
return false;
}
}

View File

@@ -1,69 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Iterator;
use Symfony\Component\Finder\Iterator\FilePathsIterator;
class FilePathsIteratorTest extends RealIteratorTestCase
{
/**
* @dataProvider getSubPathData
*/
public function testSubPath($baseDir, array $paths, array $subPaths, array $subPathnames)
{
$iterator = new FilePathsIterator($paths, $baseDir);
foreach ($iterator as $index => $file) {
$this->assertEquals($paths[$index], $file->getPathname());
$this->assertEquals($subPaths[$index], $iterator->getSubPath());
$this->assertEquals($subPathnames[$index], $iterator->getSubPathname());
}
}
public function getSubPathData()
{
$tmpDir = sys_get_temp_dir().'/symfony_finder';
return array(
array(
$tmpDir,
array(
// paths
$tmpDir.DIRECTORY_SEPARATOR.'.git' => $tmpDir.DIRECTORY_SEPARATOR.'.git',
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => $tmpDir.DIRECTORY_SEPARATOR.'test.py',
$tmpDir.DIRECTORY_SEPARATOR.'foo' => $tmpDir.DIRECTORY_SEPARATOR.'foo',
$tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp',
$tmpDir.DIRECTORY_SEPARATOR.'test.php' => $tmpDir.DIRECTORY_SEPARATOR.'test.php',
$tmpDir.DIRECTORY_SEPARATOR.'toto' => $tmpDir.DIRECTORY_SEPARATOR.'toto',
),
array(
// subPaths
$tmpDir.DIRECTORY_SEPARATOR.'.git' => '',
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => '',
$tmpDir.DIRECTORY_SEPARATOR.'foo' => '',
$tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => 'foo',
$tmpDir.DIRECTORY_SEPARATOR.'test.php' => '',
$tmpDir.DIRECTORY_SEPARATOR.'toto' => '',
),
array(
// subPathnames
$tmpDir.DIRECTORY_SEPARATOR.'.git' => '.git',
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => 'test.py',
$tmpDir.DIRECTORY_SEPARATOR.'foo' => 'foo',
$tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => 'foo'.DIRECTORY_SEPARATOR.'bar.tmp',
$tmpDir.DIRECTORY_SEPARATOR.'test.php' => 'test.php',
$tmpDir.DIRECTORY_SEPARATOR.'toto' => 'toto',
),
),
);
}
}

View File

@@ -1,83 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Iterator;
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
class RecursiveDirectoryIteratorTest extends IteratorTestCase
{
/**
* @dataProvider getPaths
*
* @param string $path
* @param bool $seekable
* @param array $contains
* @param string $message
*/
public function testRewind($path, $seekable, $contains, $message = null)
{
try {
$i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
}
$i->rewind();
$this->assertTrue(true, $message);
}
/**
* @dataProvider getPaths
*
* @param string $path
* @param bool $seekable
* @param array $contains
* @param string $message
*/
public function testSeek($path, $seekable, $contains, $message = null)
{
try {
$i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
}
$actual = array();
$i->seek(0);
$actual[] = $i->getPathname();
$i->seek(1);
$actual[] = $i->getPathname();
$i->seek(2);
$actual[] = $i->getPathname();
$this->assertEquals($contains, $actual);
}
public function getPaths()
{
$data = array();
// ftp
$contains = array(
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'README',
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'index.html',
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'pub',
);
$data[] = array('ftp://ftp.mozilla.org/', false, $contains);
return $data;
}
}

View File

@@ -1,162 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Shell;
use Symfony\Component\Finder\Shell\Command;
class CommandTest extends \PHPUnit_Framework_TestCase
{
public function testCreate()
{
$this->assertInstanceOf('Symfony\Component\Finder\Shell\Command', Command::create());
}
public function testAdd()
{
$cmd = Command::create()->add('--force');
$this->assertSame('--force', $cmd->join());
}
public function testAddAsFirst()
{
$cmd = Command::create()->add('--force');
$cmd->addAtIndex(Command::create()->add('-F'), 0);
$this->assertSame('-F --force', $cmd->join());
}
public function testAddAsLast()
{
$cmd = Command::create()->add('--force');
$cmd->addAtIndex(Command::create()->add('-F'), 1);
$this->assertSame('--force -F', $cmd->join());
}
public function testAddInBetween()
{
$cmd = Command::create()->add('--force');
$cmd->addAtIndex(Command::create()->add('-F'), 0);
$cmd->addAtIndex(Command::create()->add('-X'), 1);
$this->assertSame('-F -X --force', $cmd->join());
}
public function testCount()
{
$cmd = Command::create();
$this->assertSame(0, $cmd->length());
$cmd->add('--force');
$this->assertSame(1, $cmd->length());
$cmd->add('--run');
$this->assertSame(2, $cmd->length());
}
public function testTop()
{
$cmd = Command::create()->add('--force');
$cmd->top('--run');
$this->assertSame('--run --force', $cmd->join());
}
public function testTopLabeled()
{
$cmd = Command::create()->add('--force');
$cmd->top('--run');
$cmd->ins('--something');
$cmd->top('--something');
$this->assertSame('--something --run --force ', $cmd->join());
}
public function testArg()
{
$cmd = Command::create()->add('--force');
$cmd->arg('--run');
$this->assertSame('--force \'--run\'', $cmd->join());
}
public function testCmd()
{
$cmd = Command::create()->add('--force');
$cmd->cmd('run');
$this->assertSame('--force run', $cmd->join());
}
public function testInsDuplicateLabelException()
{
$cmd = Command::create()->add('--force');
$cmd->ins('label');
$this->setExpectedException('RuntimeException');
$cmd->ins('label');
}
public function testEnd()
{
$parent = Command::create();
$cmd = Command::create($parent);
$this->assertSame($parent, $cmd->end());
}
public function testEndNoParentException()
{
$cmd = Command::create();
$this->setExpectedException('RuntimeException');
$cmd->end();
}
public function testGetMissingLabelException()
{
$cmd = Command::create();
$this->setExpectedException('RuntimeException');
$cmd->get('invalid');
}
public function testErrorHandler()
{
$cmd = Command::create();
$handler = function() { return 'error-handler'; };
$cmd->setErrorHandler($handler);
$this->assertSame($handler, $cmd->getErrorHandler());
}
public function testExecute()
{
$cmd = Command::create();
$cmd->add('php');
$cmd->add('--version');
$result = $cmd->execute();
$this->assertTrue(is_array($result));
$this->assertNotEmpty($result);
$this->assertRegexp('/PHP|HipHop/', $result[0]);
}
public function testCastToString()
{
$cmd = Command::create();
$cmd->add('--force');
$cmd->add('--run');
$this->assertSame('--force --run', (string) $cmd);
}
}

View File

@@ -12,7 +12,6 @@
namespace Symfony\Component\Finder\Tests;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\Adapter;
class FinderTest extends Iterator\RealIteratorTestCase
{
@@ -21,109 +20,94 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertInstanceOf('Symfony\Component\Finder\Finder', Finder::create());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testDirectories($adapter)
public function testDirectories()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->directories());
$this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->directories();
$finder->files();
$finder->directories();
$this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testFiles($adapter)
public function testFiles()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->files());
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->files();
$finder->directories();
$finder->files();
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testDepth($adapter)
public function testDepth()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->depth('< 1'));
$this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->depth('<= 0'));
$this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->depth('>= 1'));
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->depth('< 1')->depth('>= 1');
$this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testName($adapter)
public function testName()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->name('*.php'));
$this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->name('test.ph*');
$finder->name('test.py');
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->name('~^test~i');
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->name('~\\.php$~i');
$this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->name('test.p{hp,y}');
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testNotName($adapter)
public function testNotName()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->notName('*.php'));
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->notName('*.php');
$finder->notName('*.py');
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->name('test.ph*');
$finder->name('test.py');
$finder->notName('*.php');
$finder->notName('*.py');
$this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->name('test.ph*');
$finder->name('test.py');
$finder->notName('*.p{hp,y}');
@@ -133,228 +117,184 @@ class FinderTest extends Iterator\RealIteratorTestCase
/**
* @dataProvider getRegexNameTestData
*/
public function testRegexName($adapter, $regex)
public function testRegexName($regex)
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->name($regex);
$this->assertIterator($this->toAbsolute(array('test.py', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testSize($adapter)
public function testSize()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->files()->size('< 1K')->size('> 500'));
$this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testDate($adapter)
public function testDate()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->files()->date('until last month'));
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testExclude($adapter)
public function testExclude()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->exclude('foo'));
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testIgnoreVCS($adapter)
public function testIgnoreVCS()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreVCS(false)->ignoreDotFiles(false));
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->ignoreVCS(false)->ignoreVCS(false)->ignoreDotFiles(false);
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreVCS(true)->ignoreDotFiles(false));
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testIgnoreDotFiles($adapter)
public function testIgnoreDotFiles()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreDotFiles(false)->ignoreVCS(false));
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->ignoreDotFiles(false)->ignoreDotFiles(false)->ignoreVCS(false);
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreDotFiles(true)->ignoreVCS(false));
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testSortByName($adapter)
public function testSortByName()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->sortByName());
$this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testSortByType($adapter)
public function testSortByType()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->sortByType());
$this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'toto', 'foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testSortByAccessedTime($adapter)
public function testSortByAccessedTime()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->sortByAccessedTime());
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testSortByChangedTime($adapter)
public function testSortByChangedTime()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->sortByChangedTime());
$this->assertIterator($this->toAbsolute(array('toto', 'test.py', 'test.php', 'foo/bar.tmp', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testSortByModifiedTime($adapter)
public function testSortByModifiedTime()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->sortByModifiedTime());
$this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testSort($adapter)
public function testSort()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->sort(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealPath(), $b->getRealPath()); }));
$this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testFilter($adapter)
public function testFilter()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->filter(function (\SplFileInfo $f) { return false !== strpos($f, 'test'); }));
$this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testFollowLinks($adapter)
public function testFollowLinks()
{
if ('\\' == DIRECTORY_SEPARATOR) {
return;
$this->markTestSkipped('symlinks are not supported on Windows');
}
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->followLinks());
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testIn($adapter)
public function testIn()
{
$finder = $this->buildFinder($adapter);
try {
$finder->in('foobar');
$this->fail('->in() throws a \InvalidArgumentException if the directory does not exist');
} catch (\Exception $e) {
$this->assertInstanceOf('InvalidArgumentException', $e, '->in() throws a \InvalidArgumentException if the directory does not exist');
}
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$iterator = $finder->files()->name('*.php')->depth('< 1')->in(array(self::$tmpDir, __DIR__))->getIterator();
$this->assertIterator(array(self::$tmpDir.DIRECTORY_SEPARATOR.'test.php', __DIR__.DIRECTORY_SEPARATOR.'FinderTest.php'), $iterator);
$expected = array(
self::$tmpDir.DIRECTORY_SEPARATOR.'test.php',
__DIR__.DIRECTORY_SEPARATOR.'FinderTest.php',
__DIR__.DIRECTORY_SEPARATOR.'GlobTest.php',
);
$this->assertIterator($expected, $iterator);
}
/**
* @dataProvider getAdaptersTestData
* @expectedException \InvalidArgumentException
*/
public function testInWithGlob($adapter)
public function testInWithNonExistentDirectory()
{
$finder = $this->buildFinder($adapter);
$finder = new Finder();
$finder->in('foobar');
}
public function testInWithGlob()
{
$finder = $this->buildFinder();
$finder->in(array(__DIR__.'/Fixtures/*/B/C', __DIR__.'/Fixtures/*/*/B/C'))->getIterator();
$this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
}
/**
* @dataProvider getAdaptersTestData
* @expectedException \InvalidArgumentException
*/
public function testInWithNonDirectoryGlob($adapter)
public function testInWithNonDirectoryGlob()
{
$finder = $this->buildFinder($adapter);
$finder = new Finder();
$finder->in(__DIR__.'/Fixtures/A/a*');
}
/**
* @dataProvider getAdaptersTestData
*/
public function testInWithGlobBrace($adapter)
public function testInWithGlobBrace()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->in(array(__DIR__.'/Fixtures/{A,copy/A}/B/C'))->getIterator();
$this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
}
/**
* @dataProvider getAdaptersTestData
* @expectedException \LogicException
*/
public function testGetIterator($adapter)
public function testGetIteratorWithoutIn()
{
$finder = $this->buildFinder($adapter);
try {
$finder->getIterator();
$this->fail('->getIterator() throws a \LogicException if the in() method has not been called');
} catch (\Exception $e) {
$this->assertInstanceOf('LogicException', $e, '->getIterator() throws a \LogicException if the in() method has not been called');
}
$finder = Finder::create();
$finder->getIterator();
}
$finder = $this->buildFinder($adapter);
public function testGetIterator()
{
$finder = $this->buildFinder();
$dirs = array();
foreach ($finder->directories()->in(self::$tmpDir) as $dir) {
$dirs[] = (string) $dir;
@@ -367,22 +307,19 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertEquals($expected, $dirs, 'implements the \IteratorAggregate interface');
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$this->assertEquals(2, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface');
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$a = iterator_to_array($finder->directories()->in(self::$tmpDir));
$a = array_values(array_map(function ($a) { return (string) $a; }, $a));
sort($a);
$this->assertEquals($expected, $a, 'implements the \IteratorAggregate interface');
}
/**
* @dataProvider getAdaptersTestData
*/
public function testRelativePath($adapter)
public function testRelativePath()
{
$finder = $this->buildFinder($adapter)->in(self::$tmpDir);
$finder = $this->buildFinder()->in(self::$tmpDir);
$paths = array();
@@ -398,12 +335,9 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertEquals($ref, $paths);
}
/**
* @dataProvider getAdaptersTestData
*/
public function testRelativePathname($adapter)
public function testRelativePathname()
{
$finder = $this->buildFinder($adapter)->in(self::$tmpDir)->sortByName();
$finder = $this->buildFinder()->in(self::$tmpDir)->sortByName();
$paths = array();
@@ -419,15 +353,12 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertEquals($ref, $paths);
}
/**
* @dataProvider getAdaptersTestData
*/
public function testAppendWithAFinder($adapter)
public function testAppendWithAFinder()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
$finder1 = $this->buildFinder($adapter);
$finder1 = $this->buildFinder();
$finder1->directories()->in(self::$tmpDir);
$finder = $finder->append($finder1);
@@ -435,12 +366,9 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testAppendWithAnArray($adapter)
public function testAppendWithAnArray()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
$finder->append($this->toAbsolute(array('foo', 'toto')));
@@ -448,20 +376,14 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
}
/**
* @dataProvider getAdaptersTestData
*/
public function testAppendReturnsAFinder($adapter)
public function testAppendReturnsAFinder()
{
$this->assertInstanceOf('Symfony\\Component\\Finder\\Finder', $this->buildFinder($adapter)->append(array()));
$this->assertInstanceOf('Symfony\\Component\\Finder\\Finder', Finder::create()->append(array()));
}
/**
* @dataProvider getAdaptersTestData
*/
public function testAppendDoesNotRequireIn($adapter)
public function testAppendDoesNotRequireIn()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
$finder1 = Finder::create()->append($finder);
@@ -505,9 +427,9 @@ class FinderTest extends Iterator\RealIteratorTestCase
/**
* @dataProvider getContainsTestData
*/
public function testContains($adapter, $matchPatterns, $noMatchPatterns, $expected)
public function testContains($matchPatterns, $noMatchPatterns, $expected)
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
->name('*.txt')->sortByName()
->contains($matchPatterns)
@@ -516,12 +438,9 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
}
/**
* @dataProvider getAdaptersTestData
*/
public function testContainsOnDirectory(Adapter\AdapterInterface $adapter)
public function testContainsOnDirectory()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->in(__DIR__)
->directories()
->name('Fixtures')
@@ -529,12 +448,9 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertIterator(array(), $finder);
}
/**
* @dataProvider getAdaptersTestData
*/
public function testNotContainsOnDirectory(Adapter\AdapterInterface $adapter)
public function testNotContainsOnDirectory()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->in(__DIR__)
->directories()
->name('Fixtures')
@@ -546,11 +462,9 @@ class FinderTest extends Iterator\RealIteratorTestCase
* Searching in multiple locations involves AppendIterator which does an unnecessary rewind which leaves FilterIterator
* with inner FilesystemIterator in an invalid state.
*
* @see https://bugs.php.net/bug.php?id=49104
*
* @dataProvider getAdaptersTestData
* @see https://bugs.php.net/68557
*/
public function testMultipleLocations(Adapter\AdapterInterface $adapter)
public function testMultipleLocations()
{
$locations = array(
self::$tmpDir.'/',
@@ -558,85 +472,66 @@ class FinderTest extends Iterator\RealIteratorTestCase
);
// it is expected that there are test.py test.php in the tmpDir
$finder = $this->buildFinder($adapter);
$finder->in($locations)->depth('< 1')->name('test.php');
$finder = new Finder();
$finder->in($locations)
// the default flag IGNORE_DOT_FILES fixes the problem indirectly
// so we set it to false for better isolation
->ignoreDotFiles(false)
->depth('< 1')->name('test.php');
$this->assertCount(1, $finder);
}
/**
* Iterator keys must be the file pathname.
* Searching in multiple locations with sub directories involves
* AppendIterator which does an unnecessary rewind which leaves
* FilterIterator with inner FilesystemIterator in an invalid state.
*
* @dataProvider getAdaptersTestData
* @see https://bugs.php.net/68557
*/
public function testIteratorKeys(Adapter\AdapterInterface $adapter)
public function testMultipleLocationsWithSubDirectories()
{
$finder = $this->buildFinder($adapter)->in(self::$tmpDir);
$locations = array(
__DIR__.'/Fixtures/one',
self::$tmpDir.DIRECTORY_SEPARATOR.'toto',
);
$finder = $this->buildFinder();
$finder->in($locations)->depth('< 10')->name('*.neon');
$expected = array(
__DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'c.neon',
__DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'d.neon',
);
$this->assertIterator($expected, $finder);
$this->assertIteratorInForeach($expected, $finder);
}
/**
* Iterator keys must be the file pathname.
*/
public function testIteratorKeys()
{
$finder = $this->buildFinder()->in(self::$tmpDir);
foreach ($finder as $key => $file) {
$this->assertEquals($file->getPathname(), $key);
}
}
/**
* @dataProvider getAdaptersTestData
*/
public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartFlag(Adapter\AdapterInterface $adapter)
public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartFlag()
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'r+e.gex[c]a(r)s')
->path('/^dir/');
$expected = array('r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir',
'r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'bar.dat',);
$expected = array('r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir', 'r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'bar.dat');
$this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
}
public function testAdaptersOrdering()
{
$finder = Finder::create()
->removeAdapters()
->addAdapter(new FakeAdapter\NamedAdapter('a'), 0)
->addAdapter(new FakeAdapter\NamedAdapter('b'), -50)
->addAdapter(new FakeAdapter\NamedAdapter('c'), 50)
->addAdapter(new FakeAdapter\NamedAdapter('d'), -25)
->addAdapter(new FakeAdapter\NamedAdapter('e'), 25);
$this->assertEquals(
array('c', 'e', 'a', 'd', 'b'),
array_map(function (Adapter\AdapterInterface $adapter) {
return $adapter->getName();
}, $finder->getAdapters())
);
}
public function testAdaptersChaining()
{
$iterator = new \ArrayIterator(array());
$filenames = $this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto'));
foreach ($filenames as $file) {
$iterator->append(new \Symfony\Component\Finder\SplFileInfo($file, null, null));
}
$finder = Finder::create()
->removeAdapters()
->addAdapter(new FakeAdapter\UnsupportedAdapter(), 3)
->addAdapter(new FakeAdapter\FailingAdapter(), 2)
->addAdapter(new FakeAdapter\DummyAdapter($iterator), 1);
$this->assertIterator($filenames, $finder->in(sys_get_temp_dir())->getIterator());
}
public function getAdaptersTestData()
{
return array_map(
function ($adapter) { return array($adapter); },
$this->getValidAdapters()
);
}
public function getContainsTestData()
{
$tests = array(
return array(
array('', '', array()),
array('foo', 'bar', array()),
array('', 'foobar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
@@ -648,26 +543,22 @@ class FinderTest extends Iterator\RealIteratorTestCase
array('', 'lorem', array('dolor.txt', 'ipsum.txt')),
array('ipsum dolor sit amet', '/^IPSUM/m', array('lorem.txt')),
);
return $this->buildTestData($tests);
}
public function getRegexNameTestData()
{
$tests = array(
return array(
array('~.+\\.p.+~i'),
array('~t.*s~i'),
);
return $this->buildTestData($tests);
}
/**
* @dataProvider getTestPathData
*/
public function testPath(Adapter\AdapterInterface $adapter, $matchPatterns, $noMatchPatterns, array $expected)
public function testPath($matchPatterns, $noMatchPatterns, array $expected)
{
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
->path($matchPatterns)
->notPath($noMatchPatterns);
@@ -675,24 +566,9 @@ class FinderTest extends Iterator\RealIteratorTestCase
$this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
}
public function testAdapterSelection()
{
// test that by default, PhpAdapter is selected
$adapters = Finder::create()->getAdapters();
$this->assertTrue($adapters[0] instanceof Adapter\PhpAdapter);
// test another adapter selection
$adapters = Finder::create()->setAdapter('gnu_find')->getAdapters();
$this->assertTrue($adapters[0] instanceof Adapter\GnuFindAdapter);
// test that useBestAdapter method removes selection
$adapters = Finder::create()->useBestAdapter()->getAdapters();
$this->assertFalse($adapters[0] instanceof Adapter\PhpAdapter);
}
public function getTestPathData()
{
$tests = array(
return array(
array('', '', array()),
array('/^A\/B\/C/', '/C$/',
array('A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat'),
@@ -733,20 +609,15 @@ class FinderTest extends Iterator\RealIteratorTestCase
),
),
);
return $this->buildTestData($tests);
}
/**
* @dataProvider getAdaptersTestData
*/
public function testAccessDeniedException(Adapter\AdapterInterface $adapter)
public function testAccessDeniedException()
{
if ('\\' === DIRECTORY_SEPARATOR) {
$this->markTestSkipped('chmod is not supported on Windows');
}
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->files()->in(self::$tmpDir);
// make 'foo' directory non-readable
@@ -776,16 +647,13 @@ class FinderTest extends Iterator\RealIteratorTestCase
}
}
/**
* @dataProvider getAdaptersTestData
*/
public function testIgnoredAccessDeniedException(Adapter\AdapterInterface $adapter)
public function testIgnoredAccessDeniedException()
{
if ('\\' === DIRECTORY_SEPARATOR) {
$this->markTestSkipped('chmod is not supported on Windows');
}
$finder = $this->buildFinder($adapter);
$finder = $this->buildFinder();
$finder->files()->ignoreUnreadableDirs()->in(self::$tmpDir);
// make 'foo' directory non-readable
@@ -805,62 +673,8 @@ class FinderTest extends Iterator\RealIteratorTestCase
}
}
private function buildTestData(array $tests)
protected function buildFinder()
{
$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();
}
);
}
/**
* Searching in multiple locations with sub directories involves
* AppendIterator which does an unnecessary rewind which leaves
* FilterIterator with inner FilesystemIterator in an invalid state.
*
* @see https://bugs.php.net/bug.php?id=49104
*/
public function testMultipleLocationsWithSubDirectories()
{
$locations = array(
__DIR__.'/Fixtures/one',
self::$tmpDir.DIRECTORY_SEPARATOR.'toto',
);
$finder = new Finder();
$finder->in($locations)->depth('< 10')->name('*.neon');
$expected = array(
__DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'c.neon',
__DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'d.neon',
);
$this->assertIterator($expected, $finder);
$this->assertIteratorInForeach($expected, $finder);
return Finder::create();
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests;
use Symfony\Component\Finder\Glob;
class GlobTest extends \PHPUnit_Framework_TestCase
{
public function testGlobToRegexDelimiters()
{
$this->assertEquals('#^(?=[^\.])\#$#', Glob::toRegex('#'));
$this->assertEquals('#^\.[^/]*$#', Glob::toRegex('.*'));
$this->assertEquals('^\.[^/]*$', Glob::toRegex('.*', true, true, ''));
$this->assertEquals('/^\.[^/]*$/', Glob::toRegex('.*', true, true, '/'));
}
}

View File

@@ -39,6 +39,7 @@ class DateRangeFilterIteratorTest extends RealIteratorTestCase
'foo/bar.tmp',
'test.php',
'toto',
'toto/.git',
'.bar',
'.foo',
'.foo/.bar',
@@ -51,6 +52,7 @@ class DateRangeFilterIteratorTest extends RealIteratorTestCase
'test.py',
'foo',
'toto',
'toto/.git',
'.bar',
'.foo',
'.foo/.bar',

View File

@@ -50,6 +50,7 @@ class DepthRangeFilterIteratorTest extends RealIteratorTestCase
'foo/bar.tmp',
'test.php',
'toto',
'toto/.git',
'.foo',
'.foo/.bar',
'.bar',
@@ -58,12 +59,14 @@ class DepthRangeFilterIteratorTest extends RealIteratorTestCase
);
$graterThanOrEqualTo1 = array(
'toto/.git',
'foo/bar.tmp',
'.foo/.bar',
'.foo/bar',
);
$equalTo1 = array(
'toto/.git',
'foo/bar.tmp',
'.foo/.bar',
'.foo/bar',

View File

@@ -39,6 +39,7 @@ class ExcludeDirectoryFilterIteratorTest extends RealIteratorTestCase
'test.py',
'test.php',
'toto',
'toto/.git',
'foo bar',
);
@@ -53,6 +54,7 @@ class ExcludeDirectoryFilterIteratorTest extends RealIteratorTestCase
'foo/bar.tmp',
'test.php',
'toto',
'toto/.git',
'foo bar',
);

View File

@@ -43,6 +43,7 @@ class FileTypeFilterIteratorTest extends RealIteratorTestCase
'.git',
'foo',
'toto',
'toto/.git',
'.foo',
);

View File

@@ -43,8 +43,9 @@ class FilterIteratorTest extends RealIteratorTestCase
++$c;
}
// This would fail with \FilterIterator but works with Symfony\Component\Finder\Iterator\FilterIterator
// see https://bugs.php.net/bug.php?id=49104
// This would fail in php older than 5.5.23/5.6.7 with \FilterIterator
// but works with Symfony\Component\Finder\Iterator\FilterIterator
// see https://bugs.php.net/68557
$this->assertEquals(1, $c);
}
}

View File

@@ -16,7 +16,7 @@ abstract class IteratorTestCase extends \PHPUnit_Framework_TestCase
protected function assertIterator($expected, \Traversable $iterator)
{
// set iterator_to_array $use_key to false to avoid values merge
// this made FinderTest::testAppendWithAnArray() failed with GnuFinderAdapter
// this made FinderTest::testAppendWithAnArray() fail with GnuFinderAdapter
$values = array_map(function (\SplFileInfo $fileinfo) { return str_replace('/', DIRECTORY_SEPARATOR, $fileinfo->getPathname()); }, iterator_to_array($iterator, false));
$expected = array_map(function ($path) { return str_replace('/', DIRECTORY_SEPARATOR, $path); }, $expected);

View File

@@ -52,7 +52,7 @@ class MockSplFileInfo extends \SplFileInfo
{
if (null === $this->type) {
return false !== strpos($this->getFilename(), 'file');
};
}
return self::TYPE_FILE === $this->type;
}

View File

@@ -38,6 +38,9 @@ class MultiplePcreFilterIteratorTest extends \PHPUnit_Framework_TestCase
array('/foo/imsxu', true, 'valid regex with multiple modifiers'),
array('#foo#', true, '"#" is a valid delimiter'),
array('{foo}', true, '"{,}" is a valid delimiter pair'),
array('[foo]', true, '"[,]" is a valid delimiter pair'),
array('(foo)', true, '"(,)" is a valid delimiter pair'),
array('<foo>', true, '"<,>" is a valid delimiter pair'),
array('*foo.*', false, '"*" is not considered as a valid delimiter'),
array('?foo.?', false, '"?" is not considered as a valid delimiter'),
);

View File

@@ -31,6 +31,7 @@ abstract class RealIteratorTestCase extends IteratorTestCase
'foo/bar.tmp',
'test.php',
'toto/',
'toto/.git/',
'foo bar',
);

View File

@@ -0,0 +1,59 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests\Iterator;
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
class RecursiveDirectoryIteratorTest extends IteratorTestCase
{
/**
* @group network
*/
public function testRewindOnFtp()
{
try {
$i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped('Unsupported stream "ftp".');
}
$i->rewind();
$this->assertTrue(true);
}
/**
* @group network
*/
public function testSeekOnFtp()
{
try {
$i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\UnexpectedValueException $e) {
$this->markTestSkipped('Unsupported stream "ftp".');
}
$contains = array(
'ftp://speedtest.tele2.net'.DIRECTORY_SEPARATOR.'1000GB.zip',
'ftp://speedtest.tele2.net'.DIRECTORY_SEPARATOR.'100GB.zip',
);
$actual = array();
$i->seek(0);
$actual[] = $i->getPathname();
$i->seek(1);
$actual[] = $i->getPathname();
$this->assertEquals($contains, $actual);
}
}

View File

@@ -36,6 +36,7 @@ class SizeRangeFilterIteratorTest extends RealIteratorTestCase
'foo',
'test.php',
'toto',
'toto/.git',
);
return array(

View File

@@ -33,7 +33,11 @@ class SortableIteratorTest extends RealIteratorTestCase
if (!is_callable($mode)) {
switch ($mode) {
case SortableIterator::SORT_BY_ACCESSED_TIME :
file_get_contents(self::toAbsolute('.git'));
if ('\\' === DIRECTORY_SEPARATOR) {
touch(self::toAbsolute('.git'));
} else {
file_get_contents(self::toAbsolute('.git'));
}
sleep(1);
file_get_contents(self::toAbsolute('.bar'));
break;
@@ -56,7 +60,11 @@ class SortableIteratorTest extends RealIteratorTestCase
if ($mode === SortableIterator::SORT_BY_ACCESSED_TIME
|| $mode === SortableIterator::SORT_BY_CHANGED_TIME
|| $mode === SortableIterator::SORT_BY_MODIFIED_TIME) {
|| $mode === SortableIterator::SORT_BY_MODIFIED_TIME
) {
if ('\\' === DIRECTORY_SEPARATOR && SortableIterator::SORT_BY_MODIFIED_TIME !== $mode) {
$this->markTestSkipped('Sorting by atime or ctime is not supported on Windows');
}
$this->assertOrderedIteratorForGroups($expected, $iterator);
} else {
$this->assertOrderedIterator($expected, $iterator);
@@ -77,6 +85,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'test.php',
'test.py',
'toto',
'toto/.git',
);
$sortByType = array(
@@ -84,6 +93,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'.git',
'foo',
'toto',
'toto/.git',
'.bar',
'.foo/.bar',
'.foo/bar',
@@ -105,6 +115,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'test.php',
'test.py',
'toto',
'toto/.git',
);
$sortByAccessedTime = array(
@@ -119,6 +130,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'test.py',
'foo',
'toto',
'toto/.git',
'foo bar',
),
// This file was accessed after sleeping for 1 sec
@@ -135,6 +147,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'foo',
'foo/bar.tmp',
'toto',
'toto/.git',
'foo bar',
),
array('test.php'),
@@ -151,6 +164,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'foo',
'foo/bar.tmp',
'toto',
'toto/.git',
'foo bar',
),
array('test.php'),

View File

@@ -16,19 +16,18 @@
}
],
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
"php": ">=5.5.9"
},
"autoload": {
"psr-0": { "Symfony\\Component\\Finder\\": "" }
"psr-4": { "Symfony\\Component\\Finder\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"target-dir": "Symfony/Component/Finder",
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.6-dev"
"dev-master": "3.0-dev"
}
}
}

View File

@@ -9,6 +9,7 @@
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Symfony Finder Component Test Suite">
<directory>./Tests/</directory>