Команды Go и переменные среды, которые должен знать каждый разработчик

Работаете на Go? Тогда вы наверняка сталкивались с этими загадочными GOPATH, GOPRIVATE, Go111module и т. д. Хлопот они обычно не доставляют, но иногда возможны ошибки, из-за которых разработка резко замедляется.

Покажем, как этих ошибок избежать. Итак, начнем!

Внимание: применимо только к Go 1.15 и новее.

GOROOT

В GOROOT хранится SDK для Go

GOROOT  —  это место хранения SDK для Go, компиляторов по умолчанию, исполняемых команд и библиотек. Не изменяйте эту переменную, если не переходите на другую версию Go.

При импорте библиотеки поиск файла начинается с GOROOT. Если файл не найден, поиск продолжается в GOPATH.

GOPATH

Три подкаталога GOPATH

В GOPATH имеется три каталога: pkg, src и bin.

$GOPATH/pkg

  • $GOPATH/pkg/mod  —  это местоположение кеша модулей по умолчанию, где хранятся и кешируются загруженные через go get или go install зависимости.
  • Оно изменяется посредством редактирования переменной GOMODCACHE в go env.

$GOPATH/bin

  • В каталоге bin хранятся установленные через go install исполняемые команды, в том числе сторонние и из исходных файлов.
  • Стандартные команды, такие как gofmt, хранятся в каталоге GOROOT/bin.

$GOPATH/src

  • В каталоге src хранятся исходные файлы.
  • Но с появлением модулей он менее значим.

Модули Go

До модулей проекты и зависимости на Go хранились в каталоге $GOPATH/src/.

Контроль версий отсутствовал. В проектах каталога src библиотеки использовались в одной и той же стабильной версии, ветке master.

Появились модули, и теперь:

  • проекты можно создавать вне каталога $GOPATH/src/;
  • проект, он же модуль,  —  это набор выпускаемых вместе файлов и пакетов;
  • в каждом модуле содержится файл go.mod, которым определяются требуемые зависимости и версии;
  • зависимости загружаются из соответствующих репозиториев во время сборки.

Go.mod

В Go.mod содержатся зависимости модуля и путь к нему

Файлом go.mod определяются:

  • путь к модулю, используемый при импорте пакетов/файлов в одном и том же модуле Go;
  • зависимости и версии, необходимые для успешной сборки модуля.

Go.sum

В Go.sum находится список контрольных сумм

При сборке на удаленном сервере в модуль из соответствующих систем контроля версий добавляются и загружаются указанные в файле go.mod зависимости.

Здесь неизбежны проблемы:

  • Что, если кто-то намеренно поменяет версию библиотеки?
  • Как гарантировать, что на удаленном сервере добавляется библиотека с точным содержимым локальной копии?

Но с go.sum они решаются:

  • Это контрольная сумма всех прямых и косвенных зависимостей, перечисленных в go.mod.
  • Ею проверяется и гарантируется, что локальная загруженная копия зависимостей аналогична удаленной.

Go mod tidy

Запуск Go mod tidy для обновления go.mod

При запуске go mod tidy:

  • нужные зависимости загружаются, а ненужные из go.mod удаляются;
  • из локального кеша, то есть $GOPATH/pkg/mod, библиотеки не удаляются.

Go clean -modcache

Когда в Go выполняется go get или go mod tidy, зависимости загружаются и кешируются в GOMODCACHE, то есть в $GOPATH/pkg/mod/ по умолчанию.

Этими кешированными библиотеками локальная разработка и локальная сборка сглаживаются.

Все загруженные пакеты удаляются из каталога GOMODCACHE с помощью go clean -modcache.

Go mod vendor

Командой Go mod vendor в текущем модуле создается каталог vendor

При сборке на удаленном сервере в модуль добавляются и загружаются указанные в файле go.mod зависимости.

Но проблема с сетью или удаление одной из зависимостей в системе контроля версий чревато ошибками сборки.

Чтобы гарантировать воспроизводимую сборку, командой go mod vendor в модуле создается папка и в каталоге сохраняются исходные файлы зависимостей.

Каталог vendor сохраняется вместе с изменением кода.

Так обеспечивается:

  • воспроизводимость и последовательность сборки;
  • легкость просмотра изменений в зависимостях.

Однако каталог занимает дополнительное место и увеличивается время клонирования репозитория. В итоге CI/CD удлиняется.

GOPROXY

До появления GOPROXY зависимости загружались из удаленных систем контроля версий напрямую.

Имелись две фундаментальные проблемы  —  безопасность и доступность. Зависимости в удаленной системе контроля версий можно было:

  • в любое время удалить;
  • изменить и скомпрометировать.

GOPROXY  —  это централизованный репозиторий, в котором размещаются и кешируются общедоступные сторонние модули.

Теперь каждый запрос на загрузку перенаправляется на общедоступный GOPROXY, а загруженный модуль проверяется на соответствие общедоступной базе данных контрольных сумм.

GOPROXY настраивается в go env. По умолчанию:

GOPROXY="https://proxy.golang.org"

Если нужный модуль в GOPROXY не найден, добавляем direct:

GOPROXY="https://proxy.golang.org,direct"

и загружаем модуль из удаленной системы контроля версий.

GOPRIVATE

С общедоступными модулями хорошо справляется GOPROXY. А что, если нужна зависимость из приватного репозитория, например репозитория компании?

Какие модули считать приватными, определяется командой GOPRIVATE. Например:

GOPRIVATE=*github.com/org_name

В Go любой путь, соответствующий такому шаблону, приватный. Следовательно, прокси- и глобальная база данных контрольных сумм не используются.

Go111module

GO111module означает режим с поддержкой модулей.

Диспетчера пакетов в Go не было до версии 1.11, когда появились модули. Зависимости получались через go get и сохранялись с исходными файлами в $GOPATH/src.

С появлением модулей загрузка, импорт и сохранение зависимостей изменились.

При GO111module=on в Go активировано модульное поведение, при GO111module=off  —  поведение GOPATH.

Поскольку модули Go теперь применяются на практике, поведение по умолчанию  —  GO111module=on.

Заключение

У команд Go и переменных среды́ еще много нюансов.

Мы рассмотрели те, что встречаются в рабочем процессе разработки почти каждый день.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Jason Ngan: Go Commands and Env Vars Every Developer Should Know

Предыдущая статьяКак упростить автоматизированное тестирование компонентов React
Следующая статьяРеализация структурированной конкурентности в Java и Kotlin