kekrozsak/vendor/jms/di-extra-bundle/JMS/DiExtraBundle/Finder/PatternFinder.php

201 lines
5.5 KiB
PHP

<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JMS\DiExtraBundle\Finder;
use JMS\DiExtraBundle\Exception\RuntimeException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\ExecutableFinder;
class PatternFinder
{
const METHOD_GREP = 1;
const METHOD_FINDSTR = 2;
const METHOD_FINDER = 3;
private static $method;
private static $grepPath;
private $pattern;
private $filePattern;
private $recursive = true;
private $regexPattern = false;
public function __construct($pattern, $filePattern = '*.php')
{
if (null === self::$method) {
self::determineMethod();
}
$this->pattern = $pattern;
$this->filePattern = $filePattern;
}
public function setRecursive($bool)
{
$this->recursive = (Boolean) $bool;
}
public function setRegexPattern($bool)
{
$this->regexPattern = (Boolean) $bool;
}
public function findFiles(array $dirs)
{
// check for grep availability
if (self::METHOD_GREP === self::$method) {
return $this->findUsingGrep($dirs);
}
// use FINDSTR on Windows
if (self::METHOD_FINDSTR === self::$method) {
return $this->findUsingFindstr($dirs);
}
// this should really be avoided at all costs since it is damn slow
return $this->findUsingFinder($dirs);
}
private function findUsingFindstr(array $dirs)
{
$cmd = 'FINDSTR /M /S /P';
if (!$this->recursive) {
$cmd .= ' /L';
}
$cmd .= ' /D:'.escapeshellarg(implode(';', $dirs));
$cmd .= ' '.escapeshellarg($this->pattern);
$cmd .= ' '.$this->filePattern;
exec($cmd, $lines, $exitCode);
if (1 === $exitCode) {
return array();
}
if (0 !== $exitCode) {
throw new RuntimeException(sprintf('Command "%s" exited with non-successful status code. "%d".', $cmd, $exitCode));
}
// Looks like FINDSTR has different versions with different output formats.
//
// Supported format #1:
// C:\matched\dir1:
// Relative\Path\To\File1.php
// Relative\Path\To\File2.php
// C:\matched\dir2:
// Relative\Path\To\File3.php
// Relative\Path\To\File4.php
//
// Supported format #2:
// C:\matched\dir1\Relative\Path\To\File1.php
// C:\matched\dir1\Relative\Path\To\File2.php
// C:\matched\dir2\Relative\Path\To\File3.php
// C:\matched\dir2\Relative\Path\To\File4.php
$files = array();
$currentDir = '';
foreach ($lines as $line) {
if (':' === substr($line, -1)) {
$currentDir = trim($line, ' :/').'/';
continue;
}
$files[] = $currentDir.$line;
}
return $files;
}
private function findUsingGrep(array $dirs)
{
$cmd = self::$grepPath;
if (!$this->regexPattern) {
$cmd .= ' --fixed-strings';
} else {
$cmd .= ' --extended-regexp';
}
if ($this->recursive) {
$cmd .= ' --directories=recurse';
} else {
$cmd .= ' --directories=skip';
}
$cmd .= ' --devices=skip --files-with-matches --with-filename --max-count=1 --color=never --include='.$this->filePattern;
$cmd .= ' '.escapeshellarg($this->pattern);
foreach ($dirs as $dir) {
$cmd .= ' '.escapeshellarg($dir);
}
exec($cmd, $files, $exitCode);
if (1 === $exitCode) {
return array();
}
if (0 !== $exitCode) {
throw new RuntimeException(sprintf('Command "%s" exited with non-successful status code "%d".', $cmd, $exitCode));
}
return $files;
}
private function findUsingFinder(array $dirs)
{
$finder = new Finder();
$pattern = $this->pattern;
$regex = $this->regexPattern;
$finder
->files()
->name($this->filePattern)
->in($dirs)
->ignoreVCS(true)
->filter(function($file) use ($pattern, $regex) {
if (!$regex) {
return false !== strpos(file_get_contents($file->getPathName()), $pattern);
}
return 0 < preg_match('#'.$pattern.'#', file_get_contents($file->getPathName()));
})
;
if (!$this->recursive) {
$finder->depth('<= 0');
}
return array_keys(iterator_to_array($finder));
}
private static function determineMethod()
{
$finder = new ExecutableFinder();
$isWindows = 0 === stripos(PHP_OS, 'win');
if (!$isWindows && self::$grepPath = $finder->find('grep')) {
self::$method = self::METHOD_GREP;
} else if ($isWindows) {
self::$method = self::METHOD_FINDSTR;
} else {
self::$method = self::METHOD_FINDER;
}
}
}