Версии 1.11 и 1.12 Go включают начальную поддержку модулей — новую систему управления зависимостями Go, которая делает информацию о версии зависимостей явной и упрощает управление. В этом сообщении блога рассматриваются основные операции, необходимые для начала работы с модулями.
Модули хранятся в корневом каталоге сgo.mod
Коллекция пакетов Go в файловом дереве файла.go.mod
Файл определяет путь модуля модуля (также путь импорта корневого каталога модуля) и требования других модулей, от которых зависит модуль, так что модуль может быть успешно собран, если требования зависимости выполнены. Требования для каждого зависимого модуля записываются в виде пути к модулю и соответствующей версии модуля.
Ниже показано простоеgo.mod
документ
module example.com/hello
go 1.12
require rsc.io/quote v1.5.2
Начиная с Go 1.11, когда текущий каталог или любой родительский каталогgo.mod
, пока каталог находится в$GOPATH/src
Кроме того, команда go может использовать модули. (существует$ GOPATH/src
Внутренне, для совместимости, даже если найденоgo.mod
, команда go по-прежнему выполняется в старом режиме GOPATH. ) начиная с Go 1.13, модульный режим будет режимом по умолчанию для всей разработки.
В этой статье описывается ряд общих действий, которые происходят при разработке кода Go с использованием модулей:
- Создайте новый модуль.
- Добавьте зависимости модуля.
- Обновите зависимости модуля.
- Увеличьте основную версию зависимости.
- Обновите зависимости до новой основной версии.
- Удалите неиспользуемые зависимости.
Создать новый модуль
существует$GOPATH/src
Создайте новый пустой каталог где-нибудь, кроме нового каталога, затем создайте новый исходный файл в новом каталоге.hello.go
:
package hello
func Hello() string {
return "Hello, world."
}
Также напишите свой тестовый файлhello_test.go
package hello
import "testing"
func TestHello(t *testing.T) {
want := "Hello, world."
if got := Hello(); got != want {
t.Errorf("Hello() = %q, want %q", got, want)
}
}
Предположим, что наш вновь созданный каталог/home/gopher/hello
, в этот момент каталог содержит пакет, а не модуль, потому что нетgo.mod
документ. Запустив тест с помощью команды go, вы увидите:
$ go test
PASS
ok _/home/gopher/hello 0.020s
$
Последняя строка вывода суммирует тестовую информацию для всего пакета. потому что мы работаем в$GOPATH
и любой модуль, команда go не знает путь импорта текущего каталога (путь импорта — это уникальный строковый идентификатор, который идентифицирует пакет), поэтому создается фальшивый путь импорта на основе местоположения каталога_/home/gopher/hello
давайте использоватьgo mod init
Установите текущий каталог в качестве корневого каталога модуля и выполните снова.go test
:
$ go mod init example.com/hello
go: creating new go.mod: module example.com/hello
go mod init
команда пишетgo.mod
документ:
$ cat go.mod
module example.com/hello
go 1.12
$
go.mod
Появляется только в корневом каталоге модуля. Путь импорта для пакета, расположенного в подкаталоге, будет состоять из пути к модулю и пути к подкаталогу. Например, если мы создадим подкаталогworld
Не нужно (и не хочется) в нем бегатьgo mod init
.该包将自动被识别为example.com/hello
часть модуля, путь импортаexample.com/hello/world
.
запустить его сейчасgo test
Результаты его работы следующие:
$ go test
PASS
ok example.com/hello 0.020s
$
Теперь путь импорта на выходе становитсяexample.com/hello
, неосознанно пишем и тестируем наш первый модуль go.
добавить зависимости модуля
Основная мотивация для модулей Go — улучшить опыт управления кодом, написанным другими разработчиками (зависимости кода). давайте обновимhello.go
импортироватьrsc.io/quote
и использовать его для достиженияHello
функция:
package hello
import "rsc.io/quote"
func Hello() string {
return quote.Hello()
}
теперь беги сноваgo test
:
$ go test
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: finding rsc.io/sampler v1.3.0
go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
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
PASS
ok example.com/hello 0.023s
$
go
команда, используемая вgo.mod
Указанная версия модуля зависимостей, указанная в разрешении импорта при обнаруженииgo.mod
При импорте пакета, предоставленного любым модулем вgo
Команда автоматически найдет модуль, содержащий пакет, использует его последнюю стабильную версию и добавит его в go.mod. В нашем примереgo test
импортировать новыйrsc.io/quote
решаетrsc.io/quote v1.5.2
модуль, который также загружаетrsc.io/quote
Две используемые зависимости, а именноrsc.io/sampler
иgolang.org/x/text
. Но только прямые зависимости задокументированы вgo.mod
В файле:
$ cat go.mod
module example.com/hello
go 1.12
require rsc.io/quote v1.5.2
$
бежать сноваgo test
Команда не повторяет описанную выше работу по загрузке зависимостей, потому чтоgo.mod
теперь обновлен, а загруженные модули кэшируются локально в$ GOPATH/pkg / mod
бинго.
Как мы видели выше, добавление прямой зависимости часто влечет за собой и другие косвенные зависимости. Команда go list -m all выводит текущий модуль и все его зависимости:
$ go list -m all
example.com/hello
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
$
существуетgo list
В выводе текущий модуль, также известный как основной модуль, всегда появляется в первой строке, за которой следуют отображаемые зависимости, отсортированные по пути к модулю:
Кромеgo.mod
Кроме,go
Команда также поддерживает файл с именемgo.sum
, который содержит криптографические хэши версий зависимых модулей:
$ cat go.sum
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZO...
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:Nq...
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3...
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPX...
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/Q...
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9...
$
использовать команду gogo.sum
файл, чтобы гарантировать, что будущие загрузки этих модулей будут такими же, как и первая загрузка, чтобы гарантировать, что модули, от которых зависит проект, не будут случайно изменены из-за злонамеренных, случайных или других причин. также**go.sum
не похожеpackage-lock.json
Файл блокировки диспетчера пакетов**, который представляет собой файл отслеживания состояния сборки. Он записывает все прямые и косвенные зависимости текущего модуля, а также контрольные суммы этих зависимостей, тем самым обеспечивая 100% воспроизводимый процесс сборки и гарантии безопасности построенных объектов. такдолжно бытьgo.mod
иgo.sum
добавляются в систему контроля версий.go.sum
При этом информация о версиях пакетов, использовавшихся в прошлом, будет сохранена для возможного отката версии в будущем, что также отличается от обычных файлов блокировки. Таким образом, go.sum не является файлом блокировки менеджера пакетов.
обновить зависимости
Для модулей Go используйте семантический тег версии для ссылки на версию модуля. Семантическое управление версиями состоит из трех частей: основной, дополнительной и исправления. Например, для версии 0.1.2 основная версия — 0, дополнительная версия — 1, а версия исправления — 2. Давайте пройдемся по нескольким второстепенным обновлениям версии. В следующем разделе мы рассмотрим возможность обновления основной версии.
отgo list -m all
в выводе мы видим, что мы используем немаркированную версиюgolang.org/x/text
. Давайте обновимся до последней версии с тегами и проверим, что все работает:
$ go get golang.org/x/text
go: finding golang.org/x/text v0.3.0
go: downloading golang.org/x/text v0.3.0
go: extracting golang.org/x/text v0.3.0
$ go test
PASS
ok example.com/hello 0.013s
$
Испытание прошло. давайте посмотрим еще разgo list -m all
Вывод и содержимое файла go.mod:
$ go list -m all
example.com/hello
golang.org/x/text v0.3.0
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
$ cat go.mod
module example.com/hello
go 1.12
require (
golang.org/x/text v0.3.0 // indirect
rsc.io/quote v1.5.2
)
$
golang.org/x/text
Пакет обновлен до последней версии с тегами (v0.3.0).go.mod
в файлеgolang.org/x/text
Также обновлено, чтобы указатьv0.3.0
.indirect
Аннотация указывает, что зависимость используется не непосредственно текущим модулем, а модулями, от которых она зависит.
Теперь попробуем обновитьrsc.io/sampler
Для указанной версии сначала перечислите ее доступные версии:
$ go list -m -versions rsc.io/sampler
rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
$
мы будемrsc.io/sampler
обновитесь доv1.3.1
$ go get rsc.io/sampler@v1.3.1
go: finding rsc.io/sampler v1.3.1
go: downloading rsc.io/sampler v1.3.1
go: extracting rsc.io/sampler v1.3.1
$ go test
PASS
ok example.com/hello 0.022s
$
Обратите внимание на явный @v1.3.1 в параметре go get. В общем, каждый параметр, передаваемый в get, может принимать явную форму. Значение по умолчанию — @latest, которое преобразуется в последнюю ранее определенную версию.
Добавьте основную версию зависимости
Добавим в пакет новую функцию: functionProverb
позвонивquote.Concurrency
Возвращаясь к поговорке о параллелизме Go (то есть к золотой фразе, которую Пайк произнес на конференции по разработке Go в определенном году: «Параллелизм — это не параллелизм»), созданнойrsc.io/quote/v3
обеспечивается модулем. Во-первых, мы обновляемhello.go
чтобы добавить новые функции:
package hello
import (
"rsc.io/quote"
quoteV3 "rsc.io/quote/v3"
)
func Hello() string {
return quote.Hello()
}
func Proverb() string {
return quoteV3.Concurrency()
}
Тогда мыhello_test.go
Добавьте тестовый метод в:
func TestProverb(t *testing.T) {
want := "Concurrency is not parallelism."
if got := Proverb(); got != want {
t.Errorf("Proverb() = %q, want %q", got, want)
}
}
Затем запускаем тест:
$ go test
go: finding rsc.io/quote/v3 v3.1.0
go: downloading rsc.io/quote/v3 v3.1.0
go: extracting rsc.io/quote/v3 v3.1.0
PASS
ok example.com/hello 0.024s
$
Вы можете видеть, что команда go загружена и установлена.rsc.io/quote/v3
модулей, теперь наши модули также зависят отrsc.io/quote
иrsc.io/quote/v3
:
$ go list -m rsc.io/q...
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.1.0
$
Каждая основная версия модуля Go (v1, v2 и т. д.) использует свой путь к модулю: начиная с v2 путь должен заканчиваться основной версией. В примереrsc.io/quote
Версия v3 пути к модулю больше неrsc.io/quote
, ноrsc.io/quote/v3
. Эта конвенция называетсяСемантический импорт, что дает несовместимым пакетам (пакетам с разными основными версиями) разные имена. Напротив,rsc.io/quote的v1.6.0
должно быть сv1.5.2
обратно совместим, поэтому он повторно использует именаrsc.io/quote
.
Команда go требует, чтобы путь к каждому модулю основной версии был неповторяемым, и каждая основная версия имела не более:rsc.io/quote
,Одинrsc.io/quote/v2
,Одинrsc.io/quote/v3
,Так далее и тому подобное. Это дает авторам модулей четкие правила о возможных дублирующихся путях модулей: программы не могут использовать оба пути.rsc.io/quote
v1.5.2 иrsc.io/quote
v1.6.0 для сборки. В то же время, разрешение разных основных версий модуля (поскольку у них разные пути) позволяет потребителям модулей постепенно обновляться до новых основных версий. В этом примере мы хотим использоватьrsc/quote/v3
в версии 3.1.0quote.Concurrency
, но не готов к миграцииrsc.io/quote
Использование версии 1.5.2. Возможность поэтапной миграции особенно важна для больших программ или кодовых баз.
Обновите зависимости до новой основной версии
Начнем с использованияrsc.io/quote
Две версии пакета для использования толькоrsc.io/quote/v3
преобразование. Из-за критических изменений в версиях следует ожидать, что некоторые API могли быть удалены, переименованы или иным образом изменены несовместимым образом. Читая документацию, мы видим, что Hello сталHelloV3
:
$ go doc rsc.io/quote/v3
package quote // import "rsc.io/quote"
Package quote collects pithy sayings.
func Concurrency() string
func GlassV3() string
func GoV3() string
func HelloV3() string
func OptV3() string
$
мы можем поставитьhello.go
средняя параqoute.Hello()
Вызов обновлен для использованияquoteV3.HelloV3()
, теперь нет необходимости переименовывать путь импорта версии v3, поэтому мы отменяем переименование пакета (обратите внимание, что имя пакета по умолчанию не содержит суффикс версии).
package hello
import "rsc.io/quote/v3"
func Hello() string {
return quote.HelloV3()
}
func Proverb() string {
return quote.Concurrency()
}
Повторите тесты, чтобы убедиться, что все работает:
$ go test
PASS
ok example.com/hello 0.014s
Удалить неиспользуемые зависимости
мы удалилиrsc.io/quote
, но он все еще отображается вgo list -m all
выход иgo.mod
В файле:
$ go list -m all
example.com/hello
golang.org/x/text v0.3.0
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1
$ cat go.mod
module example.com/hello
go 1.12
require (
golang.org/x/text v0.3.0 // indirect
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.0.0
rsc.io/sampler v1.3.1 // indirect
)
$
Зачем? Потому что сборка одного пакета (например, с помощью go build или go test) позволяет легко сказать, что чего-то не хватает и нужно добавить, но невозможно определить, безопасно ли что-то удалить. Зависимости можно удалить только после проверки всех пакетов в модуле и всех возможных комбинаций флагов сборки для этих пакетов. нормальныйbuild
Команда не загружает эту информацию, поэтому не может безопасно удалить зависимости.
go mod tidy
Команда очищает эти неиспользуемые зависимости:
$ go mod tidy
$ go list -m all
example.com/hello
golang.org/x/text v0.3.0
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1
$ cat go.mod
module example.com/hello
go 1.12
require (
golang.org/x/text v0.3.0 // indirect
rsc.io/quote/v3 v3.1.0
rsc.io/sampler v1.3.1 // indirect
)
$ go test
PASS
ok example.com/hello 0.020s
$
Суммировать
Модули Go — это будущее управления зависимостями в Go. Функционал модуля доступен начиная с Go 1.11. В этом посте описываются эти рабочие процессы с использованием модулей Go:
-
go mod init создает новый модуль, инициализируя описывающий его файл go.mod.
-
go build , go test и другие команды сборки пакетов по мере необходимости
go.mod
Добавьте новые зависимости. -
go list -m all выводит зависимости текущего модуля.
-
go get изменяет версию требуемой зависимости (или добавляет новую).
-
go mod tidy удаляет неиспользуемые зависимости.
Справочная статья:blog.gowaves.org/using-go-mo…
Сейчас все больше и больше проектов используют Go Modules для управления пакетами зависимостей. Я только начал пытаться перевести существующие проекты в режим, управляемый Go Modules. На практике я обнаружил, что еще многое предстоит узнать, чем я буду делиться позже Другие обучающие статьи и обзоры в этой области.