Modules

Лекция 6

Максим Иванов

Modules

# go mod init github.com/verytable/hello
go: creating new go.mod: module github.com/verytable/hello
# cat go.mod
module github.com/verytable/hello

go 1.22.0
2

Modules

Например, в модуле github.com/google/go-cmp есть директория cmp/.

import path пакета cmp будет github.com/google/go-cmp/cmp.

3

Modules

# cat hello.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}

Install binary.

# go env -w GOBIN=/tmp/bin
# go install .
# /tmp/bin/hello
Hello, world!
# go env -u GOBIN
4

Modules

# mkdir -p morestrings
# cat morestrings/reverse.go
package morestrings

func ReverseRunes(s string) string {
    r := []rune(s)
    for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
        r[i], r[j] = r[j], r[i]
    }
    return string(r)
}
5

Modules

# go build ./morestrings  // в репозитории ничего не изменится

Команда go кэширует выходные данные сборки для повторного использования в будущих сборках.

go help cache для деталей.

6

Modules

Используем subpackage

# cat hello.go
package main

import (
    "fmt"

    "github.com/verytable/hello/morestrings"
)

func main() {
    fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}

# go install github.com/verytable/hello
# hello
Hello, Go!
7

Modules

Добавляем внешнюю зависимость

# cat hello.go
package main

import (
    "fmt"

    "github.com/google/go-cmp/cmp"
    "github.com/verytable/hello/morestrings"
)

func main() {
    fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
    fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}
8

Modules

# go mod tidy
go: finding module for package github.com/google/go-cmp/cmp
go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.6.0
# go install
# hello
Hello, Go!
  string(
-     "Hello World",
+     "Hello Go",
  )

Внешние зависимости хранятся in go.mod.

# cat go.mod
module github.com/verytable/hello

go 1.22.0

require github.com/google/go-cmp v0.6.0
9

Modules

go mod help tidy для подробностей.

10

Modules

Исходный код модулей хранится в $GOPATH/pkg/mod.

# tree -L 2 $GOPATH/pkg/mod/github.com/google
...
├── go-cmp@v0.5.9
│   ├── cmp
│   ├── CONTRIBUTING.md
│   ├── go.mod
│   ├── LICENSE
│   └── README.md
├── go-cmp@v0.6.0
│   ├── cmp
│   ├── CONTRIBUTING.md
│   ├── go.mod
│   ├── LICENSE
│   └── README.md
...
11

Modules

go clean -modcache удаляет все модули из $GOPATH/pkg/mod.

go clean -cache удаляет объекты из GOCACHE.

12

Modules

Установить другую версию пакета.

# go get github.com/google/go-cmp/cmp@v0.5.5
go: downloading github.com/google/go-cmp v0.5.5
go: downgraded github.com/google/go-cmp v0.6.0 => v0.5.5

Обновить модули.

# go mod tidy
go: downloading golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543

# cat go.mod
module github.com/verytable/hello

go 1.22.0

require github.com/google/go-cmp v0.5.5
13

Modules

# go list -m -f {{.Path}}{{.Version}} all
github.com/verytable/hello
github.com/google/go-cmpv0.5.5
golang.org/x/xerrorsv0.0.0-20191204190536-9bdfabe68543

Format options.

type Module struct {
    Path      string       // module path
    Version   string       // module version
    Versions  []string     // available module versions (with -versions)
    Replace   *Module      // replaced by this module
    Time      *time.Time   // time version was created
    Update    *Module      // available update, if any (with -u)
    Main      bool         // is this the main module?
    Indirect  bool         // is this module only an indirect dependency of main module?
    Dir       string       // directory holding files for this module, if any
    GoMod     string       // path to go.mod file used when loading this module, if any
    GoVersion string       // go version used in module
    Retracted string       // retraction information, if any (with -retracted or -u)
    Error     *ModuleError // error loading module
}
14

Modules

# cat go.sum
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
15

Modules

# go mod graph
github.com/verytable/hello github.com/google/go-cmp@v0.5.5
github.com/verytable/hello go@1.22.0
github.com/google/go-cmp@v0.5.5 golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543
go@1.22.0 toolchain@go1.22.0
16

Modules

# go mod why golang.org/x/xerrors
# golang.org/x/xerrors
github.com/verytable/hello
github.com/google/go-cmp/cmp
github.com/google/go-cmp/cmp.test
github.com/google/go-cmp/cmp/cmpopts
golang.org/x/xerrors
17

Modules

Vendor dependencies.

# go mod vendor
# tree -L 3 ./vendor
./vendor
├── github.com
│   └── google
│       └── go-cmp
└── modules.txt
18

Modules

# cat vendor/modules.txt 
# github.com/google/go-cmp v0.5.5
## explicit
github.com/google/go-cmp/cmp
github.com/google/go-cmp/cmp/internal/diff
github.com/google/go-cmp/cmp/internal/flags
github.com/google/go-cmp/cmp/internal/function
github.com/google/go-cmp/cmp/internal/value
19

Modules

Indirect зависимости

# go mod init github.com/verytable/world
go: creating new go.mod: module github.com/verytable/world
# cat sum.go
package world

import _ "github.com/jackc/pgx/v5"

func Sum(a, b int) int {
  return a + b
}
20

Modules

Indirect зависимости

# go mod tidy
...

# cat go.mod
module github.com/verytable/world

go 1.22.0

require github.com/jackc/pgx/v5 v5.5.5

require (
  github.com/jackc/pgpassfile v1.0.0 // indirect
  github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
  golang.org/x/crypto v0.17.0 // indirect
  golang.org/x/text v0.14.0 // indirect
)
21

Modules

Indirect зависимости — это модули, которые:

