Gitignore.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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;
  11. /**
  12. * Gitignore matches against text.
  13. *
  14. * @author Ahmed Abdou <mail@ahmd.io>
  15. */
  16. class Gitignore
  17. {
  18. /**
  19. * Returns a regexp which is the equivalent of the gitignore pattern.
  20. *
  21. * @param string $gitignoreFileContent
  22. *
  23. * @return string The regexp
  24. */
  25. public static function toRegex(string $gitignoreFileContent): string
  26. {
  27. $gitignoreFileContent = preg_replace('/^[^\\\\]*#.*/', '', $gitignoreFileContent);
  28. $gitignoreLines = preg_split('/\r\n|\r|\n/', $gitignoreFileContent);
  29. $gitignoreLines = array_map('trim', $gitignoreLines);
  30. $gitignoreLines = array_filter($gitignoreLines);
  31. $ignoreLinesPositive = array_filter($gitignoreLines, function (string $line) {
  32. return !preg_match('/^!/', $line);
  33. });
  34. $ignoreLinesNegative = array_filter($gitignoreLines, function (string $line) {
  35. return preg_match('/^!/', $line);
  36. });
  37. $ignoreLinesNegative = array_map(function (string $line) {
  38. return preg_replace('/^!(.*)/', '${1}', $line);
  39. }, $ignoreLinesNegative);
  40. $ignoreLinesNegative = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesNegative);
  41. $ignoreLinesPositive = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesPositive);
  42. if (empty($ignoreLinesPositive)) {
  43. return '/^$/';
  44. }
  45. if (empty($ignoreLinesNegative)) {
  46. return sprintf('/%s/', implode('|', $ignoreLinesPositive));
  47. }
  48. return sprintf('/(?=^(?:(?!(%s)).)*$)(%s)/', implode('|', $ignoreLinesNegative), implode('|', $ignoreLinesPositive));
  49. }
  50. private static function getRegexFromGitignore(string $gitignorePattern): string
  51. {
  52. $regex = '(';
  53. if (0 === strpos($gitignorePattern, '/')) {
  54. $gitignorePattern = substr($gitignorePattern, 1);
  55. $regex .= '^';
  56. } else {
  57. $regex .= '(^|\/)';
  58. }
  59. if ('/' === $gitignorePattern[\strlen($gitignorePattern) - 1]) {
  60. $gitignorePattern = substr($gitignorePattern, 0, -1);
  61. }
  62. $iMax = \strlen($gitignorePattern);
  63. for ($i = 0; $i < $iMax; ++$i) {
  64. $doubleChars = substr($gitignorePattern, $i, 2);
  65. if ('**' === $doubleChars) {
  66. $regex .= '.+';
  67. ++$i;
  68. continue;
  69. }
  70. $c = $gitignorePattern[$i];
  71. switch ($c) {
  72. case '*':
  73. $regex .= '[^\/]+';
  74. break;
  75. case '/':
  76. case '.':
  77. case ':':
  78. case '(':
  79. case ')':
  80. case '{':
  81. case '}':
  82. $regex .= '\\'.$c;
  83. break;
  84. default:
  85. $regex .= $c;
  86. }
  87. }
  88. $regex .= '($|\/)';
  89. $regex .= ')';
  90. return $regex;
  91. }
  92. }