11. go list и introspection проекта

Рентген вашего проекта

Если go env показывает глобальные настройки среды выполнения и тулчейна, то go list позволяет заглянуть внутрь структуры самого проекта. Это команда-инспектор, которая отвечает на ключевой вопрос компилятора: "Что Go реально видит в моих каталогах и файлах, прежде чем начнет строить бинарник?".

В классическом Unix-мире инженеры привыкли опрашивать файловую систему скриптами на базе find, grep и awk. Но в Go такой наивный подход быстро дает сбой: файл app_windows.go не должен компилироваться на Linux, файлы *_test.go не должны попадать в продакшн-сборку, а некоторые пакеты могут быть исключены из-за build-тегов //go:build. Для Senior-разработчика go list — это не просто способ узнать имена пакетов. Это фундаментальный инструмент интроспекции, анализа графа импортов и построения гибких Makefile и CI/CD пайплайнов.


JSON как API к тулчейну

Главная сила go list — возможность выводить информацию не плоским текстом, а в структурированном формате JSON (флаг -json). Это превращает утилиту в полноценное программное API к загрузчику пакетов (cmd/go/internal/load). Под капотом go list оперирует теми же структурами данных, что и компилятор, заполняя поля метаданными о файлах, импортах, зависимостях и ошибках.

Попробуйте выполнить в корне проекта:

Bash
go list -json ./...

Вы получите подробный массив данных. Вот как выглядит структура информации для каждого отдельного пакета:

flowchart TD
    classDef process  fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
    classDef success  fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
    classDef error    fill:#7f1d1d,stroke:#f87171,stroke-width:1px,color:#f8fafc
    classDef warning  fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
    classDef entry    fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
    classDef aux      fill:#334155,stroke:#64748b,stroke-width:1px,color:#f8fafc
    classDef system   fill:#312e81,stroke:#a78bfa,stroke-width:1px,color:#f8fafc
    classDef data     fill:#132d29,stroke:#2dd4bf,stroke-width:1px,color:#f8fafc
    classDef network  fill:#881337,stroke:#fb7185,stroke-width:1px,color:#f8fafc
    classDef accent   fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
    subgraph Output ["Структура Package JSON"]
        Dir["Dir: /path/to/project/pkg"]:::process
        ImportPath["ImportPath: github.com/user/project/pkg"]:::entry
        Name["Name: pkg"]:::process
        GoFiles["GoFiles: .go файлы"]:::process
        Imports["Imports: зависимости"]:::process
        Deps["Deps: транзитивные зависимости"]:::process
    end

    subgraph Advanced ["Дополнительные поля"]
        TestGoFiles["TestGoFiles: _test.go файлы"]:::process
        XTestGoFiles["XTestGoFiles: внешние тесты"]:::process
        Error["Error: ошибки компиляции"]:::error
    end
  

Полезные флаги и шаблоны

Выводить полный JSON каждый раз избыточно. Для интеграции со скриптами автоматизации используется мощный механизм шаблонов Go (флаг -f), позволяющий извлекать конкретные поля структуры пакета.

1. Список всех зависимостей

Чтобы узнать, от каких пакетов зависит ваш проект (прямо или транзитивно):

Bash
go list -f '{{.Deps}}' ./...

2. Поиск main пакетов

Если у вас монорепозиторий с несколькими сервисами в каталоге cmd, вы можете программно найти все исполняемые точки входа:

Bash
# Найдет все пакеты с именем main
go list -f '{{if eq .Name "main"}}{{.ImportPath}}{{end}}' ./...

3. Файлы для компиляции

Иногда нужно передать список всех реальных .go файлов (исключая тесты) в кастомный линтер или анализатор:

Bash
go list -f '{{range .GoFiles}}{{$.Dir}}/{{.}}{{"\n"}}{{end}}' ./...

Флаг -deps: Полный граф

Флаг -deps расширяет список выводимых пакетов. Без него go list ./... покажет только ваши локальные пакеты. С ним — вы получите дерево всех зависимостей, включая стандартную библиотеку и сторонние модули.

Это полезно для:

  • Анализа "раздувания" бинарника (какие библиотеки тянутся).
  • Поиска уязвимостей (проверка версий вложенных зависимостей).
  • Визуализации графа зависимостей.

Кроме того, режим go list -m all опрашивает модули (а не пакеты), выводя полный список зафиксированных в go.mod внешних модулей с их точными версиями.


Работа с ошибками (-e)

Обычно, если пакет содержит синтаксические ошибки или сломанные зависимости, go list немедленно завершает работу с кодом ошибки. Но при построении диагностических инструментов и плагинов IDE нам критически важно получить метаданные обо всех корректных пакетах, даже если соседний пакет временно сломан. Флаг -e указывает команде игнорировать сбои и транслировать ошибки прямо в поле Error структуры JSON:

JSON
{
  "ImportPath": "broken/pkg",
  "Error": {
    "ImportStack": ["broken/pkg"],
    "Pos": "broken/pkg/main.go:5:2",
    "Err": "undefined: someVar"
  }
}

go list в Real World

Главный кейс использования — написание умных Makefile. Например, вы хотите запустить линтеры параллельно над всеми файлами, или сгенерировать документацию только для экспортируемых пакетов.

Пример скрипта для поиска всех go-файлов для статического анализатора:

Bash
FILES=$(go list -f '{{range .GoFiles}}{{$.Dir}}/{{.}} {{end}}' ./...)
my-custom-tool $FILES

Также именно go list используется редакторами кода (VSCode, GoLand) и сервером языка gopls для формирования списка файлов, отображения структуры проекта и навигации. Если ваш проект странно ведет себя в IDE, иногда помогает ручной запуск go list -e -json ./... чтобы увидеть, не отвалился ли какой-то пакет из-за ошибок сборки.


Итог

  1. go list — это API для интроспекции проекта через консоль.
  2. Формат вывода -json идеален для парсинга скриптами и CI.
  3. Шаблоны -f позволяют фильтровать данные прямо на этапе запроса.
  4. Флаг -deps показывает полное дерево зависимостей.
  5. Используйте этот инструмент для автоматизации рутины (поиск файлов, пакетов).

Мы научились "рентгенить" структуру проекта. Теперь пора углубиться в то, как эта структура связана с внешним миром — зависимостями. В следующей статье мы разберем фундамент современной Go-разработки: 12. Модули. go.mod и go.sum.