zoukankan      html  css  js  c++  java
  • golang包管理解决之道——go modules初探

    golang的包管理是一直是为人诟病之处,从golang1.5引入的vendor机制,到准官方工具dep,目前为止还没一个简便的解决方案。

    不过现在go modules随着golang1.11的发布而和我们见面了,这是官方提倡的新的包管理,乃至项目管理机制,可以不再需要GOPATH的存在。

    go module的初始化

    现在modules机制仍在早期阶段,所以golang提供了一个环境变量“GO111MODULE”,默认值为auto,如果当前目录里有go.mod文件,就使用go modules,否则使用旧的GOPATH和vendor机制,因为在modules机制下go get只会下载go modules,这一行为会在以后版本中成为默认值,这里我们保持auto即可,如果你想直接使用modules而不需要从GOPATH过度,那么把“GO111MODULE”设置为on。

    modules和传统的GOPATH不同,不需要包含例如src,bin这样的子目录,一个源代码目录甚至是空目录都可以作为module,只要其中包含有go.mod文件。

    我们就用一个空目录来创建我们的第一个module:

    要初始化modules,需要使用如下命令(假设已经安装配置好golang1.11):

    go mod init [module name]

    我们的module叫test,所以就是:

    go mod init test

    初始完成后会在目录下生成一个go.mod文件,里面的内容只有一行“module test”。

    包管理

    那么我们怎么进行包管理呢?别担心,当我们使用go build,go test以及go list时,go会自动得更新go.mod文件,将依赖关系写入其中。

    如果你想手动处理依赖关系,那么使用如下的命令:

    go mod tidy

    这条命令会自动更新依赖关系,并且将包下载放入cache。

    下面我们使用chromedp的一个简单example作为实验代码main.go,看下go modules是如何处理包的依赖关系的。

    我们手动运行go mod tidy:

    查找并下载包

    我们发现多了一个go.sum,我们看看它里面是什么内容:

    没错,你已经猜到了,这是我们直接引用的package和它自身需要的以来的版本记录,go modules就是根据这些去找到需要的packages的。

    顺带一提,如果我们不做任何修改,默认会使用最新的包版本,如果包打过tag,那么就会使用最新的那个tag对应的版本。

    下面我们使用go build来编译我们的代码:

    go build

    值得注意的是,新增了一个编译选项“-mod”,它有如下的可选值:

    go build -mod=readonly

    在这个模式下任何会导致依赖关系变动的情况都将导致build失败,前面提到过build能查找并更新依赖关系,使用这个选项可以检查依赖关系的变动。

    go build -mod=vendor

    意思是忽略cache里的包,只使用vendor目录里的版本。

    构建完成后目录结构如下:

    我们的代码成功构建了,包管理都由go modules替我们完成了。

    包的版本控制

    包管理的另外一项重要功能就是包的版本控制。modules同样可以做到。

    在介绍版本控制之前,我们要先明确一点,如果上层目录和下层目录的go.mod里有相同的package规则,那么上层目录的无条件覆盖下层目录,目的是为了main module的构建不会被依赖的package所影响。

    那么我们看看go.mod长什么样:

    module test
    
    require github.com/chromedp/chromedp v0.1.2

    如果有多个依赖,可以是这样的:

    module github.com/chromedp/chromedp
    
    require (
    	github.com/chromedp/cdproto v0.0.0-20180713053126-e314dc107013
    	github.com/disintegration/imaging v1.4.2
    	github.com/gorilla/websocket v1.2.0
    	github.com/knq/sysutil v0.0.0-20180306023629-0218e141a794
    	github.com/mailru/easyjson v0.0.0-20180606163543-3fdea8d05856
    	golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81
    )

    前面部分是包的名字,也就是import时需要写的部分,而空格之后的是版本号,版本号遵循如下规律:

    vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
    vX.0.0-yyyymmddhhmmss-abcdefabcdef
    vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef
    vX.Y.Z

    也就是版本号+时间戳+hash,我们自己指定版本时只需要制定版本号即可,没有版本tag的则需要找到对应commit的时间和hash值。

    默认使用最新版本的package。

    现在我们要修改依赖关系了,我们想使用chromedp 的v0.1.0版本,怎么办呢?

    只需要如下命令:

    go mod edit -require="github.com/chromedp/chromedp@v0.1.0"

    @后面加上你需要的版本号。go.mod已经修改了:

    module test
    
    require github.com/chromedp/chromedp v0.1.0

    我们还需要让go modules更新依赖关系,这里我们手动go mod tidy之后:

    注意颜色较深的那两行,我们已经切换到了v0.1.0版本了。

    go modules是一个很大的主题,以后我还将进一步介绍它。

    如果想进一步深入go modules的使用,可以阅读我的这篇文章:再探go modules:使用与细节

    因为go1.11刚发布不久,这篇文件作为探路,必定会有错误和疏漏,欢迎大家指正!

  • 相关阅读:
    BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
    BZOJ 2134: 单选错位( 期望 )
    BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )
    BZOJ 2599: [IOI2011]Race( 点分治 )
    BZOJ 3238: [Ahoi2013]差异( 后缀数组 + 单调栈 )
    ZOJ3732 Graph Reconstruction Havel-Hakimi定理
    HDU5653 Bomber Man wants to bomb an Array 简单DP
    HDU 5651 xiaoxin juju needs help 水题一发
    HDU 5652 India and China Origins 并查集
    HDU4725 The Shortest Path in Nya Graph dij
  • 原文地址:https://www.cnblogs.com/apocelipes/p/9534885.html
Copyright © 2011-2022 走看看