Golang modules 初探

Stella981 等级 364 0 0

今天天色刚刚亮起,起床看到golang 1.11正式发版了,有着两个重要的特性:modules和WebAssembly。

本博文只要说的是modules,从Java转golang的同学肯定是对golang的包管理充满了无奈之情,我也曾在博客中介绍过glide,也介绍过dep,现在我们再一次升级介绍modules。

什么是modules

现在都在说modules,那么它是什么?
到文档看看 Modules, module versions, and more

A module is a collection of related Go packages. Modules are the unit of source code interchange and versioning. The go command has direct support for working with modules, including recording and resolving dependencies on other modules. Modules replace the old GOPATH-based approach to specifying which source files are used in a given build.

翻译一下:

模块是相关Go包的集合。modules是源代码交换和版本控制的单元。 go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。

可以得到两个重要信息:

  • Go命令行支持modules操作
  • modules用来替换GOPATH的

大家不需要太担心了,golang 1.11版本仅仅是指对modules的初步支持,之前老的GOPATH还是可以继续使用的,有人说是在golang 1.12去除,但是我觉得有点早了,毕竟人的惯性不是这么容易改变的。

如何使用modules

modules是一个新的特性,那么就需要新的Golang版本进行支持了,可以到官网下载,一定要是go 1.11及以上的版本(写博文的时候go 1.11刚刚出来)。 怎么部署就不在这里说了,相信初学者也是知道怎么做的。

还有人记得vendor刚刚出来时候golang提供的环境变量GO15VENDOREXPERIMENT吗?现在modules出来,按照惯例也提供了一个环境变量GO111MODULE,这个变量的三个1太有魔性了。

GO111MODULE

GO111MODULE可以设置为三个字符串值之一:off,on或auto(默认值)。

  • off,则go命令从不使用新模块支持。它查找vendor 目录和GOPATH以查找依赖关系;也就是继续使用“GOPATH模式”。
  • on,则go命令需要使用模块,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod下载依赖。
  • auto或未设置,则go命令根据当前目录启用或禁用模块支持。仅当当前目录位于GOPATH/src之外并且其本身包含go.mod文件或位于包含go.mod文件的目录下时,才启用模块支持。

Defining a module

开始的时候谁也不知道怎么使用?不过go已经给我提供了工具了,可以在控制台输入:

go help modules

看到一大串的文档输出,看着都头疼了,一会儿我们再简要说明重点,现在先进行操作。

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)
$ export GO111MODULE=on  #开启modules

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)
$ go mod init  gitlab.luojilab.com/zeroteam/ddkafka # 创建go.mod
go: creating new go.mod: module gitlab.luojilab.com/zeroteam/ddkafka

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)
$ ls    # 真的创建了,google大法好呀
README.md  go.mod  models.go  mq_interface.go  sarama  segmentio
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)
$ cat go.mod    # 看看里面什么东西
module gitlab.luojilab.com/zeroteam/ddkafka
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)
$ cd segmentio/
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)
$ go test   # 执行一下看看
go: finding github.com/segmentio/kafka-go latest
go: finding github.com/golang/glog latest
go: downloading github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
go: downloading github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)
$ go list -m
gitlab.luojilab.com/zeroteam/ddkafka

细心的同学一定可以发现,执行go mod init [module]使用go.mod只有一行信息module gitlab.luojilab.com/zeroteam/ddkafka,在执行 go build、 go test、 go list命令时会根据需要的依赖自动生成 require语句。

