предисловие
Редакция: 2020.09.17
Управление пакетами в Golang всегда было одним из пунктов, на который жалуется большинство разработчиков.
Краткая история управления зависимостями Go
Управление пакетами Golang разделено на три этапа: версия = 1.13.
version < 1.11
На данном этапе управление пакетами в Golang имеет следующие недостатки:
- Должна быть установлена переменная среды GOPATH, а исходный код должен храниться в GOPATH.
- При подтягивании внешних зависимостей всегда подтягивается последняя версия, а требуемую версию указать нельзя
Переменная среды GOPATH установлена по двум причинам:
- это предусматривает
go get
Место хранения зависимостей, загруженных командой ($GOPATH/src) - Установив GOPATH, Golang удобно рассчитывать путь импорта
Кроме того, поскольку нельзя указать версию зависимого пакета, легко может возникнуть проблема «локальное тестирование проходит нормально, но онлайн-развертывание завершается неудачно». Такая проблема невыносима для большинства разработчиков, поэтому стали появляться различные инструменты управления пакетами, как правило, dep, glide и т.п., которые здесь повторяться не будут.
1.11 <= version < 1.13
На данном этапе по умолчанию используется метод управления GOPATH, но он начинает поддерживатьGo Module
метод управления.
Go Module устраняет недостатки вышеперечисленных этапов:
1. Больше не требует GOPATH, то есть код вашего проекта можно хранить по желанию
2. Решает проблему версии зависимых пакетов через go.mod + go.sum (будет упомянуто позже)
Если вам нужно перейти на модуль Go, вам необходимо установить следующие переменные среды.
vim ~/.bash_profile
export GO111MODULE=on
version >= 1.13
Начиная с этого этапа, управление пакетами Golang по умолчанию использует Go Module.
GOPATH VS GoModule
Можно сказать, что эти два механизма являются как механизмом управления проектами, так и механизмом управления зависимостями, поэтому их различия в этих двух пунктах заключаются в следующем:
- 1. В плане управления проектами GOPATH придерживается концепции единого рабочего пространства, и все коды хранятся в одном каталоге, а GoModule преодолевает это ограничение и может создавать новые проекты где угодно.
- 2. С точки зрения управления зависимостями, зависимости, загруженные GOPATH, будут храниться в каталоге $GOPATH/src, управление версиями отсутствует, а зависимости GoModule отделены от исходного кода и хранятся в каталоге pkg. включить управление версиями.
Управление зависимостями с помощью GOPATH
Если вы хотите узнать, как использовать GOPATH для управления зависимостями, вы можете обратиться к моей предыдущей статье.Go Guide - Управление зависимостями GOPATH.
Управление зависимостями с модулями Go
Этот раздел переведен с«Использование модулей Go»
Модуль представляет собой набор зависимых пакетов, черезgo mod init xxx
Пустые файлы go.mod и go.sum можно инициализировать, и эти два файла хранятся в корневом каталоге проекта.
Для go.mod он не только хранит пути и версии этих зависимостей, но иТакже указывает корневой путь импорта, для go.sum он хранит ожидаемую контрольную сумму содержимого зависимого пакета, гарантируя, что код, загруженный в последний раз, согласуется с кодом, загруженным сейчас.
Настроить прокси
Так как большинство зависимостей Golang находится за границей, прямая загрузка очень медленная.При отсутствии модуля Go необходимо настроить собственный прокси, например socks, но с модулем Go можно настроить прокси, задав переменные среды. конкретная ссылка:перейти прокси.IO/это/.
При настройке следует учитывать несколько моментов:
1. Если у вас есть частный репозиторий и публичный репозиторий, вам нужно добавитьdirect
параметры и настроитьGOPRIVATE
(для Go1.13)
# 有了direct,GOPRIVATE指定的仓库不会使用代理
go env -w GOPROXY=https://goproxy.io,direct
# 设置不走代理的私有仓库,多个用逗号相隔
go env -w GOPRIVATE=*.corp.example.com
2. Если вы используете Golang IDE, обратите внимание, что IDE также должна быть настроена
3. Если в вашем файле ~/.bash_profile или ~./bashrc есть переменные среды, такие как GO111MODULE, они будут конфликтовать при записи go env.
warning: go env -w GOPROXY=... does not override conflicting OS environment variable
Инициализировать проект
1. Создайте новую папку
mkdir go-module-lab && cd go-module-lab
2. Инициализируйте проект модуля Go, git.own.com/go-module является пользовательским.
go mod init git.own.com/go-module
3. Посмотреть go.mod
module git.own.com/go-module
go 1.13
Пользовательские тесты зависимостей
1. Пользовательская библиотека
mkdir hello && touch hello/hello.go
контент hello.go
package hello
func Hello() string {
return "Hello, world."
}
2. Создайте новый тест main.go со следующим содержимым
package main
import (
"fmt"
// 前面提过,go.mod 指定了import时的根路径
"git.own.com/go-module/hello"
)
func main() {
fmt.Println(hello.Hello())
}
Скачать сторонние тесты зависимостей
1. Обновите файл hello.go и введитеrsc.io/quote
полагаться
package hello
import "rsc.io/quote"
func Hello() string {
return quote.Hello()
}
2. Выполнитьgo run main.go
,встречаАвтоматически загружать зависимости
➜ go-module-lab go run main.go
go: finding rsc.io/quote v1.5.2
go: downloading rsc.io/quote v1.5.2
go: extracting rsc.io/quote v1.5.2
go: downloading rsc.io/sampler v1.3.0
go: extracting rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: finding rsc.io/sampler v1.3.0
go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
Hello, world.
3. Посмотреть go.mod
module git.own.com/go-module
go 1.13
require rsc.io/quote v1.5.2
Как видите, используя метод управления пакетами Go Module, Golang автоматически сделает это за нас.зависимости пакета, добавьте недостающий пакет в go.mod и используйтеrsc.io/quote
Последняя версия. (Под последней версией здесь следует понимать самую последнюю и помеченную версию, если тега нет, будет использоватьсяpseudo-version
способ идентификации, будет описан ниже)
4. Просмотрите все зависимости с помощью команды go list
$ go list -m all
git.own.com/go-module
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
Пополнить:
псевдоверсии
В общем, go.mod использует语义化版本
Чтобы отметить номер версии зависимого пакета, например v1.0.0, v1.0.1.
Он состоит из трех частей:
- Основной номер версии: при внесении несовместимых изменений API, например v1.5.2.
1
- Второстепенный номер версии: когда вы добавляете обратно совместимые функции, например v1.5.2.
5
- Номер редакции: при исправлении проблем обратной совместимости, например 1.5.2.
2
Семантическое управление версиями предусматривает, что один и тот же основной номер версии должен быть обратно совместим. Например, версия 1.5.2 должна быть обратно совместима с версией 1.1.0; если код несовместим, необходимо использовать новый номер версии.
Но семантическая версия основана на случае, когда проект помечен, если некоторые проекты не помечены, Golang будет использоватьpseudo-version
идентифицировать, какv0.0.0-yyyymmddhhmmss-abcdefabcdef
форма.
Среди них yyyymmddhhmmss использует время UTC, abcdefabcdef соответствует хеш-значению (первые 12 цифр) вашего коммита на этот раз,
Для префикса v0.0.0 возможны три случая:
1. Если в вашем проекте нет тега, форма будет v0.0.0-yyyymmddhhmmss-abcdefabcdef
2. Если имя самого последнего тега в вашем проекте — vX.Y.Z-pre, форма — vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
3. Если имя самого последнего тега вашего проекта — vX.Y.Z, форма — vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef
Ссылаться на:golang.org/cmd/go/#Многие люди…
go.sum
Причина файла go.sum в том, что его нельзя определить просто с помощью семантического управления версиями (v1.5.2).Один и тот же код загружается каждый раз через тег v1.5.2.
Например, издатели отмечают свои проекты на GitHub.v1.5.2
После тега вы все равно можете удалить тег, отправить другой контент, а затем ввести его снова.v1.5.2
тег.
Чтобы определить, является ли это одним и тем же кодом, go.sum хранит содержимое конкретной версии модуля.Ожидаемая контрольная сумма, при изменении кода ожидаемая контрольная сумма не совпадает, что приводит к ошибке компиляции.
verifying xxx/base@v1.3.0: checksum mismatch
downloaded: h1:T2eK+D0jzzeu4+S+oP9KvGgovPnl4FjxYShqdNSPrjc=
go.sum: h1:Crwm2FliMjZ3BABjnydOpoJiFPaKcod/zYNOtcB9Xkw=
обновить внешние зависимости
обновить дополнительный номер версии
Обновить дополнительный номер версии относительно просто, просто используйте go get напрямую, например, обновите golang.org/x/text.
go get golang.org/x/text
Глядя на изменения в go.mod мы видимgolang.org/x/text
Номер версии был обновлен с v0.0.0-20170915032832-14c0d48ead0c до v0.3.2. (косвенно указывает, что пакет зависимостей не используется в исходном коде и зависит косвенно)
module git.own.com/go-module
go 1.13
require (
golang.org/x/text v0.3.2 // indirect
rsc.io/quote v1.5.2
)
Кроме того, мы также можем обновиться до определенной версии, перед этим посмотрим, какие версии модуля доступны (в качестве примера возьмем rsc.io/quote)
$ go list -m -versions rsc.io/quote
rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1
Обновление до определенной версии:
go get rsc.io/quote@v1.4.0
если ты хочешьиспользовать определенную ветку, просто замените номер версии на имя ветки (если имя ветки содержит определенный символ, например "/", вы можете заключить имя ветки в двойные кавычки):
go get rsc.io/quote@dev
Обновить основной номер версии
Если вам нужно обновить основной номер версии, вам нужно вручную указать его в коде, потому что разные основные номера версий эквивалентны новой зависимости (библиотеке).
1. Добавьте новые функции
package hello
import (
"rsc.io/quote"
quoteV3 "rsc.io/quote/v3"
)
func Hello() string {
return quote.Hello()
}
func Proverb() string {
return quoteV3.Concurrency()
}
2. Автоматически загружать зависимости
package main
import (
"fmt"
"git.own.com/go-module/hello"
)
func main() {
fmt.Println(hello.Hello())
fmt.Println("proverb", hello.Proverb())
}
3. Посмотреть go.mod
module git.own.com/go-module
go 1.13
require (
golang.org/x/text v0.3.2 // indirect
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1 // indirect
)
Как видно из вышеизложенного, каждый основной номер версии модуля Go представлен отдельным путем, например, v1, v2, v3; кроме того, Golang допускает одновременное существование нескольких основных номеров версий, поскольку пути отличается, это эквивалентно новой библиотеке, поэтому цель состоит в том, чтобы сохранить добавочные миграции.
Например, когда я начал использоватьrsc.io/quote
, позже есть изменения, и он несовместим с предыдущим, это новый основной номер версии, который я могу использовать, напримерrsc.io/quote/v3
, но функция Hello пока не может быть перенесена в версию V3, что подчеркивает роль нескольких версий.
удалить лишние зависимости
По прошествии некоторого времени мы поставилиrsc.io/quote
Весь код перенесен на новую версиюrsc.io/quote/v3
, аналогичный следующему коду
package hello
import (
quoteV3 "rsc.io/quote/v3"
)
func Hello() string {
return quoteV3.HelloV3()
}
func Proverb() string {
return quoteV3.Concurrency()
}
В это время в предыдущем go.modrsc.io/quote
избыточно, мы можем пройтиgo mod tidy
удалить лишнееrsc.io/quote
$ go mod tidy
$ cat go.mod
module git.own.com/go-module
go 1.13
require (
golang.org/x/text v0.3.2 // indirect
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1 // indirect
)
Суммировать
1. go mod init: Инициализировать проект модуля Go и одновременно сгенерировать файлы go.mod и go.sum.
2.go build/test/run: эти три команды автоматически загружают зависимости и обновляют файлы go.mod и go.sum.
3.go list -m all: распечатать все текущие зависимости
4. go get: загрузите пакет зависимостей вручную или измените версию пакета зависимостей.
5. go mod tidy: добавьте недостающие зависимости и удалите неиспользуемые зависимости
Пополнить
go env
Настройте некоторые переменные среды.
# 环境变量说明文档
go help environment
# 环境变量配置文件路径
$ go env GOENV
/Users/xxx/Library/Application Support/go/env
# 列出所有环境变量
go env
# 列出所有环境变量(以json格式)
go env -json
# 修改某个环境变量
go env -w GOPROXY=https://goproxy.io,direct
# 重置某个变量
go env -u GOPROXY
Ссылка/рекомендация
1. Краткая история управления пакетами в Go
2. Первый взгляд на модуль Go
3.Go модули: Как выбирается версия?
4. Расскажите о go.sum