Go和依赖管理

请将以下内容以中文为母语的方式改写,只需要一种选择:

お題

据悉,对于Go语言来说,版本管理和依赖包管理(有时也称之为版本控制)一直是一个长期的问题。类似于“Go没有泛型!”这样的热门讨论,关于这个问题的争论屡见不鲜。

在这些讨论中,目前可供尝试的最新工具是称为“Go module”的东西。

根据我的经验,在Go语言的1.7和1.9版本中,我使用过一些vendoring工具,比如glide和dep。
个人而言,我对这些工具没有太大的不满(当然也遇到了一些问题,实际情况下可能也会遇到类似的挑战,无论使用哪个工具都一样),但如果官方能提供(dep本身也是为了让Go语言拥有vendoring(版本控制)功能而开发的实验性工具)一个工具,我仍然更倾向于使用官方提供的工具。

所以,让我们尝试使用Go模块,顺便回顾一下我之前使用的工具方法。

开发环境。

操作系统

You only need one option, right?

你只需要一个选项,对吗?

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="17.10 (Artful Aardvark)"

# Go语言

$ go version
go version go1.11.2 linux/amd64

版本的切换是通过goenv来实现的。

实践

■使用GOPATH解决依赖包

试行源代码如下:
https://github.com/sky0621/go-modules/tree/4f5e5a5187c79413550655c9620d539923c65615

在环境变量中设置GOPATH。

$ env | grep GOPATH
GOPATH=/work/src/golang

将源代码放置在GOPATH下

$ pwd
/work/src/golang/src/github.com/sky0621/go-modules
$ tree
.
├── cmd
│   └── main.go
└── rootpackage.go

主要.go

执行同一项目中不同包的函数”github.com/sky0621/go-modules”。
同时,执行另一个项目(github.com/satori/go.uuid)的函数。
请确保将上述内容放置在GOPATH下通过命令$ go get github.com/satori/go.uuid进行安装。

package main

import (
    "fmt"

    "github.com/sky0621/go-modules"

    uuid "github.com/satori/go.uuid"
)

func main() {
    fmt.Println("Hello, World!")
    modules.SayBye()
    u1 := uuid.Must(uuid.NewV4())
    fmt.Printf("UUIDv4: %s\n", u1)
}

执行结果。

$ pwd
/work/src/golang/src/github.com/sky0621/go-modules/cmd
$ go run main.go 
Hello, World!
Bye!
UUIDv4: 2a601fdb-fe9d-49e7-81b8-15b554d2e42e

备考

我从来没有使用GOPATH指定的方式来构建和部署产品。
例如,如果使用Kubernetes(或者即使不用Kubernetes,只使用Docker容器),可能需要在Dockerfile中设置GOPATH,并且还要添加一系列外部依赖包的”go get”语句。然后,将其编译成可执行文件。

在 Glide(一个用于管理依赖包的工具)中解决依赖包的问题。

举例来说,如果在GOPATH目录下没有应用程序使用的包,则在运行go run时将会出现错误。

$ env | grep GOPATH
GOPATH=/work/src/golang
$ ll /work/src/golang/src/github.com/satori
ls: '/work/src/golang/src/github.com/satori' にアクセスできません: そのようなファイルやディレクトリはありません
$ pwd
/tmp/go-modules/cmd
$
$ go run main.go 
main.go:8:2: cannot find package "github.com/satori/go.uuid" in any of:
    /home/koge/.goenv/versions/1.11.2/src/github.com/satori/go.uuid (from $GOROOT)
    /work/src/golang/src/github.com/satori/go.uuid (from $GOPATH)
main.go:6:2: cannot find package "github.com/sky0621/go-modules" in any of:
    /home/koge/.goenv/versions/1.11.2/src/github.com/sky0621/go-modules (from $GOROOT)
    /work/src/golang/src/github.com/sky0621/go-modules (from $GOPATH)

安装和应用glide

安装

$ curl https://glide.sh/get | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4833  100  4833    0     0   1611      0  0:00:03  0:00:03 --:--:--  1294
  〜〜〜 省略 〜〜〜
Downloading https://github.com/Masterminds/glide/releases/download/v0.13.2/glide-v0.13.2-linux-amd64.tar.gz
glide version v0.13.2 installed successfully

适用 – shì

$ pwd
/tmp/go-modules
$
$ glide init
[INFO]  Generating a YAML configuration file and guessing the dependencies
  〜〜〜 省略 〜〜〜
[INFO]  Writing updates to configuration file (glide.yaml)
[INFO]  You can now edit the glide.yaml file.:
[INFO]  --> For more information on versions and ranges see https://glide.sh/docs/versions/
[INFO]  --> For details on additional metadata see https://glide.sh/docs/glide.yaml/

确认生成文件

$ tree
.
├── cmd
│   └── main.go
├── glide.yaml
└── rootpackage.go

glide.yaml的内容

$ cat glide.yaml 
package: .
import:
- package: github.com/satori/go.uuid
  version: ~1.2.0
- package: github.com/sky0621/go-modules

依赖包的打包

