С недавнего времени в golang появилась система управления зависимости. В данной статье будут только основные моменты, как можно решать базовые задачи управления зависимостями.
Введение
Системы управления зависимостями есть в почти каждом языке программирования, в некоторых даже два. Например в php это getcomposer.org, в js это npmjs.com. Но разработчики golang оставили этот момент на сообщество, и в итоге получили несколько решений например dep и vgo, разнообразие это конечно хорошо, но не в ключевых моментах. Разработчикам библиотеки не понятно какие лучше использовать, поскольку не известно кто будет использовать(какая у нах система контроля). С выходом golang 1.11 добавили команду `go mod`, к этому моменту большинство разработчиков уже использовало какую-то из систем, а некоторые даже сохраняли зависимость в своем репозитории. Основные моменты которые нам дает `go mod` это повторяемость сборки как следствие не нужна папка vendor, и так как официальная система контроля версий то очень большая вероятность что библиотеки которые вам нужны уже ее используют. Если вам нужна полная документация то тут ее не будет можете прочитать из первоисточника.
Инициализация
Заходите в папку проекта и запускаете команду go mod init
учитывайте только, что он берет название проекта от $GOPATH/src
поэтому если по каким-то причинам ваш проект лежит к примеру в $GOPATH/src/github.com/myname/myasesomeproject
то необходимо в файле `go.mod` поправить module ...
на имя проекта из репозитория, иначе будут проблемы установкой вашего проекта как зависимости. Одна из полезных команд go mod tidy
которая позволяет ваш go.mod
держать в чистоте. После предыдущих двух команд нужно сделать только go mod download
и и можно использовать go run
или go build
, все просто.
Установка зависимостей
В проекте необходимо выполнить go get package@latest
, при этом в go.mod
и go.sum
добавляется новый пакет, и следующий build будет использовать ту же версию пакета которая прописана в go.mod
. Если что-то пошло не так то используйте команду go get -v package@latest
что покажет в каком моменте что-то пошло не так.
Замена зависимостей
Бывают моменты когда необходимо заменить пакет на такой же, к примеру в исходном пакете найден баг или он стал недоступен по старому url. Для этого существует директива replace
в файле go.mod
например
replace bou.ke/monkey v1.0.1 => github.com/bouk/monkey v1.0.1
Но все же я бы предлагал отказываться от таких зависимостей. Из выше перечисленного получается такой порядок действий при баге в стороне пакете:
- fork пакета в свой репозиторий и исправление бага
- добавление директивы
replace
вgo.mod
- создание Pull request в исходный репозиторий, поскольку как только вы поставили
replace
все остальные исправления не будут вам приходить.
Если к примеру вы знаете где находится зависимость но там не поддерживается функциональность go get ...
можно указать путь на git к примеру если по каким-то причинам GitLab перестал правильно работать с go mod
можно добавить replace
replace ( gitlab.com/4devs/pass => gitlab.com/4devs/pass.git v0.0.2 gitlab.com/4devs/pass/password => gitlab.com/4devs/pass.git/password v0.0.0-20190819053721-35c7ec7a72b1 )
В данном примере показано не только путь к пакету но и ко вложенному пакету. К сожалению до сих пор Gitlab плохо работает со вложенными группами если они не public, и вам прийдется ставить такие `replace` во все вложенные пакеты для gitlab. Так же replace
работает с локальной структурой папок, например можно использовать такой подход
module github.com/go-4devs/httpclient/json replace ( github.com/go-4devs/httpclient/dc => ../dc github.com/go-4devs/httpclient/decoder => ../decoder ) require ( github.com/go-4devs/httpclient/dc v0.0.0-20190814063109-82955e154764 github.com/go-4devs/httpclient/decoder v0.0.0-20190814063109-82955e154764 )
В данном примере просто сделала реализация клиента той же библиотеки, вложенность может быть и другого пакета.
Стоит также учитывать что `replace` работает только в рамках текущего пакета где прописан, например в предыдущем примере github.com/go-4devs/httpclient/decoder
, будет все равно скачиваться теми кто использует github.com/go-4devs/httpclient/json
.
Версионирования
Для указания версии используется SemVer, ставим git тэг формата v0.1.1
, обязательно начинать с v..
. Версия v0.1.1
используется как имя пакета в импорте. Начиная с v2.0.0
к имени пакета добавляться путь .../v2
что позволяет использовать обе версии в одном приложении, или по крайней мере переходить постепенно. Если у вас один репозиторий и много пакетов, то на каждый пакет можно поставить версию просто добавив тэг формата path/to/pkg/v0.0.1
. Например для github.com/go-4devs/httpclient/dc
будет dc/v0.0.1
.
Выводы
Управление зависимостями пришло и в golang, и сделано удобно, что позволяет не только повторять сборки, но и полностью отказаться от папки `vendor`. Также есть удобный механизм исправления багов в зависимостях как и можно полностью их заменить. Добавляются новые возможность такие как GOPROXY, GONOSUMDB и тп.
Для того чтобы выбирать пакеты которые с меньшей вероятностью преподнесут вам сюрпризы есть ресурсы, например Go Report Card.