Руководство по Go — Управление зависимостями GoModule

Go

предисловие

Редакция: 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