$ glide up
[INFO]  Downloading dependencies. Please wait...
[INFO]  --> Fetching github.com/sky0621/go-modules
[INFO]  --> Fetching github.com/satori/go.uuid
[INFO]  --> Detected semantic version. Setting version for github.com/satori/go.uuid to v1.2.0
[INFO]  Resolving imports
[INFO]  Downloading dependencies. Please wait...
[INFO]  Setting references for remaining imports
[INFO]  Exporting resolved dependencies...
[INFO]  --> Exporting github.com/sky0621/go-modules
[INFO]  --> Exporting github.com/satori/go.uuid
[INFO]  Replacing existing vendor dependencies
[INFO]  Project relies on 2 dependencies.

glide.lock已生成并在vendor目录下获取了依赖包的源代码。

$ tree
.
├── cmd
│   └── main.go
├── glide.lock
├── glide.yaml
├── rootpackage.go
└── vendor
    └── github.com
        ├── satori
        │   └── go.uuid
        │       ├── LICENSE
        │       ├── README.md
        │       ├── codec.go
        │       ├── codec_test.go
        │       ├── generator.go
        │       ├── generator_test.go
        │       ├── sql.go
        │       ├── sql_test.go
        │       ├── uuid.go
        │       └── uuid_test.go
        └── sky0621
            └── go-modules
                ├── README.md
                ├── cmd
                │   └── main.go
                └── rootpackage.go

滑行锁定

$ cat glide.lock 
hash: 450d4cce664d8e157d796b280456c6e33dbcf1a6529a42bd413a990516ba6bef
updated: 2018-11-19T01:58:50.856499847+09:00
imports:
- name: github.com/satori/go.uuid
  version: f58768cc1a7a7e77a3bd49e98cdd21419399b6a3
- name: github.com/sky0621/go-modules
  version: 4f5e5a5187c79413550655c9620d539923c65615
testImports: []

如果对这个文件进行源代码管理,即使在某个时刻由于依赖关系的问题导致构建失败,也可以恢复到正常的状态。
* 如果只有glide.yaml文件,因为根据设定,次要版本或补丁版本可能会在执行glide up命令时升级到指定版本,所以修复依赖关系可能会变得困难。

好的,现在进行操作确认。

在GOPATH之外尝试

$ pwd
/tmp/go-modules/cmd
$
$ go run main.go 
main.go:8:2: cannot find package "github.com/satori/go.uuid" in any of:
    /home/koge/.goenv/versions/1.11.2/src/github.com/satori/go.uuid (from $GOROOT)
    /work/src/golang/src/github.com/satori/go.uuid (from $GOPATH)
main.go:6:2: no Go files in /work/src/golang/src/github.com/sky0621/go-modules

哎呀???
嗯,看起来,在glide中,如果源代码不在GOPATH目录下,最终无法使用vendoring。
参考:https://qiita.com/mom0tomo/items/b66203b2718dd2626fd3#glideで何が問題になるのか-confused

在GOPATH目录下尝试一下

$ pwd
/work/src/golang/src/github.com/sky0621/go-modules/cmd
$
$ go run main.go 
Hello, World!
Bye!
UUIDv4: 46225e42-8129-47de-b284-146d16d7a948

可以行。
暫時,我確認了在GOPATH下的main.go所引入的「github.com/satori/go.uuid」不存在,但好像最終還是依賴於GOPATH。

试验源代码如下:
https://github.com/sky0621/go-modules/tree/94e18719957dc74129667a0fb95b286e9169f08a

■使用Vendoring(依赖)解决依赖包问题。

安装和应用dep。

请安装

$ curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  〜〜〜 省略 〜〜〜
Setting executable permissions.
Moving executable to /work/src/golang/bin/dep

在GOPATH之外生效

$ pwd
/tmp/go-modules
$
$ dep init
init failed: unable to detect the containing GOPATH: /tmp/go-modules is not within a known GOPATH/src

哎呀,看来只有在GOPATH内才行啊,dep才有效。

在GOPATH中应用

$ pwd
/work/src/golang/src/github.com/sky0621/go-modules
$
$ dep init
  Using ^1.2.0 as constraint for direct dep github.com/satori/go.uuid
  Locking in v1.2.0 (f58768c) for direct dep github.com/satori/go.uuid

Gopkg.toml和Gopkg.lock已生成,获取了依赖包源码并放置在vendor目录下。

$ tree
.
├── Gopkg.lock
├── Gopkg.toml
├── cmd
│   └── main.go
├── rootpackage.go
└── vendor
    └── github.com
        └── satori
            └── go.uuid
                ├── LICENSE
                ├── README.md
                ├── codec.go
                ├── generator.go
                ├── sql.go
                └── uuid.go

现在,让我们来确认一下操作吧。

$ pwd
/work/src/golang/src/github.com/sky0621/go-modules/cmd
$
$ go run main.go 
Hello, World!
Bye!
UUIDv4: b5e4a50f-b1bc-4044-8bc5-cea56d770992

试行源代码如下:
https://github.com/sky0621/go-modules/tree/0e9b65282b80d3064528baf13c464e35e95bb573

概述

因为时间已经用完了,所以试用Go模块将会在下次。
顺便提一下,虽然不是真正写代码试用,但是这里记录了关于Go和版本控制的历史信息。(英文)
有翻译这段内容的Qiita文章,真厉害。

广告
将在 10 秒后关闭
bannerAds