PageRenderTime 24ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/PHP/Test/vendor/symfony/symfony/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php

https://bitbucket.org/AdriVanHoudt/school
PHP | 320 lines | 197 code | 46 blank | 77 comment | 34 complexity | 71d3bc4a784ee76efe7615cba29e3f75 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Finder\Adapter;
  11. use Symfony\Component\Finder\Iterator;
  12. use Symfony\Component\Finder\Shell\Shell;
  13. use Symfony\Component\Finder\Expression\Expression;
  14. use Symfony\Component\Finder\Shell\Command;
  15. use Symfony\Component\Finder\Iterator\SortableIterator;
  16. use Symfony\Component\Finder\Comparator\NumberComparator;
  17. use Symfony\Component\Finder\Comparator\DateComparator;
  18. /**
  19. * Shell engine implementation using GNU find command.
  20. *
  21. * @author Jean-François Simon <contact@jfsimon.fr>
  22. */
  23. abstract class AbstractFindAdapter extends AbstractAdapter
  24. {
  25. /**
  26. * @var Shell
  27. */
  28. protected $shell;
  29. /**
  30. * Constructor.
  31. */
  32. public function __construct()
  33. {
  34. $this->shell = new Shell();
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function searchInDirectory($dir)
  40. {
  41. // having "/../" in path make find fail
  42. $dir = realpath($dir);
  43. // searching directories containing or not containing strings leads to no result
  44. if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
  45. return new Iterator\FilePathsIterator(array(), $dir);
  46. }
  47. $command = Command::create();
  48. $find = $this->buildFindCommand($command, $dir);
  49. if ($this->followLinks) {
  50. $find->add('-follow');
  51. }
  52. $find->add('-mindepth')->add($this->minDepth + 1);
  53. // warning! INF < INF => true ; INF == INF => false ; INF === INF => true
  54. // https://bugs.php.net/bug.php?id=9118
  55. if (INF !== $this->maxDepth) {
  56. $find->add('-maxdepth')->add($this->maxDepth + 1);
  57. }
  58. if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
  59. $find->add('-type d');
  60. } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
  61. $find->add('-type f');
  62. }
  63. $this->buildNamesFiltering($find, $this->names);
  64. $this->buildNamesFiltering($find, $this->notNames, true);
  65. $this->buildPathsFiltering($find, $dir, $this->paths);
  66. $this->buildPathsFiltering($find, $dir, $this->notPaths, true);
  67. $this->buildSizesFiltering($find, $this->sizes);
  68. $this->buildDatesFiltering($find, $this->dates);
  69. $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
  70. $useSort = is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
  71. if ($useGrep && ($this->contains || $this->notContains)) {
  72. $grep = $command->ins('grep');
  73. $this->buildContentFiltering($grep, $this->contains);
  74. $this->buildContentFiltering($grep, $this->notContains, true);
  75. }
  76. if ($useSort) {
  77. $this->buildSorting($command, $this->sort);
  78. }
  79. $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
  80. $iterator = new Iterator\FilePathsIterator($paths, $dir);
  81. if ($this->exclude) {
  82. $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
  83. }
  84. if (!$useGrep && ($this->contains || $this->notContains)) {
  85. $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
  86. }
  87. if ($this->filters) {
  88. $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
  89. }
  90. if (!$useSort && $this->sort) {
  91. $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
  92. $iterator = $iteratorAggregate->getIterator();
  93. }
  94. return $iterator;
  95. }
  96. /**
  97. * {@inheritdoc}
  98. */
  99. protected function canBeUsed()
  100. {
  101. return $this->shell->testCommand('find');
  102. }
  103. /**
  104. * @param Command $command
  105. * @param string $dir
  106. *
  107. * @return Command
  108. */
  109. protected function buildFindCommand(Command $command, $dir)
  110. {
  111. return $command
  112. ->ins('find')
  113. ->add('find ')
  114. ->arg($dir)
  115. ->add('-noleaf'); // the -noleaf option is required for filesystems that don't follow the '.' and '..' conventions
  116. }
  117. /**
  118. * @param Command $command
  119. * @param string[] $names
  120. * @param Boolean $not
  121. */
  122. private function buildNamesFiltering(Command $command, array $names, $not = false)
  123. {
  124. if (0 === count($names)) {
  125. return;
  126. }
  127. $command->add($not ? '-not' : null)->cmd('(');
  128. foreach ($names as $i => $name) {
  129. $expr = Expression::create($name);
  130. // Find does not support expandable globs ("*.{a,b}" syntax).
  131. if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
  132. $expr = Expression::create($expr->getGlob()->toRegex(false));
  133. }
  134. // Fixes 'not search' and 'full path matching' regex problems.
  135. // - Jokers '.' are replaced by [^/].
  136. // - We add '[^/]*' before and after regex (if no ^|$ flags are present).
  137. if ($expr->isRegex()) {
  138. $regex = $expr->getRegex();
  139. $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
  140. ->setStartFlag(false)
  141. ->setStartJoker(true)
  142. ->replaceJokers('[^/]');
  143. if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
  144. $regex->setEndJoker(false)->append('[^/]*');
  145. }
  146. }
  147. $command
  148. ->add($i > 0 ? '-or' : null)
  149. ->add($expr->isRegex()
  150. ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
  151. : ($expr->isCaseSensitive() ? '-name' : '-iname')
  152. )
  153. ->arg($expr->renderPattern());
  154. }
  155. $command->cmd(')');
  156. }
  157. /**
  158. * @param Command $command
  159. * @param string $dir
  160. * @param string[] $paths
  161. * @param Boolean $not
  162. */
  163. private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
  164. {
  165. if (0 === count($paths)) {
  166. return;
  167. }
  168. $command->add($not ? '-not' : null)->cmd('(');
  169. foreach ($paths as $i => $path) {
  170. $expr = Expression::create($path);
  171. // Find does not support expandable globs ("*.{a,b}" syntax).
  172. if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
  173. $expr = Expression::create($expr->getGlob()->toRegex(false));
  174. }
  175. // Fixes 'not search' regex problems.
  176. if ($expr->isRegex()) {
  177. $regex = $expr->getRegex();
  178. $regex->prepend($regex->hasStartFlag() ? $dir.DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
  179. } else {
  180. $expr->prepend('*')->append('*');
  181. }
  182. $command
  183. ->add($i > 0 ? '-or' : null)
  184. ->add($expr->isRegex()
  185. ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
  186. : ($expr->isCaseSensitive() ? '-path' : '-ipath')
  187. )
  188. ->arg($expr->renderPattern());
  189. }
  190. $command->cmd(')');
  191. }
  192. /**
  193. * @param Command $command
  194. * @param NumberComparator[] $sizes
  195. */
  196. private function buildSizesFiltering(Command $command, array $sizes)
  197. {
  198. foreach ($sizes as $i => $size) {
  199. $command->add($i > 0 ? '-and' : null);
  200. switch ($size->getOperator()) {
  201. case '<=':
  202. $command->add('-size -' . ($size->getTarget() + 1) . 'c');
  203. break;
  204. case '>=':
  205. $command->add('-size +'. ($size->getTarget() - 1) . 'c');
  206. break;
  207. case '>':
  208. $command->add('-size +' . $size->getTarget() . 'c');
  209. break;
  210. case '!=':
  211. $command->add('-size -' . $size->getTarget() . 'c');
  212. $command->add('-size +' . $size->getTarget() . 'c');
  213. case '<':
  214. default:
  215. $command->add('-size -' . $size->getTarget() . 'c');
  216. }
  217. }
  218. }
  219. /**
  220. * @param Command $command
  221. * @param DateComparator[] $dates
  222. */
  223. private function buildDatesFiltering(Command $command, array $dates)
  224. {
  225. foreach ($dates as $i => $date) {
  226. $command->add($i > 0 ? '-and' : null);
  227. $mins = (int) round((time()-$date->getTarget()) / 60);
  228. if (0 > $mins) {
  229. // mtime is in the future
  230. $command->add(' -mmin -0');
  231. // we will have no result so we don't need to continue
  232. return;
  233. }
  234. switch ($date->getOperator()) {
  235. case '<=':
  236. $command->add('-mmin +' . ($mins - 1));
  237. break;
  238. case '>=':
  239. $command->add('-mmin -' . ($mins + 1));
  240. break;
  241. case '>':
  242. $command->add('-mmin -' . $mins);
  243. break;
  244. case '!=':
  245. $command->add('-mmin +' . $mins.' -or -mmin -' . $mins);
  246. break;
  247. case '<':
  248. default:
  249. $command->add('-mmin +' . $mins);
  250. }
  251. }
  252. }
  253. /**
  254. * @param Command $command
  255. * @param string $sort
  256. *
  257. * @throws \InvalidArgumentException
  258. */
  259. private function buildSorting(Command $command, $sort)
  260. {
  261. $this->buildFormatSorting($command, $sort);
  262. }
  263. /**
  264. * @param Command $command
  265. * @param string $sort
  266. */
  267. abstract protected function buildFormatSorting(Command $command, $sort);
  268. /**
  269. * @param Command $command
  270. * @param array $contains
  271. * @param Boolean $not
  272. */
  273. abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
  274. }