Перейти к содержимому

Обходчик файлов

Каждый режим Greph (текст, AST, переписывание, индексированный текст, индексированный AST, кэшированный AST, оболочка rg, оболочка sg) начинает работу с обхода дерева файлов и создания Greph\Walker\FileList. Обходчик общий, поэтому везде действуют одни и те же флаги и правила.

Поведение по умолчанию

По умолчанию обходчик:

  • Рекурсивно обходит все каталоги в заданных путях.
  • Соблюдает правила .gitignore и .grephignore на каждом уровне, включая вложенные переопределения и отрицания.
  • Пропускает каталог .git.
  • Пропускает скрытые файлы и каталоги (имена которых начинаются с .).
  • Пропускает бинарные файлы (определяет их по нулевым байтам в первых 512 байтах файла).
  • Пропускает файлы размером более 10 MiB.
  • Не переходит по символьным ссылкам.

Флаги переопределения

Флаг Действие
--no-ignore Не учитывать правила .gitignore и .grephignore
--hidden Включать скрытые файлы и каталоги
--type NAME Включать только файлы, соответствующие указанному псевдониму типа
--type-not NAME Исключать файлы, соответствующие указанному псевдониму типа
--glob GLOB Включать только файлы, пути которых соответствуют GLOB. Можно повторять.

Те же параметры доступны для программного использования через Greph\Walker\WalkOptions.

PHP
use Greph\Greph;
use Greph\Walker\FileTypeFilter;
use Greph\Walker\WalkOptions;

$files = Greph::walk('src', new WalkOptions(
    respectIgnore: false,
    includeHidden: true,
    fileTypeFilter: new FileTypeFilter(['php']),
    globPatterns: ['src/**/*.php'],
));

Псевдонимы типов файлов

Greph включает небольшой набор именованных типов файлов. Каждый псевдоним соответствует списку расширений:

Псевдоним Расширения
css css, sass, scss
html htm, html, phtml
js cjs, js, mjs
json json
md markdown, md
php inc, php, php3, php4, php5, php7, php8, phpt, phtml
txt txt
ts ts, tsx
xml xml
yaml yaml, yml

Полный список находится в Greph\Walker\FileTypeFilter::TYPE_MAP.

Семантика .gitignore

Greph реализует сопоставление правил gitignore на чистом PHP. Семантика соответствует git check-ignore:

  • Шаблоны оцениваются относительно каталога, в котором они находятся.
  • Вложенные файлы .gitignore переопределяют правила родительских каталогов.
  • Отрицание (!pattern) снова включает путь, который ранее был исключен.
  • Завершающий / ограничивает шаблон каталогами.
  • Начальный / привязывает шаблон к каталогу, где находится .gitignore.
  • ** соответствует любому количеству сегментов пути.

.grephignore использует тот же синтаксис и дополняет .gitignore. Здесь удобно задавать исключения для конкретного инструмента, которые не должны попадать под контроль версий.

Реализация находится в Greph\Walker\GitignoreFilter.

Обнаружение бинарных файлов

Обходчик проверяет первые 512 байтов каждого файла на наличие нулевых байтов. Если они обнаружены, файл считается бинарным и пропускается. Это позволяет отсеивать распространенные случаи, когда в индексируемом каталоге репозитория находятся изображения, архивы или скомпилированные файлы.

Чтобы искать и в бинарных файлах, задайте skipBinaryFiles: false для соответствующего объекта Options. В CLI сейчас нельзя задать этот флаг; используйте фасад.

По умолчанию обходчик не переходит по символьным ссылкам. Чтобы включить их обход, задайте followSymlinks: true или передайте -L / --follow в оболочку rg. Обходчик отслеживает посещенные каталоги, чтобы циклы символьных ссылок не приводили к бесконечной рекурсии.

Максимальный размер файла

Файлы размером более maxFileSizeBytes (по умолчанию 10 MiB) пропускаются. Это защищает сканирование от случайной загрузки в память файла журнала размером 1 GB. Если нужно обрабатывать файлы большего размера, измените ограничение в объекте Options.

Зачем нужен собственный обходчик

Greph мог бы использовать glob() или RecursiveDirectoryIterator, но ни один из них не реализует семантику gitignore, не учитывает .grephignore и не интегрируется с пулом рабочих процессов. Единый обходчик для всех режимов гарантирует, что каждый режим применяет одинаковые правила фильтрации. Это важно для стратегии тестирования на основе oracle: сравнение с grep, ripgrep и ast-grep возможно только при обходе того же набора файлов, что и у этих инструментов.