go依赖管理与go_module使用

go依赖管理与go_module使用

go依赖管理

为什么需要依赖管理

​ 最初:go依赖的第三库都在GOPATH的目录下,会导致同一个库只能保存一个版本的代码,如果不同项目依赖同一个第三库的不同版本,如何解决?

godep

​ go从1.5版本开始引入vener模式,如项目目录下有vender目录,那么go会优先使用vender内的包进行编译测试;

​ godep是通过vender模式实现的go语言的第三方依赖管理工具,类似的有社区维护的包管理工具dep;

安装

​ 在命令行中安装godep工具;

image-20201225100618380

基础命令

C:\Users\ten>godep
Godep is a tool for managing Go package dependencies.

Usage:

        godep command [arguments]

The commands are:

    save     list and copy dependencies into Godeps
    go       run the go tool with saved dependencies
    get      download and install packages with specified dependencies
    path     print GOPATH for dependency code
    restore  check out listed dependency versions in GOPATH
    update   update selected packages or the go version
    diff     shows the diff between current and previously saved set of dependencies
    version  show version info

Use "godep help [command]" for more information about a command.

godep使用

# cmd切换其他盘符的命令:加个/d
C:\ISOs>cd /d D:\workstation\mycode\gocode\src\hello2 


  1. 在项目源码目录执行dodep save;

    D:\workstation\mycode\gocode\src\hello2>godep save     
       
    D:\workstation\mycode\gocode\src\hello2>
    
  2. 之后,会在项目目录下生成Godeps和vender目录;

    image-20201225103840408

  3. Godeps目录下有Godeps.json文件,记录了项目依赖的包信息;vender下是项目依赖包的源码文件;

    image-20201225103908837

vender机制

​ go1.5后开始支持,控制了go编译时依赖包搜索路径的优先级;

​ 例如:查看某项目依赖包时,会先在项目根目录下的vender查看,没有就去就$GOPATH/src目录下找;

godep开发流程

  1. 保证程序正常编译;
  2. 执行godep save保存当前项目的所有第三方依赖的版本信息和源码;
  3. 提交Godeps目录和vender目录到代码库;
  4. 更新依赖包版本时,修改Godeps.json中对应项即可;

go_module

​ go1.11后推出的版本管理工具,1.13版本会成为默认管理工具;

go111module

  1. 启用go module先设置环境变量GO111MODULE,其有三个值:
    1. off:禁用go module,编译时从GOPATH和vender下找包;
    2. on;启用go module,编译时忽略GOPATH和vender,只根据go.mod下载依赖;
    3. auto-默认值:当项目在$GOPATH/src外且项目根目录有go.mod文件时,开始go module模块支持;

设置GO111MODULE=on后,即可使用go module管理依赖,不必非要在GOPATH中创建项目,使用go module管理依赖后,会再项目根目录生成go.mod和go.sum文件;

goproxy

unix:
export GOPROXY=https://goproxy.cn

windows:
go env -w GOPROXY=https://goproxy.cn,direct

go mod命令

D:\workstation\mycode\gocode\src\hello2>go mod
Go mod provides access to operations on modules.

Note that support for modules is built into all the go 
commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.

Usage:

        go mod <command> [arguments]

The commands are:

        download    download modules to local cache    
        edit        edit go.mod from tools or scripts  
        graph       print module requirement graph     
        init        initialize new module in current directory
        tidy        add missing and remove unused modules
        vendor      make vendored copy of dependencies 
        verify      verify dependencies have expected content
        why         explain why packages or modules are needed

Use "go help mod <command>" for more information about 
a command.

go.mod

go.mod文件记录了项目依赖的所有依赖信息,结构如下:

module github.com/Q1mi/studygo/blogger

go 1.12

require (
	github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586
	github.com/gin-gonic/gin v1.4.0
	github.com/go-sql-driver/mysql v1.4.1
	github.com/jmoiron/sqlx v1.2.0
	github.com/satori/go.uuid v1.2.0
	google.golang.org/appengine v1.6.1 // indirect
)

#
module定义包名;
require定义依赖包和其版本;
indirect表示间接引用;

依赖包的版本表示法:

  • 支持版本号:go get foo@v1.2.3
  • 支持git分支或tag:go get foo@master
  • 支持git提交哈希:go get foo@e3702bed2
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
gopkg.in/vmihailenco/msgpack.v2 v2.9.1
gopkg.in/yaml.v2 <=v2.2.1
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
latest

replace:

golang.org/x下的包无法访问,因此可以用go.mod中的replace替换为github上对应的库;

replace (
	golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac
	golang.org/x/net v0.0.0-20180821023952-922f4815f713 => github.com/golang/net v0.0.0-20180826012351-8a410e7b638d
	golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
)

go get

go get命令用来下载依赖包,可指定版本;

  1. go get -u会升级最新的次要版本或修定版本(x.y.z,z是修订版本号,y是次要版本号)
  2. go get -u=patch会升级到最新修订版
  3. go get package@version会升级到指定版本
  4. go mod download下载所有依赖

整理依赖

代码中删除依赖代码后,相关依赖库不会在go.mod中自动移除,使用go mod tidy命令可更新go.mod中依赖关系;

