zoukankan      html  css  js  c++  java
  • go mod常用命令 已经 常见问题

    最近接触到go mod,网上查了查资料,这里记录一下。

    1 介绍

    1.1、go mod是什么

          go mod 是Golang 1.11 版本引入的官方包(package)依赖管理工具,用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。

          之前Golang 主要依靠vendor和GOPATH来管理依赖库,vendor相对主流,但现在官方更提倡go mod。

    1.2、go mod初始化及使用

    下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)

    Golang 提供一个环境变量 GO111MODULE 来设置是否使用mod,它有3个可选值,分别是off, on, auto(默认值),具体含义如下:

    1. off: GOPATH mode,查找vendor和GOPATH目录
    2. on:module-aware mode,使用 go module,忽略GOPATH目录
    3. auto:如果当前目录不在$GOPATH 并且 当前目录(或者父目录)下有go.mod文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode。

    修改 GO111MODULE 的值的语句是:set GO111MODULE=on 。

    在使用模块的时候, GOPATH 是无意义的,不过它还是会把下载的依赖储存在 GOPATH/src/mod 中,也会把 go install 的结果放在 GOPATH/bin(如果 GOBIN 不存在的话)

    • go mod download 下载模块到本地缓存,缓存路径是 $GOPATH/pkg/mod/cache
    • go mod edit 是提供了命令版编辑 go.mod 的功能,例如 go mod edit -fmt go.mod 会格式化 go.mod
    • go mod graph 把模块之间的依赖图显示出来
    • go mod init 初始化模块(例如把原本dep管理的依赖关系转换过来)
    • go mod tidy 增加缺失的包,移除没用的包
    • go mod vendor 把依赖拷贝到 vendor/ 目录下
    • go mod verify 确认依赖关系
    • go mod why 解释为什么需要包和模块

    注意有几个坑的地方:

    • go mod 命令在 $GOPATH 里默认是执行不了的,因为 GO111MODULE 的默认值是 auto。默认在$GOPATH 里是不会执行, 如果一定要强制执行,就设置环境变量为 on

    • go mod init 在没有接module名字的时候是执行不了的,会报错 go: cannot determine module path for source directory。可以这样执行:

      $ go mod init github.com/jiajunhuang/hello
      

      否则就要在 main.go 里加上导入声明,例如:

      $ cat main.go
      package main
      
      func main() {
          println("Hello world")
      }
      $ go mod init
      go: cannot determine module path for source directory /Users/jiajun/hello (outside GOPATH, no import comments)
      $ vim go.mod
      $ cat go.mod
      module github.com/jiajunhuang/hello
      $ go mod init
      go mod init: go.mod already exists
      $ rm go.mod
      $ vim main.go
      $ cat main.go
      package main // import "github.com/jiajunhuang/hello"
      
      func main() {
          println("Hello world")
      }
      $ go mod init
      go: creating new go.mod: module github.com/jiajunhuang/hello
      $ ls
      go.mod  main.go
      $ cat go.mod
      module github.com/jiajunhuang/hello
      

      当然,如果在已有代码的仓库里执行是不存在这个问题的。

    2 命令

    2.1 指定module的根目录并生成go.mod文件

    go mod init example.com/hello

    2.2 下载并添加依赖到go.mod文件中

    go build, go test

    2.3 查看module下的所有依赖

    go list -m all

    2.4 更新稳定版依赖

    go get rsc.io/sampler

    2.5 更新为指定版本依赖

    1.  
      go list -m -versions rsc.io/sampler
    2.  
       
    3.  
      rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
    4.  
       
    5.  
      go get rsc.io/sampler@v1.3.1

    2.6 清理无用的依赖

    go mod tidy

    2.7 将依赖复制到项目路径的vendor文件夹中

    go mod vendor

    2.8 忽略cache里的包,只使用vendor目录里的依赖进行编译

    go build -mod=vendor

    2.9 校验依赖并查看是否有修改

    go mod verify

    3 问题

    3.1 go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

    go mod init

    go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

    开启go module:

    1. set GO111MODULE=on //windows

    2. export GO111MODULE=on //linux

    3.2 $GOPATH/go.mod exists but should not

    GO 1.11或之后模块遇到这个问题:

    $GOPATH/go.mod exists but should not
    

        开启模块支持后(set GO111MODULE=on),并不能与$GOPATH共存,所以把$GOPATH从env中移出即可(unset GOPATH),可运行“unset GOPATH && make”。

    4 例子

    4.1 例子1

    go mod初始化:在$GOPATH外建一个文件夹,把个人代码放进去,我的测试代码路径:https://github.com/kevinhao8/go-mod-example。

    首先main入口代码所在文件夹创建mod

    创建语句  go mod init [module name]

    比如我的测试代码 redisTest.go,创建语句就是  go mod init redisTest,成功创建时返回  go: creating new go.mod: module redisTest

    此时文件夹下出现 go.mod文件,打开发现只有2行如下,并没有记录依赖库。

    module redisTest

    go 1.12

    此时需要输入go test语句,根据需要的依赖自动生成require,也就是依赖包,此时go.mod多了如下内容(红字是我写的注释,文件里面没有)

    require (
          github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect(有indirect注释的代表间接依赖,没有的代表直接依赖)
          github.com/gin-gonic/gin v1.3.0  
          github.com/golang/protobuf v1.3.1 // indirect
          github.com/mattn/go-isatty v0.0.7 // indirect
          github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect(这里是版本号+时间戳+hash)
          gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
          gopkg.in/yaml.v2 v2.2.2 // indirect
    )

    此时会有如下失败提示,此处为我踩得第一个坑!!!花了挺长时间才解决

    build redisTest: cannot load dbredis: cannot find module providing package dbredis

    dbredis是我写的私有包,代码是没有问题的,为什么找不到呢?从网上查了一圈,发现私有包如果不想发布到网上,需要手动添加require ,然后replace 进行替换,将私有包指向本地module所在的绝对或相对路径。一般用相对路径更通用。

    此时手动将go.mod改为如下,红字为新加

    require (
          dbredis v0.0.0
          github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
          github.com/gin-gonic/gin v1.3.0
          github.com/golang/protobuf v1.3.1 // indirect
          github.com/mattn/go-isatty v0.0.7 // indirect
          github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect
          gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
          gopkg.in/yaml.v2 v2.2.2 // indirect
    )

    replace dbredis v0.0.0 => ./dbredis

    再度运行go test  命令,发现仍有失败提示如下,找不到dbredis文件夹下的go.mod文件。

    go: parsing dbredisgo.mod: open E:codego-mod-exampledbredisgo.mod: The system cannot find the file specified.
    go: error loading module requirements

    从网上查资料发现,这种情况下需要给私有包也生成mod,这样整个工程的依赖才能完整。故运行如下命令:

    cd dbredis

    go mod init dbredis(此处我写的mod名跟package名一致,不知道不一致行不行)

    go test

    三条命令依次运行通过,dbredis文件夹下的go.mod文件如下:

    module dbredis

    go 1.12

    require github.com/go-redis/redis v6.15.2+incompatible

    此时再运行如下命令:

    cd ..(回到上层文件夹)

    go test

    运行通过,不再有报错。运行命令 go build redisTest.go 也能够正常生成redisTest.exe

    至此通过mod来管理依赖包基本实现,我们的程序能基本脱离$GOPATH编译。
     

    5 go mod 和 dep 比较

    • go mod 支持代理,以后就可以使用私有镜像源了~,具体请搜索 GOPROXY
    • go mod 速度比 dep 快很多
    • go.mod 中列出了所有的依赖,这一点其实我不是很喜欢,因为当项目一大,历史一久,只要升级其中一个依赖,很可能整个依赖 就挂了。我还是比较喜欢只要列出顶级依赖,由程序处理子依赖的情况。

    一个生成的 go.mod 的示例

    module github.com/my/module/v3  // 这是你的包的声明
    
    // require 里是依赖。需要带上路径和版本。
    require (
        github.com/some/dependency v1.2.3
        github.com/another/dependency v0.1.0
        github.com/additional/dependency/v4 v4.0.0
    )
    

    其他

    windows下的尝试:

    gomod初尝试
    下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)
    go mod help查看帮助
    go mod init<项目模块名称>初始化模块,会在项目根目录下生成 go.mod文件。

    go mod tidy根据go.mod文件来处理依赖关系。

    go mod vendor将依赖包复制到项目下的 vendor目录。建议一些使用了被墙包的话可以这么处理,方便用户快速使用命令go build -mod=vendor编译

    go list -m all显示依赖关系。go list -m -json all显示详细依赖关系。

    go mod download <path@version>下载依赖。参数<path@version>是非必写的,path是包的路径,version是包的版本。

    在gopath外新建一个项目,单独开一个cmd设置set GO111MODULE=on(习惯性的和git初始化一样)go mod init然后报错了。 正解如下:go mod init xxx(module名称可与文件名不同)

    在项目目录下执行go mod tidy下载完成后项目路径下会生成go.mod和go.sum

    go.mod文件必须要提交到git仓库,但go.sum文件可以不用提交到git仓库(git忽略文件.gitignore中设置一下)。

    go模块版本控制的下载文件及信息会存储到GOPATH的pkg/mod文件夹里。

    --------------------分割线---------------------------------------------------------

    gopath 与go mod的区别

    1.  
      环境变量GOPATH不再用于解析imports包路径,即原有的GOPATH/src/下的包,通过import是找不到了。
    2.  
      Go Module功能开启后,下载的包将存放与$GOPATH/pkg/mod路径
    3.  
      $GOPATH/bin路径的功能依旧保持


    go get 流程的变化

    1.  
      老的go get取包过程类似:git clone + go install , 开启Go Module功能后go get就只有 git clone 或者 download过程了。
    2.  
      新老实现还有一个不同是,两者存包的位置不同。前者,存放在$GOPATH/src目录下;后者,存放在$GOPATH/pkg/mod目录下。
    3.  
      老的go get取完主包后,会对其repo下的submodule进行循环拉取。新的go get不再支持submodule子模块拉取。



    依赖包的变化

    1.  
      三方远程包:
    2.  
      检查远程仓库最新的tag版本,有就取得该版本
    3.  
      远程仓库没有tag版本时,直接获取master分支的HEAD版本
    4.  
      如果在go.mod文件中指定了具体版本,go get直接获取该指定版本
    5.  
      go.mod中除了可以指定具体版本号以外,还支持分支名
    6.  
       
    7.  
      本地包:
    8.  
      通过replace()进行替换


    私有仓库权限和私有vcs非标准路径取包问题

    1.  
      权限问题
    2.  
      windows10下:
    3.  
          控制面板>用户账户>凭据管理手动添加普通凭据即可
    4.  
      linux下:
    5.  
      增加 $HOME/.gitconfig 配置:
    6.  
      [url "ssh://git@github.com/MYORGANIZATION/"]
    7.  
      insteadOf = https://github.com/MYORGANIZA...
    8.  
       
    9.  
      增加 $HOME/.netrc:
    10.  
      machine github.com login YOU password APIKEY
    11.  
      将其中的 APIKEY 换成自己的登录KEY。
    12.  
       
    13.  
      非标准路径问题(https://private.vcs.com:20000)
    14.  
      搭建一个中间服务:https://private.vcs.com 能够通过go get的包路径匹配查询正确的仓库地址。


     

    参考:

    https://blog.csdn.net/Lazybones_3/article/details/89355133

    https://blog.csdn.net/kevinh531/article/details/88691870

    https://jiajunhuang.com/articles/2018_09_03-go_module.md.html

    https://blog.csdn.net/qq_33296108/article/details/88184060 

  • 相关阅读:
    SGU 271 Book Pile (双端队列)
    POJ 3110 Jenny's First Exam (贪心)
    HDU 4310 Hero (贪心)
    ZOJ 2132 The Most Frequent Number (贪心)
    POJ 3388 Japanese Puzzle (二分)
    UVaLive 4628 Jack's socks (贪心)
    POJ 2433 Landscaping (贪心)
    CodeForces 946D Timetable (DP)
    Android Studio教程从入门到精通
    Android Tips – 填坑手册
  • 原文地址:https://www.cnblogs.com/wl-blog/p/14978386.html
Copyright © 2011-2022 走看看