Управление зависимостями в Go с помощью dep

Практически в любом проекте рано или поздно возникает необходимость использования сторонних библиотек. Многие современные языки имеют общепринятые пакетные менеджеры для управления зависимостями в приложении. Например npm для Node.js или Composer для PHP.

В Go существует достаточно много инструментов для управления пакетами от разных разработчиков. Некоторые из них даже не написаны на Go.

dep

Одним из таких инструментов является dep. В отличие от других, он был официальным экспериментом разработчиков команды Go, но пока не включен в официальный набор утилит. Поскольку у него есть все шансы стать стандартом, предлагаю с ним ознакомиться.

23 января 2018 года состоялся релиз v0.4.1 и уже готов для использования в production, все нижеизложенное будет справедливо для этой версии.

Установка

Разработчиками рекомендуется скачать готовый бинарник последнего релиза для вашей платформы.

В MacOS установить или обновить до последней версии можно с помощью Homebrew

$ brew install dep
$ brew upgrade dep

Если интересно посмотреть как все работает, можно скачать используя go get

go get -u github.com/golang/dep/cmd/dep

Для компиляции из исходного кода потребуется Go 1.8 или выше.

Инициализация

Как обычно создадим проект в $GOPATH и перейдем в его папку:

mkdir -p $GOPATH/src/github.com/username/hello
cd $GOPATH/src/github.com/username/hello

Инициализация менеджера происходит командой:

dep init

Эта команда создаст в папке проекта папку vendor для хранения библиотек и файлы Gopkg.lock и Gopkg.toml.

Есть еще пара команд:

  • dep ensure – основная рабочая команда для внесения изменений
  • dep status – отчет о состоянии вашего проекта

Главная команда dep ensure. Слово ensure (гарантировать, обеспечивать) означает то, что будет выполнена не дискретная операция (как добавление зависимости), а что-то целостное. Вместо того, чтобы выполнять несколько последовательных команд для изменения состояния проекта, каждый запуск dep ensure обеспечивает полный, безопасный и воспроизводимый набор изменений состояния проекта. Это означает, что на диск будет записано всё или ничего. За исключением критический ситуаций.

Существует четыре ситуации, когда использовать dep ensure:

  • Чтобы добавить новую зависимость
  • Для обновления существующей зависимости
  • Для синхронизации зависимостей в зависимости от появления или удаления операторов import в коде
  • Подхватить изменения в файле Gopkg.toml

Добавление зависимости

Допустим, нам нужен пакет github.com/pkg/errors. Его можно добавить командой:

dep ensure -add github.com/pkg/errors

Команды dep ensure и dep status как и команды git можно вызывать из любых подпапок проекта.

После успешного добавления пакета будет изменен файл Gopkg.lock и содержимое папки vendor. Версия пакета github.com/pkg/errors будет добавлена в Gopkg.toml однако мы получим предупреждение:

"github.com/pkg/errors" is not imported by your project, and has been temporarily added to Gopkg.lock and vendor/.
If you run "dep ensure" again before actually importing it, it will disappear from Gopkg.lock and vendor/.

Это означает, что мы должны использовать import "github.com/pkg/errors" где-то в коде проекта. Иначе после вызова dep ensure этот пакет будет отмечен как неиспользуемый и удалён из папки vendor и файла Gopkg.lock.

Можно поступить наоборот. Сначала использовать import в коде, а затем установить зависимость, например создать файл main.go:

package main
import (
    "github.com/fatih/color"
)
func main() {
    color.Red("Error!")
}

и выполнить dep ensure.

Все зависимости будут разрешены, более того, если до этого dep не был инициирован, то зависимости для существующего кода будут скачаны сразу после dep init.

Обновление зависимостей

Отдельный пакет можно обновить командой:

dep ensure -update github.com/user/project

Или при необходимости попытаться обновить всё сразу:

dep ensure -update

Правила для изменения файла Gopkg.toml

Содержимое директории vendor и файл Gopkg.lock редактировать не нужно, они генерируются автоматически. А файл Gopkg.toml предоставляет пять основных типов правил, для настройки:

  • required – является эквивалентом оператора import в файлах .go. За исключеним того, что здесь можно указать пакет main
  • ignored – позволяет указать игнорируемые пакеты
  • [[constraint]] – определяет как зависимость должна быть включена. Позволяет указать определенную ветку, версию, ревизию или форк
  • [[override]] – отличается от [[constraint]] тем, что действует для текущего проекта и позволяет влиять на версии не только прямых зависимостей, но и зависимостей их зависимостей
  • [prune] – глобальные правила, и правила для проекта, позволяющие определить какие файлы необходимо удалять из папки vendor

После внесения любых изменений в этот файл, вызов dep ensure приведет весь проект в необходимое состояние.