go mod edit

格式化go.mod文件

go mod edit -fmt

添加依赖项:

go mod edit -require=golang.org/x/text

移除依赖项:

go mod edit -droprequire=golang.org/x/text
移除一个依赖

在项目中使用go module

既有项目

对一个已经存在的项目启用go module

  1. 项目目录下执行go mod init,生成go.mod文件
  2. 执行go get,查找当前项目依赖,并生成一个go.sum记录每个依赖库的版本和哈希值

新项目

创建一个新创建项目并启用go module

  1. go mod init “项目名”,在当前项目目录下生成go.mod文件
  2. 手动编辑go.mod中的require依赖,或执行go get自动发现,解决依赖;

go module导入本地包

go module是go1.11后官方推出的版本管理工具,go1.13后成为默认的依赖管理工具;

同一个项目下

  1. 目录结构如下:在GOPATH目录的src目录下新建一个moduledemo目录;

    moduledemo
    ├── go.mod
    ├── main.go
    └── mypackage
        └── mypackage.go
    
  2. vscode新建一个项目文件夹;在src目录下

    image-20201225120639515

  3. 准备mypackage/mypackage.go

    定义了一个new方法,其功能就是输出一行mypackage.New;

    package mypackage
       
    import "fmt"
       
    func New(){
     fmt.Println("mypackage.New")
    }
    

    image-20201225120816543

  4. 初始化go.mod文件

    D:\workstation\mycode\gocode\src\moduledemo>go mod init
    go: creating new go.mod: module moduledemo
    

    image-20201225121006786

  5. 编辑main.go

    import了fmt和module/mypackage包,并在main中调用了2个方法;

    package main
       
    import (
     "fmt"
     "moduledemo/mypackage"
    )
       
    func main(){
     mypackage.New()
     fmt.Println("main")
    }
    
  6. 编译当前项目

    D:\workstation\mycode\gocode\src\moduledemo>go build
    
  7. 运行测试:成功编译,并执行;

    D:\workstation\mycode\gocode\src\moduledemo>moduledemo.exe
    mypackage.New
    main
    

不同项目下

  1. 目录结构如下:2个项目下,都有go mod init初始化一个go.mod文件

    ├── moduledemo2
    │   ├── go.mod
    │   └── main.go
    └── mypackage
        ├── go.mod
        └── mypackage.go
    
  2. 在GOPATH的src目录分别创建2个项目目录

    image-20201225143359784

  3. moduledemo2的文件内容

    # main.go文件;引入了fmt和mypackage包,然后在main函数中输出;
    --------
    package main
       
       
    import (
     "fmt"
     "mypackage"
    )
       
    func main()  {
     mypackage.New()
     fmt.Println("main")
    }
       
    # go.mod文件;由于mypackage在本地,没有发布到远程的代码仓库,且不在moduledemo2的子目录,因此采用require指令引用,replace指令指明路径;
    -------
    module moduledemo2
       
    go 1.14
       
    require "mypackage" v0.0.0
    replace "mypackage" => "../mypackage"
    
  4. mypackage的文件内容

    # package.go内容;定义了一个方法New(),可以输出一句话
    package mypackage
       
    import "fmt"
       
    func New(){
     fmt.Println("mypackage.New")
    }
       
    # go.mod文件
    module mypackage
       
    go 1.14
    
  5. 在moduledemo2下编译

    D:\workstation\mycode\gocode\src\moduledemo2>go build
       
    D:\workstation\mycode\gocode\src\moduledemo2>moduledemo2.exe
    mypackage.New
    main
    

不同项目的示例2:

  1. 2个项目的目录结构

    ├── p1
    │   ├── go.mod
    │   └── main.go
    └── p2
        ├── go.mod
        └── p2.go
    

    image-20201225150609672

  2. 定义p2项目

    1. 定义p2的go.mod

      module github.com/ice-latte/p2 // 定义这个模块的名字,以github.com做顶级域名,可上传到github;引用名字就是该“github.com/ice-latte/p2”
            
      go 1.14
            
      
    2. 定义p2的方法

      package p2 // p2定义了一个方法输出一行文本,可被其他项目引用
            
      import "fmt"
            
      func New(){
        fmt.Println("this is p2 new func")
      }
      
  3. 定义p1项目

    1. 定义p1的go.mod,引用了p2这个module

      module p1 // 定义这个模块的名字叫p1,也可以github.com/用户名做前缀,然后上传到github
            
      go 1.14
            
      require "github.com/ice-latte/p2" v0.0.0 // 定义依赖模块,模块名是github.com/ice-latte/p2,版本v0.0.0
            
      replace "github.com/ice-latte/p2" => "../p2" // 因p2模块并未上传到github上,还在本地,需要用replace执向其在本地的路径;
      
    2. 定义p1的主函数,main方法中输出2个语句

      package main
            
      import ( // 引用了2个模块
        "fmt"
        "github.com/ice-latte/p2" // 该模块指向了本地的p2项目;
      )
            
      func main(){
        p2.New() // 调用了p2的new方法,
        fmt.Println("this is p1 main") // 调用了fmt的Println方法
      }
      
updatedupdated2020-12-282020-12-28
加载评论