• Golang(八)go modules 学习


    0. 前言

    • 最近加入鹅厂学习 k8s,组内使用 Go 1.11 以上的 go modules 管理依赖,因此整理了相关资料
    • 本文严重参考原文:初窥Go module

    1. 传统 Golang 包依赖管理

    • Golang 设计深受 Google 主干开发模型影响:

      • 所有开发人员基于主干 trunk/mainline 开发:提交到 trunk 或从 trunk 获取最新的代码(同步到本地 workspace)
      • 版本发布时,建立 Release branch,release branch 实质上就是某一个时刻主干代码的快照
      • release branch 上 的 bug fix 和增强改进代码也通常是先在主干上提交(commit),然后再 cherry-pick 到 release branch 上

    • Golang 中的 go get 的设计深受 Google 内部单一代码仓库(single monorepo)和基于主干(trunk/mainline based)的开发模型的影响:只获取 trunk/mainline 最新版本
    • go get 获取的代码会放在 $GOPATH/src 下面,而 go build 会在 $GOROOT/src 和 $GOPATH/src 下面按照 import path 去搜索 package
    • 由于 go get 获取的都是各个 package repo 的 trunk/mainline 的代码,因此 Go 1.5 之前的 Go compiler 都是基于目标 Go 程序依赖包的 trunk/mainline 代码去编译的
    • 这样的机制带来的问题包括:
      • trunk/mainline 代码时刻变化,不同人不同时刻获取的代码可能不同(即不能实现 reproduceable build)
      • 依赖包的 trunk 演进可能会导致代码无法编译
    • 为了实现 reporduceable build,Go 1.5 引入了 govendor 机制
      • Golang 编译器会优先在 vendor 下搜索依赖的第三方包
      • 开发者将特定版本的依赖包存放在 vendor 下面并提交到代码库
      • 那么所有人理论上都会得到同样的编译结果,从而实现reporduceable build
    • 在Go 1.5 发布后的若干年,Gopher 们把注意力都集中在如何利用 vendor 解决包依赖问题
      • 从手工添加依赖到 vendor
      • 手工更新依赖,到一众包依赖管理工具的诞生:比如: govendor、glide 以及号称准官方工具的 dep
      • 努力地尝试着按照当今主流思路解决着诸如:“钻石型依赖”等难题
    • 正当 Gopher 认为 dep 将顺理成章地升级为 go toolchain 一部分的时候,vgo 横空出世
    • 在原 Go tools 上简单快速地实现 了Go 原生的包依赖管理方案 ,vgo 就是 go modules 的前身

    2. go modules 简介

    • 通常我们会在一个仓库中创建一组 package,仓库的路径比如:github.com/bigwhite/gocmpp 会作为 go package 的导入路径(import path)
    • GOPATH 模式下,编译器会根据 package 路径在 $GOPATH/src 或者 vendor 下逐级目录匹配
    • Go 1.8 版本中,如果开发者没有显式设置 $GOPATH,Go 会赋予 GOPATH 一个默认值(在 linux 上为 $HOME/go)
    • Go 1.11 给这样的一组在同一仓库下面的 packages 赋予了一个新的抽象概念:module
    • 并启用一个新的文件 go.mod 记录 module 的元信息
    • 一个仓库对应一个 module 或者多个 module
    • 在 go modules 下,仓库顶层目录下会放置一个 go.mod 文件,每个 go.mod 文件定义了一个 module,而放置 go.mod 文件的目录被称为 module root 目录(通常对应一个仓库的 root 目录,但不是必须的)
    • module root 目录以及其子目录下的所有 packages 均归属于该 module,除了那些自身包含 go.mod 文件的子目录
    • 在 go modules 下,Golang 编译器将不再在 GOPATH 下面以及 vendor 下面搜索目标程序依赖的第三方 packages

    3. 尝试使用 go modules

    • 设置环境变量 GO111MODULE:
      • GO111MODULE=off:无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包
      • GO111MODULE=on:模块支持,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖
      • GO111MODULE=auto:在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持
    • 在使用模块的时候,GOPATH 是无意义的,不过还是会把下载的依赖储存在 $GOPATH/pkg/mod 中,也会把 go install 的结果放在 $GOPATH/bin 
    • 在 ~/test 下创建 hello 目录,然后写入 hello.go(此时不在 $GOPATH 中)
    // hello.go
    package main
    
    import "bitbucket.org/bigwhite/c"
    
    func main() {
        c.CallC()
    }
    View Code
    • 在 ~/test/hello 下创建 go.mod:

    // go.mod
    module hello
    View Code
    • 构建 hello.go:
    $ go build hello.go
    go: finding bitbucket.org/bigwhite/c v1.3.0
    go: downloading bitbucket.org/bigwhite/c v1.3.0
    go: extracting bitbucket.org/bigwhite/c v1.3.0
    go: finding bitbucket.org/bigwhite/d v1.2.0
    go: downloading bitbucket.org/bigwhite/d v1.2.0
    go: extracting bitbucket.org/bigwhite/d v1.2.0
    
    $ ./hello.exe
    call C: v1.3.0
       --> call D:
            call D: v1.2.0
       --> call D end
    View Code
    • 查看 go.mod:
    $ cat go.mod
    // go.mod
    module hello
    
    go 1.12
    
    require bitbucket.org/bigwhite/c v1.3.0 // indirect
    View Code
    • indirect 指不是由主 mod 直接引用的包,而是由其他 mod 间接引用的包
    • 如果之后新增了该 mod 的直接引用,会删除上面的间接引用
    • go compiler 将下载的依赖包缓存在 $GOPATH/pkg/mod 下面:
    $ pwd
    /e/Coding/Golang/go/pkg/mod/cache/download
    
    $ ls
    bitbucket.org/     github.com/   golang.org/         gopkg.in/  sigs.k8s.io/
    cloud.google.com/  go.uber.org/  google.golang.org/  k8s.io/
    View Code
    • 具体执行:

    $ ./hello.exe
    call C: v1.3.0
       --> call D:
            call D: v1.2.0
       --> call D end
    View Code

    4. 参考文献

  • 相关阅读:
    MyBatis3: There is no getter for property named 'code' in 'class java.lang.String'
    jQuery获取Select选择的Text和 Value(转)
    mybatis3 :insert返回插入的主键(selectKey)
    【转】Mybatis/Ibatis,数据库操作的返回值
    Android问题-打开DelphiXE8与DelphiXE10编译空工程提示“[Exec Error] The command exited with code 1.”
    Android问题-打开DelphiXE8与DelphiXE10新建一个空工程提示"out of memory"
    BAT-使用BAT生成快捷方式
    给 TTreeView 添加复选框
    跨进程发送消息数据
    鼠标拖动虚影效果
  • 原文地址:https://www.cnblogs.com/wangao1236/p/11002871.html
Copyright © 2020-2023  润新知