Управление зависимостями в 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
приведет весь проект в необходимое состояние.