123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- <?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 --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');
- $execAvailable = function_exists('exec');
-
- if (!$isWindows && $execAvailable && self::$grepPath = $finder->find('grep')) {
- self::$method = self::METHOD_GREP;
- } else if ($isWindows && $execAvailable) {
- self::$method = self::METHOD_FINDSTR;
- } else {
- self::$method = self::METHOD_FINDER;
- }
- }
- }
|