gocorpus: открытый корпус Go кода, поддерживающий запросы

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

На днях я запустил wasm-приложение, которое позволяет запускать gogrep шаблоны на относительно крупном корпусе Go кода (~11 миллионов строк кода).


В этой заметке я напишу как этим пользоваться и зачем оно вообще может быть нужно.


Звёздочки нести сюда Исходный код можно найти здесь: github.com/quasilyte/gocorpus.



Зачем?


Допустим, вы хотите проверить утверждение, что в среднестатистическом Go кода так никто не пишет (или наоборот, что все так пишут). Для этого вам придётся выполнить эти шаги:


  1. Собрать коллекцию Go кода. Несколько репозиториев, желательно разнообразных.
  2. Придумать, как исполнять поиск. Регулярные выражения могут быть не самым подходящим инструментом.
  3. Сделать результаты воспроизводимыми для других людей, чтобы им не пришлось верить вам на слово.

Проект gocorpus решает все эти шаги за вас.


Разве что на момент написания статьи пункт (3) не решён полностью. Другой человек может зайти на страницу и повторить запрос, но "share" не реализован. По задумке, share будет выдавать URL с опциями для запуска: шаблон поиска, фильтры, выбранные репозитории.

Поскольку gocorpus лично мне нужен был для проверки статистики, а не именно для поиска по проектам, результаты сейчас выдаются без информации о локации в исходном коде. Это не принципиальное ограничение: я планирую добавить настройку формата результатов в будущем. Но нужно учитывать, что мне интереснее добавлять агрегацию и инсайты по результатам, а не превращать это в песочницу для gogrep. Например, мне очень хотелось бы вычислять некоторый hit rate для шаблона, чтобы легче было понять частоту результата.


О существующих решениях


Я несколько раз слышал о bigquery корпусе, но, насколько мне известно, это не совсем бесплатная штука. К тому же, я считаю, что этим вариантом не очень удобно пользоваться.


codesearch работает на регулярных выражениях. Этого не всегда достаточно, как я уже упоминал выше. Такая же ситуация с grep.app.


Был ещё старенький корпус от Russ Cox, но он уже в архиве и его содержимое никогда не актуализировалось. Тем более это просто коллекция кода, а не готовое решение всё-в-одном.


Daniel Marti (оригинальный автор gogrep) собрал что-то вроде индекса популярного кода: github.com/mvdan/corpus. В теории, этот индекс можно использовать для формирования набора репозиториев, доступных в моём приложении.


Корпус кода


Для выбора репозиториев я делал поиск по GitHub с фильтрами и сортировкой по количеству звёздочек. Не самый научный подход, но он достаточно хорош для первой итерации.


После этого выбранные репозитории клонируются, анализируются, минифицируются и кладутся в tar архивы со сжатием.


По мере анализа файлов, мы записываем в метаданные некоторые метрики и факты о файле. Например, импортирует ли файл "unsafe" или "C" (cgo). Эту информацию затем можно использовать в фильтрах.


На клиенте мы качаем tar.gz файлы и на месте их разжимаем.


Подробнее о том, как собирается корпус, можно посмотреть в makecorpus.



Фильтры


На текущий момент реализованы следующие фильтры:


  • $var.IsConst() выражение, захваченное $var является константой
  • $var.IsPure() выражение, захваченное $var не имеет побочных эффектов
  • file.IsTest() true для файлов с суффиксом _test.go в названии или _test в имени пакета
  • file.IsMain() true для файлов с именем пакета main
  • file.IsAutogen() true для файлов, которые размечены как автоматически сгенерированные

Фильтры — это обычные Go выражения. Их можно сочетать через &&. Также можно использовать ( и ) для группирования, а ! для инвертирования эффекта.


file — это предопределённая переменная, которая привязана к текущему обрабатываемому файлу. $<var> — это переменная из шаблона поиска.


  • $x.IsConst() && !file.IsTest() — не искать в тестах, $x должен быть константным.
  • $x.IsPure() && !$y.IsPure()$x должен быть чистым выражением, а $y — нет.
  • !file.IsAutogen() && !file.IsTest() — не искать в тестах и автоматически сгенерированных файлах.

Если вы пользовались ruleguard, то вам это может напомнить фильтры в Where().


Примеры запросов


Приведу несколько примеров поисковых шаблонов.


Шаблон Описание
copy($_, []byte($_)) Находим избыточные конвертации к []byte.
reflect.DeepEqual($x, $x) Сомнительное использование DeepEqual.
if err != nil { return nil } Потенциальные опечатки в обработке ошибок.
ioutil.ReadAll($_) Находим использования deprecated функции.
var() Пустой gen decl блок для переменных.
len($_) >= 0 Ошибочная проверка длины (always true).

Одинаковые имена переменных будут требовать идентичных матчей. То есть $x = $x находит только самоприсваивания, а $x = $y может найти любые присваивания (в том числе и самоприсваивания). Исключением из правил является $_ — пустая переменная не требует соответствий даже если она используется несколько раз.


Вот паттерн посложнее: map[$_]$_{$*_, $k: $_, $*_, $k: $_, $*_}. Он находит map-литералы, которые содержат ключи-дубликаты. Модификатор * работает прямо как в регулярных выражениях: будет 0 или более матчей. Чтобы найти любые вызовы fmt.Printf, мы можем сделать такой шаблон: fmt.Printf($*_).


Переменная с модификатором необязательно должна быть пустой. Например, вот это тоже валидный шаблон: fmt.Printf($format, $*args).


Модификатора + нет, но его часто можно эмулировать вот так: f($_, $*_) — вызовы f с одним или более аргументами.


Больше примеров шаблонов можно подсмотреть в правилах go-critic.



Если вы считаете, что нужно добавить какой-то репозиторий в корпус, сообщите мне об этом. Аналогично, если не хватает какой-то фичи или вы нашли баг, тоже открываем issue и я постараюсь это исправить.


Буду рад обратной связи.


P.S. — у меня мало опыта работы с фронтендом, поэтому код на TypeScript и вёртска оставляют желать лучшего. Если кто-то поможет с этой частью, я буду очень признателен.

Источник: https://habr.com/ru/post/593349/


Интересные статьи

Интересные статьи

ВведениеВ данной статье я бы хотел рассмотреть проблему обновления PHP в виртуальной машине BitrixVM, и действия, которые возможно применить если выполнение переезда на машину с обновленным ПО невозмо...
В октябре 2020 с платформы Ютюб исчезло более тысячи мультфильмов т.н. золотой коллекции, снятых во времена Советского Союза на студии Союзмультфильм. В январе 2021 пользователи заметили, что коллекци...
Всем привет! Вступление Меня зовут Алексей Клоков, я хочу рассказать о запуске классного курса по обработке естественного языка (Natural Language Processing), который очередной раз запускают фи...
Продолжаем тему аддитивного производства, и сегодня расскажем про внутренний корпус двигателя российского вертолета ВК-2500, полностью созданный методом SLM. Разработан корпус совместно НИТУ «МИС...
Получить трафик для интернет-магазина сегодня не проблема. Есть много каналов его привлечения: органическая выдача, контекстная реклама, контент-маркетинг, RTB-сети и т. д. Вопрос в том, как вы распор...