现在来说说如何定义一个modules,modules是由Go源文件目录结构定义的,如果目录下含有go.mod文件,该目录称为模块根目录(module root)。模块根目录及其子目录所有的Go包都是属于该modules的,但是如果子目录包含有了自己的go.mod文件就隶属于该modules。 举一个例子:

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module)
$ tree
.
|-- README.md
|-- go.mod
|-- go.sum
|-- models.go
|-- mq_interface.go
|-- sarama
|   |-- sarama_consumer.go
|   |-- sarama_consumer_test.go
|   |-- sarama_producer.go
|   `-- sarama_producter_test.go
`-- segmentio
    |-- segmention_Consumer.go
    |-- segmention_consumer_test.go
    |-- segmention_producer.go
    `-- segmention_producter_test.go

gitlab.luojilab.com/zeroteam/ddkafka目录下含有了go.mod文件,所以其子目录saramasegmentio都属于gitlab.luojilab.com/zeroteam/ddkafka模块,但是如果在segmentio目录中加入了go.mod,那么segmentio就不再隶属于gitlab.luojilab.com/zeroteam/ddkafka模块。

那么依赖被下载到哪里了呢,你可以打开的目录$GPATH/pkg/mod就可以看到了。

主模块和构建列表

The main module and the build list 暂且翻译为主模块和构建列表。 “主模块”是包含运行go命令的目录的模块。 go命令通过查找当前目录中的go.mod或者当前目录的父目录,或者祖父目录,依次递归查找。

go.mod文件可以通过require,replace和exclude语句使用的精确软件包集。

  • require语句指定的依赖项模块
  • replace语句可以替换依赖项模块
  • exclude语句可以忽略依赖项模块

go list,可以查看当前的依赖和版本.

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)
$ ls  # 这是模块的子目录
segmention_Consumer.go  segmention_consumer_test.go  segmention_producer.go  segmention_producter_test.go

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)
$ go list -m #主模块的打印路径
gitlab.luojilab.com/zeroteam/ddkafka
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)
$ go list -m -f={{.Dir}} #print主模块的根目录
D:\code\gopath\src\gitlab.luojilab.com\zeroteam\ddkafka
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module)
$ go list -m all # 查看当前的依赖和版本信息
gitlab.luojilab.com/zeroteam/ddkafka
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910

go mod 命令

go mod命令之前可以使用过了go mod init,下面我们把常用的go mod命令罗列一下:

  • go mod init:初始化modules

  • go mod download:下载modules到本地cache

  • go mod edit:编辑go.mod文件,选项有-json、-require和-exclude,可以使用帮助go help mod edit

  • go mod graph:以文本模式打印模块需求图

  • go mod tidy:删除错误或者不使用的modules

  • go mod vendor:生成vendor目录

  • go mod verify:验证依赖是否正确

  • go mod why:查找依赖

    qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ go mod edit -json { "Module": { "Path": "gitlab.luojilab.com/zeroteam/ddkafka" }, "Require": [ { "Path": "github.com/golang/glog", "Version": "v0.0.0-20160126235308-23def4e6c14b" }, { "Path": "github.com/segmentio/kafka-go", "Version": "v0.0.0-20180716203113-48c37f796910" } ], "Exclude": null, "Replace": null } qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ cat go.mod module gitlab.luojilab.com/zeroteam/ddkafka

    require ( github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910 )

    qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ go mod edit -require=github.com/Shopify/sarama@master

    qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ cat go.mod module gitlab.luojilab.com/zeroteam/ddkafka

    require ( github.com/Shopify/sarama master github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910 ) qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ go mod vendor # 启动verdon go: downloading github.com/Shopify/sarama v1.17.1-0.20180820172058-647feef69a1a go: finding github.com/davecgh/go-spew/spew latest go: finding github.com/eapache/queue v1.1.0 go: finding github.com/eapache/go-xerial-snappy latest go: finding github.com/eapache/go-resiliency/breaker latest go: finding github.com/rcrowley/go-metrics latest go: downloading github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 go: finding github.com/bsm/sarama-cluster v2.1.15+incompatible go: downloading github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 go: downloading github.com/bsm/sarama-cluster v2.1.15+incompatible go: downloading github.com/eapache/queue v1.1.0 go: finding github.com/eapache/go-resiliency v1.1.0 go: downloading github.com/eapache/go-resiliency v1.1.0 go: finding github.com/davecgh/go-spew v1.1.1 go: downloading github.com/davecgh/go-spew v1.1.1 go: finding github.com/pierrec/lz4 v2.0.3+incompatible go: downloading github.com/pierrec/lz4 v2.0.3+incompatible go: finding github.com/golang/snappy latest go: downloading github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db

    qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ ls README.md go.mod go.sum models.go mq_interface.go sarama segmentio vendor qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ go mod verify all modules verified qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ go mod why go: finding github.com/onsi/ginkgo/extensions/table latest go: finding github.com/onsi/ginkgo v1.6.0 go: finding github.com/Shopify/toxiproxy/client latest go: finding github.com/onsi/gomega v1.4.1 go: downloading github.com/onsi/gomega v1.4.1 go: downloading github.com/onsi/ginkgo v1.6.0 go: finding github.com/onsi/ginkgo/extensions latest go: finding github.com/Shopify/toxiproxy v2.1.3+incompatible go: downloading github.com/Shopify/toxiproxy v2.1.3+incompatible go: finding github.com/hpcloud/tail v1.0.0 go: finding github.com/golang/protobuf/proto latest go: finding gopkg.in/yaml.v2 v2.2.1 go: downloading github.com/hpcloud/tail v1.0.0 go: downloading gopkg.in/yaml.v2 v2.2.1 go: finding github.com/golang/protobuf v1.2.0 go: downloading github.com/golang/protobuf v1.2.0 go: finding gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 go: downloading gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 go: finding gopkg.in/tomb.v1 latest go: finding gopkg.in/fsnotify.v1 v1.4.7 go: downloading gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 go: downloading gopkg.in/fsnotify.v1 v1.4.7 go: finding github.com/fsnotify/fsnotify v1.4.7 go: downloading github.com/fsnotify/fsnotify v1.4.7

    gitlab.luojilab.com/zeroteam/ddkafka

    gitlab.luojilab.com/zeroteam/ddkafka

go的 mod与get

go get这个命令大家应该不会陌生,这是下载go依赖包的根据,下载Go 1.11出来了,go get命令也与时俱进,支持了modules。 go get 来更新 module:

  • 运行 go get -u 将会升级到最新的次要版本或者修订版本
  • 运行 go get -u=patch 将会升级到最新的修订版本(比如说,将会升级到 1.0.1 版本,但不会升级到 1.1.0 版本)
  • 运行 go get package@version将会升级到指定的版本号

运行go get如果有版本的更改,那么go.mod文件也会更改。

如何处理被墙

我原本以为go 1.11版本modules不支持代理功能,但是经过验证,是支持的。使用的命令就是之前提到过的replace命令。 文档中有一段话:

The -replace=old[@v]=new[@v] and -dropreplace=old[@v] flags
add and drop a replacement of the given module path and version pair.
If the @v in old@v is omitted, the replacement applies to all versions
with the old module path. If the @v in new@v is omitted, the new path
should be a local module root directory, not a module path.
Note that -replace overrides any existing replacements for old[@v].

大概翻译一下:

-replace=old[@v]=new[@v]和-dropreplace=old[@v]标志添加和删除给定模块路径和版本对的替换。
如果省略了old@v中的@v,则替换适用于所有使用旧模块路径的版本。
如果new@v中的@v被省略,新路径应该是本地模块根目录,而不是模块路径。

注意-replace会覆盖任何现有的旧替换[@v]。

下面进行演示: 新建一个main文件代码如下:

package main

import (
    "errors"
    "fmt"
    "golang.org/x/net/netutil"
    "net"
    "time"
)

var errFake = errors.New("fake error from errorListener")

type errorListener struct {
    net.Listener
}

func main() {
    donec := make(chan bool, 1)
    go func() {
        const n = 2
        ll := netutil.LimitListener(errorListener{}, n)
        for i := 0; i < n+1; i++ {
            _, err := ll.Accept()
            if err != errFake {
                fmt.Errorf("Accept error = %v; want errFake", err)
            }
        }
        donec <- true
    }()
    select {
    case <-donec:
    case <-time.After(5 * time.Second):
        fmt.Errorf("timeout. deadlock?")
    }
}

可以看到我们引入了golang.org/x/net/netuti,很不幸,这是不能访问到的类库。

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module)
$ go build  # 试试是否可以下载
build gitlab.luojilab.com/zeroteam/ddkafka/cmd: cannot find module for path golang.org/x/net/netutil

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module)
$ go mod edit -require=golang.org/x/net@v1.2.3 # modules中加上依赖,版本是乱给的

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module)
$ go build  # 还是不行
go: golang.org/x/net@v1.2.3: unrecognized import path "golang.org/x/net" (https fetch: Get https://golang.org/x/net?go-get=1: dial tcp 216.239.37.1:443: connectex: A connection attemp
t failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.)
go: error loading module requirements

以失败而告终!不过我们还有replace方法,首先去下载

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/github.com/golang
$ git clone https://github.com/golang/net.git
Cloning into 'net'...
remote: Counting objects: 7876, done.
remote: Compressing objects: 100% (55/55), done.
remote: Total 7876 (delta 37), reused 42 (delta 19), pack-reused 7802R
Receiving objects: 100% (7876/7876), 6.35 MiB | 812.00 KiB/s, done.
Resolving deltas: 100% (5443/5443), done.

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/github.com/golang/net (master)
$ go mod init github.com/golang/net  #创建modules
go: creating new go.mod: module github.com/golang/net

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/github.com/golang/net (master)
$ cat go.mod
module github.com/golang/net

回到原来的项目:

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module)
$ go mod edit -require=golang.org/x/net@v1.2.3 # 

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module)
$  go mod edit -replace=golang.org/x/net@v1.2.3=/d/code/gopath/src/github.com/golang/net # 使用replace替换到指定的目录了

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module)
$ go build  # 这一次成功了

qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module)
$ ls
cmd.exe  main.go

最后

最后说明一下最新出来的特性不建议立即使用到线上,最好再等等,等迭代一两个版本之后,得带最佳实践出来之后,毕竟现在支持modules模式的类库还真不多。

附录

收藏
评论区

相关推荐

关于Golang的那些事(一) -- Node.js和Golang对比
之前一直用Node.js作为开发语言,用了差不多4年的Node.js,涉及前端和后端,最近看到Golang这个新兴之秀挺火的,于是想探究探究一下这门语言,对比了一下他们的Github repo,截止现在Node.js的repo有72.5K星, issue数量是859个,Golang的repo有75.7K星,issue数量是5K个。从趋势来看,Golang来势
Mac安装Golang和vscode
Mac第一次安装golang和vscode一起使用,遇到了不少的坑,下面介绍一下正确的安装方式。 1、使用brew安装Golang 如果不知道brew是什么,或怎么安装请看这里 brew官网(https://brew.sh/index_zhcn) brew install golang 安装完成后可以使用
golang 分析调试高阶技巧
layout: post title: “golang 调试高阶技巧” date: 2020603 1:44:09 0800 categories: golang GC 垃圾回收 golang 高阶调试 Golang tools nm compile
Go WEB入门
摘要 由于Golang优秀的并发处理,很多公司使用Golang编写微服务。对于Golang来说,只需要短短几行代码就可以实现一个简单的Http服务器。加上Golang的协程,这个服务器可以拥有极高的性能。然而,正是因为代码过于简单,我们才应该去研究他的底层实现,做到会用,也知道为什么这么用。 在本文中,会以自顶向下的方式,从如何使用,到如何实现,一点点的分
Go 语言编程 — go mod 依赖包管理
目录 == ### 文章目录 * 目录 * go mod 依赖包管理 * 使用 go mod go mod 依赖包管理 ============ go mod 是 Golang 1.11 版本引入的依赖包管理工具。其中,Golang 对 Modules 的定义:Modules 是相关 Go Packages 的集合,是源代码交换和版本控制
Go语言入门系列(一)之Go的安装和使用
1.安装环境 ====== 1. 进入[Golang官网](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgolang.org),进入下载页面。 (如果打不开可访问[Golang中国](https://www.oschina.net/action/GoToLink?u
Archlinux下Visual Studio Code配置Golang开发环境
一、Golang的安装 ----------- GoLang安装并验证一下: [cox@localhost ~]$ sudo pacman -S go [cox@localhost ~]$ go version go version go1.8.3 linux/amd64s 要注意,Golang的安装要确保两个环境变量,一个是G
Golang Gin实践 番外 请入门 Makefile
<h1>Golang Gin实践 番外 请入门 Makefile</h1> <p>原文地址:<a href="https://github.com/EDDYCJY/blog/blob/master/golang/gin/2018-08-26-Gin%E5%AE%9E%E8%B7%B5-%E7%95%AA%E5%A4%96-%E8%AF%B7%E5%85%A5
Golang In PingCAP
随着 Golang 在后端领域越来越流行,有越来越多的公司选择 Golang 作为主力开发语言。本次 GopherChina Beijing 2016 大会上,看到 Golang 在各家公司从人工智能到自动运维,从 Web 应用到基础架构都发挥着越来越多的作用。可以说 Golang 在这几年间,获得了长足的进步。 PingCAP 是一家由几名 Go
Golang modules 初探
今天天色刚刚亮起,起床看到golang 1.11正式发版了,有着两个重要的特性:modules和WebAssembly。 本博文只要说的是modules,从Java转golang的同学肯定是对golang的包管理充满了无奈之情,我也曾在博客中介绍过[glide](https://my.oschina.net/u/553243/blog/1475626),也
Golang 内存管理源码剖析
Golang 的内存管理基于 tcmalloc,可以说起点挺高的。但是 Golang 在实现的时候还做了很多优化,我们下面通过源码来看一下 Golang 的内存管理实现。下面的源码分析基于 go1.8rc3。 1.tcmalloc 介绍 ------------- 关于 tcmalloc 可以参考这篇文章 [tcmalloc 介绍](https://ww
Golang 开发环境搭建
Golang 是 Google 发布的开发语言,Go 编译的程序速度可以媲美 C/C++。 安装 -- sudo apt-get install golang sudo apt-get install golang-go.tools 使用 -- * 编译运行程序 go run main.go * 查看命令文
Golang 文章正文抽取(readability)
readability for golang Golang版本是根据[readabiliity for node.js](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fluin%2Freadability)以及[readability for python](h
Golang依赖管理工具:glide从入门到精通使用
介绍 -- 不论是开发Java还是你正在学习的Golang,都会遇到**依赖管理**问题。Java有牛逼轰轰的Maven和Gradle。 Golang亦有godep、govendor、glide、gvt、gopack等等,本文主要给大家介绍[gilde](https://www.oschina.net/action/GoToLink?url=https%3
Sentinel
![9.28头图.png](https://ucc.alicdn.com/pic/developer-ecology/af7ab6c27c3c4c3aa5dc2cce3c9e8ab9.png) > \*\*导读:\*\*2020年,Sentinel 推出 Go 原生版本[Sentinel-Golang](https://www.oschina.net/ac