Minimal Version Selection (MVS) is a new dependency management algorithm in the upcoming Go 1.11 release, available out-of-box.
This talk covers how MVS helps to resolve the existing problems with dependency vendoring and how one should use new go tooling from the upcoming release.
В новом релизе Go 1.11 появится возможность работы с зависимостями "из коробки". В докладе рассказывается про используемый алгоритм разрешения зависимостей "Minimal Version Selection", решаемые с его помощью проблемы, и показано, как жить в чудесном новом мире Go 1.11
4. Зависимости в Go
• Как это было?
• Minimal Version Selection
• Текущий статус
• Примеры работы с зависимостями
• Подводные камни
04
5. Вместо предисловия
05
What is Software Engineering?
Software engineering is what happens to programming
when you add time and other programmers.
6. В начале было...
06
• pre-go1 - makefiles, gobuild (2009)
• pre-go1 - goinstall (2010) - VCS-репозитории
• go 1 - go get (2011)
• go 1.2 FAQ: Import Compatibility Rule (2013)
• создан gopkg.in (2014) - gopkg.in/yaml.v2
go get -u golang.org/x/tools/cmd/goimports
7. Vendoring и воспроизводимые сборки
(reproducible builds)
07
• goven (2012) - модификация импортов
• godep (2013) - модификация $GOPATH
• gb, glide, gom ... (2014)
• go 1.5 - vendoring в тулчейне
"original.com/pkg" -> "you.com/external/original.com/pkg"
GO15VENDOREXPERIMENT=1 go build
8. Vendoring - проблемы
08
• Дюжина менеджеров зависимостей (с разным форматом)
• Нет поддержки SemVer в go toolchain
• Коммитить папку vendor в репу -
cannot use opts
(type "<lib>/vendor/google.golang.org/
grpc".CallOption) as type []"<app>/vendor/
google.golang.org/grpc".CallOption
10. Встречаем... vgo
(февраль 2018)
010
• Semantic Import Versioning
import "github.com/go-yaml/yaml/v2"
• Go module - коллекция пакетов с общим путём
• Minimal Version Selection
• $GOPATH - больше не завязаны на src
16. Зависимости в Go
• Как это было?
• Minimal Version Selection
• Текущий статус
• Примеры работы с зависимостями
• Подводные камни
016
17. Minimal Version Selection
017
build list - список всех модулей зависимостей и их
версий
Задачи:
• Построение build list
• Обновление всех зависимостей
• Обновление модуля до нужной версии
• Откат модуля до нужной версии
27. Minimal Version Selection
027
Простота реализации - алгоритмы на графах
Минимальность вносимых изменений
Не NP-полная (не нужно решать 3SAT)
Локальные replace и exclude
Воспроизводимость билдов 👍
28. MVS - воспроизводимость билдов
028
Библиотека не должна диктовать сборку - replace и
exclude локальные.
Cargo и Dep - навязывают последние версии через
манифест.
Есть вероятность забыть обновить манифест - билд
нестабилен (B > 1.1, используем B 1.2)
29. Зависимости в Go
• Как это было?
• Minimal Version Selection
• Текущий статус
• Примеры работы с зависимостями
• Подводные камни
029
30. Статус
13 июля - vgo влили в go devel
20 июля - go1.11beta2
24 августа - go1.11
go help modules
030
31. Статус - обратная совместимость
GO111MODULE=auto
GO111MODULE=on go build <...>
Зачем?
Можно бы было определять "динамически" по наличию
go.mod в репозитории...
031
32. Статус - обратная совместимость
$GOPATH/src/A - без go.mod, импортирует B
$GOPATH/src/B - есть go.mod, импортирует C
$GOPATH/src/C - отсутствует
032
33. Статус - обратная совместимость
033
$ cd $GOPATH/src/A
$ go build
# B
../B/b.go:10: import "C": C not found
<Странно, попробуем собрать B напрямую>
$ go build B
../B/b.go:10: import "C": C not found
34. Статус - обратная совместимость
034
<Но я же только что работал с B!>
$ cd ../B
$ go build
$
<ЧТО? Собирается же>
$ go build B
$ go build С
$
35. Статус - обратная совместимость
035
<ОК, вернёмся к A >
$ cd ../A
$ go build
../B/b.go:10: import "C": C not found
36. Начало работы (fail 1)
$ cd `mktemp -d`
$ go get github.com/gorilla/mux@latest
go: cannot use path@version syntax in GOPATH mode
Почему?!
GO111MODULE=auto
036
37. Начало работы (fail 2)
$ export GO111MODULE=on
...
$ go get github.com/alecthomas/gometalinter
go: cannot find main module; see 'go help modules'
037
38. Начало работы
$ cd `mktemp -d`
$ go mod init example.com/test
$ go get github.com/gorilla/mux@latest
go: finding github.com/gorilla/mux v1.6.2
go: downloading github.com/gorilla/mux v1.6.2
$ cat go.mod
module example.com/test
require github.com/gorilla/mux v1.6.2 // indirect
038
43. go get
043
# или просто 'go get')
go get github.com/gorilla/mux@latest
# зафиксирует v1.6.2 в go.mod
go get github.com/gorilla/mux@v1.6.2
# тоже зафиксирует v1.6.2
go get github.com/gorilla/mux@e3702bed2
# запишет v1.6.3-0.20180517173623-c85619274f5d
go get github.com/gorilla/mux@c856192
# запишет v1.6.3-0.20180903154305-9e1f5955c0d2
go get github.com/gorilla/mux@master
44. Как релизить v2, v3...?
044
Указать в go.mod новую версию
module github.com/utrack/clay/v2
• master + версия в go.mod
• Бранч v2 (поддержка нескольких версий сразу)
• Директория /v2
45. go get (v2+)
045
$ go get github.com/utrack/clay/v2
go: finding github.com/utrack/clay/v2 v2.2.6
...
46. go get (v2+)
046
$ go get github.com/utrack/clay/v2
go: finding github.com/utrack/clay/v2 v2.2.6
...
$ go get github.com/utrack/clay@v2.2.6
go: finding github.com/utrack/clay v2.2.6
go: github.com/utrack/
clay@v0.0.0-20180828102536-0c2090de4d77: go.mod has post-
v0 module path "github.com/utrack/clay/v2" at revision
0c2090de4d77
go: error loading module requirements
47. go get (v2+)
047
$ go get github.com/utrack/clay/v2
go: finding github.com/utrack/clay/v2 v2.2.6
...
$ go get github.com/utrack/clay@v2.2.6
go: finding github.com/utrack/clay v2.2.6
go: github.com/utrack/
clay@v0.0.0-20180828102536-0c2090de4d77: go.mod has post-
v0 module path "github.com/utrack/clay/v2" at revision
0c2090de4d77
go: error loading module requirements
$ go get github.com/utrack/clay/v2@v2.2.6
48. А в старых проектах?
048
import "github.com/go-chi/chi/v3" - сломает клиентов
со старыми версиями go...
go1.9.7
go1.10.3
And don't forget to suffer :)
49. go get (старые проекты v2+)
049
$ go get github.com/go-chi/chi
go: finding github.com/go-chi/chi v3.3.3+incompatible
go: downloading github.com/go-chi/chi v3.3.3+incompatible
$ go get github.com/go-chi/chi@v3.3.0
go: finding github.com/go-chi/chi v3.3.0
go: downloading github.com/go-chi/chi v3.3.0+incompatible
50. go install, go build/run
050
$ go install github.com/utrack/clay/v2/cmd/protoc-gen-
goclay
Работает с go.mod - установит нужную версию
Не умеет в @<version>
$ go build -mod=vendor .
Соберёт бинарь, используя ./vendor
$ go build -mod=readonly .
Упадёт, если go.mod должен быть изменён в процессе
51. go mod
051
$ go mod init # создаст go.mod, подтянув зависимости
из ваших манифестов glide, dep и пр. (проблема с
replace - #24087)
$ go mod tidy -v # обновит go.mod
$ go mod vendor # заполнит vendor
$ go mod verify # сверит кеш модулей с go.sum
$ go mod graph # полный граф зависимостей
$ go mod graph | grep github.com/gogo/protobuf
gitlab.ozon.ru/map/fleet github.com/gogo/protobuf@v1.1.1
github.com/utrack/clay/v2@v2.2.1 github.com/gogo/protobuf@v1.0.0
gitlab.ozon.ru/map/types/v2@v2.5.0 github.com/gogo/protobuf@v1.1.1
52. go mod
052
$ go mod edit # редактирование go.mod (для роботов)
-module - поменять имя модуля
-require=path@version и -droprequire=path
-exclude=path@version и -dropexclude=path@version
-replace=old[@v]=new[@v] и -dropreplace=old[@v]
-json - печатает текущий go.mod в json
-fmt
-print
53. go mod
053
$ go mod why [-m] [-vendor] packages...
Выводит список пакетов (путь по графу зависимостей), до
использования пакета (или пакетов модуля)
$ go mod why -m github.com/mwf/vgo-modules/a
# github.com/mwf/vgo-modules/a
github.com/mwf/vgo-modules/c_user
github.com/mwf/vgo-modules/c
github.com/mwf/vgo-modules/a
54. go list
054
$ go list -m all # build list
github.com/mwf/vgo-modules
github.com/mwf/vgo-modules/a v0.0.1
github.com/mwf/vgo-modules/b v0.0.1
$ go list -m -versions github.com/gorilla/mux
github.com/gorilla/mux v1.2.0 v1.3.0 v1.4.0 v1.5.0
v1.6.0 v1.6.1 v1.6.2
55. go list - обновление зависимостей
055
$ go get github.com/go-chi/chi@v3.2.0
$ go list -m -u all
example.com/test
github.com/go-chi/chi v3.2.0+incompatible [v3.3.3+incompatible]
$ go get -u github.com/go-chi/chi
go: downloading github.com/go-chi/chi v3.3.3+incompatible
Есть go get -u=patch, работает только при наличии go.mod у
зависимости ¯_(ツ)_/¯
56. go test
056
$ go test ./... # как и раньше
$ go test all # запуск тестов всех зависимостей
Внимание, all включает тесты стандартной библиотеки!
#26317 cmd/go: exclude standard library from "all" pattern in modules
go test $(go list -f "{{if not .Standard}}{{.ImportPath}}{{end}}" $(go list -f
'{{ join .Deps "n"}}' $(go list -m)/...) $(go list -m)/...)
57. Вложенные модули
057
├── cmd/
│ ├── main.go # Точка входа в приложение
│ ├── go.mod # Зависимости бинаря
│
├── <пакеты библиотеки>
├── go.mod # Зависимости библиотеки
61. Зависимости в Go
• Как это было?
• Minimal Version Selection
• Текущий статус
• Примеры работы с зависимостями
• Подводные камни
061
62. go run vs go build
062
https://github.com/golang/go/issues/26483
$ cd `mktemp -d`
$ curl -sS https://swtch.com/hello.go >hello.go
$ go mod -init -module=example.com/test
$ go run hello.go
$ cat go.mod
module example.com/test
require rsc.io/quote v1.5.2 // indirect
63. go run vs go build
063
https://github.com/golang/go/issues/26483
64. Откат обновления зависимостей
064
#26481 - cmd/go: downgrading a module with `go get` retains
indirect dependencies
С 0.1 -> A 0.1
C 0.2 -> A 0.2 (bug)
$ go list -m all
github.com/mwf/vgo-modules/c_user
github.com/mwf/vgo-modules/a v0.1.0
github.com/mwf/vgo-modules/c v0.1.0
65. Откат обновления зависимостей
065
main -> C 0.1 - хотим обновить до 0.2
go get github.com/mwf/vgo-modules/c@v0.2.0
$ go list -m all
github.com/mwf/vgo-modules/c_user
github.com/mwf/vgo-modules/a v0.2.0
github.com/mwf/vgo-modules/c v0.2.0
66. Откат обновления зависимостей
066
go test -> fail -> откат
go get github.com/mwf/vgo-modules/c@v0.1.0
module github.com/mwf/vgo-modules/c_user
require (
github.com/mwf/vgo-modules/a v0.2.0 // indirect
github.com/mwf/vgo-modules/c v0.1.0
)
68. Откат обновления зависимостей
068
go get github.com/mwf/vgo-modules/a@v0.1.0
module github.com/mwf/vgo-modules/c_user
require (
github.com/mwf/vgo-modules/c v0.1.0
)
¯_(ツ)_/¯
69. Важные issue
069
• #24250 cmd/go: allow installing programs (at specific
versions) to GOBIN
• #25922 cmd/go: clarify best practice for tool
dependencies
• #25873 cmd/go: allow forcing tags on/off during go mod
vendor, tidy
• #26404 cmd/go: export module information for binaries
programmatically