В примере выше:
- github.com/jackc/pgx/v5прямая зависимость (импортируется в коде)
- github.com/jackc/pgpassfile, golang.org/x/crypto и др. — indirect зависимости

22

Modules

Когда появляются indirect зависимости?

1. Транзитивные зависимости — ваша прямая зависимость использует другие модули:

your-module → pgx/v5 → pgpassfile (indirect)
                   └─→ crypto (indirect)

2. Неполные go.mod — если у зависимости отсутствуют или неточно указаны её зависимости

3. Минимальная версия — Go добавляет indirect зависимости для обеспечения совместимости

23

Modules

При версию

# Ваш модуль использует go 1.21
# Зависимость A требует go 1.19 и использует модуль B v1.2.0
# Но для go 1.21 нужна минимум версия B v1.3.0

Go автоматически добавит B v1.3.0 как indirect зависимость для совместимости.

24

Modules

Как импортировать пакет из локального модуля

# cat hello.go 
package main

import (
  "fmt"

  "github.com/google/go-cmp/cmp"
  "github.com/verytable/hello/morestrings"
  "github.com/verytable/world"
)

func main() {
  fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
  fmt.Println(cmp.Diff("Hello World", "Hello Go"))

  fmt.Println(world.Sum(1, 2))
}
25

Modules

Как импортировать пакет из локального модуля

# go install .
main.go:8:2: no required module provides package github.com/verytable/world; to add it:
  go get github.com/verytable/world
# go get github.com/verytable/world
go: module github.com/verytable/world: git ls-remote -q origin in /home/verytable/go/pkg/mod/cache/vcs/8d15fd58d5b540d58dc97582a5a11fe29782f4416e9628e0183c4ea4f8c7cdcd: exit status 128:
  fatal: could not read Username for 'https://github.com': terminal prompts disabled
Confirm the import path was entered correctly.
26

Modules

# go mod edit -replace github.com/verytable/world=/tmp/world
# cat go.mod
module github.com/verytable/hello

go 1.22.0

require github.com/google/go-cmp v0.5.5

replace github.com/verytable/world => /tmp/world
27

Modules

# go get ./...
go: added github.com/jackc/pgpassfile v1.0.0
go: added github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a
go: added github.com/jackc/pgx/v5 v5.5.5
go: added github.com/verytable/world v0.0.0-00010101000000-000000000000
go: added golang.org/x/crypto v0.17.0
go: added golang.org/x/text v0.14.0
# go run .
Hello, Go!
  string(
-     "Hello World",
+     "Hello Go",
  )

3
28

Modules

Выложить свой пакет в открытый доступ.

# git init
# git add .
# git commit
# git push
# go get github.com/verytable/hello@v0.0.0-20240303255101-161cd47e91fd
# git tag v0.0.1
# git push v0.0.1
# go get github.com/verytable/hello@v0.0.1
29

Modules

Semantic versioning

30

Modules

v2 and beyond

├── go.mod
├── package.go
└── v2
    ├── go.mod
    └── package.go
main == v0/v1
├── go.mod
└── package.go

v2 == v2
├── go.mod
└── package.go
31

Modules

Module proxy

# curl https://proxy.golang.org/github.com/google/go-cmp/@v/list
v0.5.8
v0.5.5
v0.6.0
# curl https://proxy.golang.org/github.com/google/go-cmp/@v/v0.5.5.info
{"Version":"v0.5.5","Time":"2021-03-03T20:48:37Z"}
# curl https://proxy.golang.org/github.com/google/go-cmp/@latest
{"Version":"v0.6.0",
 "Time":"2023-08-31T17:32:40Z",
 "Origin":{"VCS":"git","URL":"https://github.com/google/go-cmp","Ref":"refs/tags/v0.6.0", ...}}
# curl https://proxy.golang.org/github.com/google/go-cmp/@v/v0.6.0.mod
module github.com/google/go-cmp

go 1.13
# curl -O https://proxy.golang.org/github.com/google/go-cmp/@v/v0.6.0.zip
32

Modules

Module proxy

# go get -x github.com/google/go-cmp/cmp
get https://proxy.golang.org/github.com/@v/list
get https://proxy.golang.org/github.com/google/go-cmp/@v/list
get https://proxy.golang.org/github.com/google/go-cmp/cmp/@v/list
get https://proxy.golang.org/github.com/google/@v/list
get https://proxy.golang.org/github.com/google/go-cmp/cmp/@v/list: 404 Not Found (0.622s)
get https://proxy.golang.org/github.com/google/@v/list: 404 Not Found (0.622s)
get https://proxy.golang.org/github.com/@v/list: 404 Not Found (0.622s)
get https://proxy.golang.org/github.com/google/go-cmp/@v/list: 200 OK (0.638s)
go: added github.com/google/go-cmp v0.6.0
33

Modules

Vanity import

Исходный код лежит на https://github.com/uber-go/atomic, однако импорт другой

import "go.uber.org/atomic"

Команда go get внутри делает http запрос к go.uber.org

# curl https://go.uber.org/atomic\?go-get\=1
<!DOCTYPE html>
<html>
    <head>
        <meta name="go-import" content="go.uber.org/atomic git https://github.com/uber-go/atomic">
        <meta name="go-source" content="go.uber.org/atomic https://github.com/uber-go/atomic https://github.com/uber-go/atomic/tree/master{/dir} https://github.com/uber-go/atomic/tree/master{/dir}/{file}#L{line}">
        <meta http-equiv="refresh" content="0; url=https://pkg.go.dev/go.uber.org/atomic">
    </head>
    <body>
        Nothing to see here. Please <a href="https://pkg.go.dev/go.uber.org/atomic">move along</a>.
    </body>
</html>
34

Ссылки:

35

Thank you

Максим Иванов

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)