zoukankan      html  css  js  c++  java
  • golang的包管理---vendor/dep等

    首先关于vendor

    1 提出问题

    我们知道,一个工程稍大一点,通常会依赖各种各样的包。而Go使用统一的GOPATH管理依赖包,且每个包仅保留一个版本。而不同的依赖包由各自的版本工具独立管理,所以当所依赖的包在新版本发生接口变更或删除时,会面临很多问题。
    为避免此类问题,我们可能会为不同的工程设置不同的GOPATH,或者更改依赖包路径名称。这样手动维护起来也很头疼。

    2 解决问题

    Go 1.5引入了vendor文件夹,其对语言使用,go命令没有任何影响。若某个路径下边包含vendor文件夹,则在某处引用包时,会优先搜索vendor文件夹下的包。
    在Go 1.5开启该项特性需设置GO15VENDOREXPERIMENT=1,而从Go 1.6开始,该项特性默认开启。

    3 使用方式

    3.1 vendor搜索方式

    vendor包的搜索方式为:自包引用处,从其所在文件夹查询是否有vendor文件夹包含所引用包;若没有,然后从其所在文件夹的上层文件夹寻找是否有vendor文件夹包含所引用包,若没有,则再搜索上层文件夹的上层文件夹...,直至搜索至(GOPATH/src并搜索完成时止。 例如,如下代码中,`)GOPATH/src/x/y/z/main.go引用了包"v",则不论vendor/v/v.go`置于src/,src/x/,src/x/y/,src/x/y/z/中任意一个文件夹下,均可以找到。

    $ cat $GOPATH/src/x/y/z/main.go
    
    package main
    
    import (
        "v"
    )
    
    func main() {
        v.V()
    }
    $ cat vendor/v/v.go
    
    package v
    
    import "fmt"
    
    func V() {
        fmt.Println("I'm a vendor test")
    }
    $ go run main.go
    

    I'm a vendor test

    当vendor存在嵌套时,若不同的vendor文件夹包含相同的包,且该包在某处被引用,寻找策略仍遵循如上规则。即从包引用处起,逐层向上层文件夹搜索,首先找到的包即为所引,也就是从$GOPATH/src来看,哪个vendor包的路径最长,使用哪个。

    如下代码中,(GOPATH/src/x/y/z/main.go所在工程有两个vendor文件夹(分别位于)GOPATH/src/x/vendor/v/,$GOPATH/src/x/y/z/vendor/v/)包含相同的包"v",目录树为:

    $ tree $GOPATH/src
    
    src
     └ x
       ├ vendor
       │  └ v
       │     └ v.go
       └ y
         └ z
           ├ vendor
           │ └ v
           │    └ v.go
           └ main.go
    $ cat $GOPATH/src/x/vendor/v/v.go
    
    package v
    
    import "fmt"
    
    func V() {
        fmt.Println("I'm a vendor test, My path is x/vendor/v/")
    }
    $ cat $GOPATH/src/x/y/z/vendor/v/v.go
    
    package v
    
    import "fmt"
    
    func V() {
        fmt.Println("I'm a vendor test, My path is x/y/z/vendor/v/")
    }
    

    输出为:

    $ go run main.go
    
    I'm a vendor test, My path is x/y/z/vendor/v/
    

    可以看到,真正调用的是$GOPATH/src/x/y/z/vendor/v/v.go。

    3.2 vendor使用规约

    使用vendor时,建议遵循如下两条规约。

    • a) 当欲将某包vendor时,可能想将所有依赖包均vendor;
    • b) 尽量将vendor依赖包结构扁平化,不要vendor套vendor。
      如下示例代码演示vendor扁平化使用。
      main.go位于$GOPATH/src/github.com/olzhy/test下。
    package main
    
    import (
        "strings"
        "sync"
        "time"
    
        "github.com/z"
        "github.com/y"
        "golang.org/z"
    )
    ...
    

    $GOPATH/src/github.com/olzhy/test目录树。

    ├─ main.go
    └─ vendor
        ├─ github.com
        │   ├─ x
        │   └─ y
        └─ golang.org
             └─ z
    

    参考资料
    [1] https://go.googlesource.com/proposal/+/master/design/25719-go15vendor.md
    [2] https://blog.gopheracademy.com/advent-2015/vendor-folder/
    [3] https://tonybai.com/2015/07/31/understand-go15-vendor/
    转自:

    https://leileiluoluo.com

    接下来是关于dep

    dep 是 golang 项目依赖管理之一,是官方的实验项目,目前更新很频繁处于高速发展期,所以选 dep 作为 golang 的依赖管理器是比较靠谱的。(已知 glide 仅支持不再开发新功能)
    目前 dep v0.5.0 release 已经发布,最新的 changelog 显示只支持 golang 1.9+ 以上的版本
    golang 最原始的依赖管理是 go get ,执行命令后会拉取代码放入 src 下面,但是它是作为 GOPATH 下全局的依赖,并且 go get 还不能版本控制,以及隔离项目的包依赖在没有依赖管理工具的时候,golang 项目有一种目录结构比较流行如下:

    .
    └── src
        ├── demo
        │   └── main.go
        ├── github.com
        ├── golang.org
        └── gopkg.in
    

    这样做的话就是每一个项目一个 GOPATH 则上面的 GOPATH=/xx/xx/src 这样设置后也是可以编译的,且项目依赖都是 src 下的包,与全局的无关联, go get 获取依赖,也必须在项目 GOPATH 下。可以看到这样的目录结构还是有很多缺陷的。特别是 import 包的包目录有时会很奇怪,没有统一的风格,且 ide 或 编辑器支持也不够理想。

    所以目前 golang 引入了 vendor 目录作为依赖管理目录,且 ide 或 golang 编辑插件目前都能很好的支持 例如 gogland 索引依赖包时会优先查找项目根目录下的 vendor 目录, vscode 的 go 插件也是。那么目前比较流行的目录结构如下:

    .
    ├── Gopkg.lock
    ├── Gopkg.toml
    ├── main.go
    └── vendor
        ├── github.com
        │   ├── gin-contrib
        │   ├── gin-gonic
        │   ├── golang
        │   ├── mattn
        │   └── ugorji
        ├── golang.org
        │   └── x
        └── gopkg.in
            ├── go-playground
            └── yaml.v2
    

    项目目录 $GOPATH/src/projectname/.

    Getting Started

    install / uninstall

    brew install dep
    brew uninstall dep
    # /usr/local/bin/dep
    windows
    # 推荐 go get 安装
    go get -u github.com/golang/dep/cmd/dep
    # $GOPATH/bin/dep.exe
    Arch linux
    pacman -S dep
    # 删除 pacman -R dep
    二进制安装
    curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
    # $GOPATH/bin/dep
    # 删除 > rm $GOPATH/bin/dep
    源码安装
    go get -d -u github.com/golang/dep
    cd $(go env GOPATH)/src/github.com/golang/dep
    DEP_LATEST=$(git describe --abbrev=0 --tags)
    git checkout $DEP_LATEST
    go install -ldflags="-X main.version=$DEP_LATEST" ./cmd/dep
    git checkout master
    

    推荐安装方式为 各系统的快捷安装,最方便且不容易出错, 如果想使用最新/指定版本,推荐源码安装

    初始化项目
    推荐使用上述第二种目录结构

    mkdir $GOPATH/src/example
    cd $GOPATH/src/example
    dep init
    # 生成 vendor/ 目录下 Gopkg.toml Gopkg.lock
    

    使用流程

    Usage
    Dep is a tool for managing dependencies for Go projects
    
    Usage: "dep [command]"
    
    Commands:
      init     Set up a new Go project, or migrate an existing one
      status   Report the status of the project's dependencies
      ensure   Ensure a dependency is safely vendored in the project
      prune    Pruning is now performed automatically by dep ensure.
      version  Show the dep version information
    
    Examples:
      dep init                               set up a new project
      dep ensure                             install the project's dependencies
      dep ensure -update                     update the locked versions of all dependencies
      dep ensure -add github.com/pkg/errors  add a dependency to the project
    
    Use "dep help [command]" for more information about a command.
    

    获取依赖策略

    • 获取最新TAG的依赖包
      dep ensure -add github.com/gin-gonic/gin

    • 获取指定分支的依赖包
      dep ensure -add github.com/gin-gonic/gin@master

    • 获取指定TAG的依赖包
      dep ensure -add github.com/gin-gonic/gin@V1.2

    • 获取指定TAG以上的依赖包
      dep ensure -add github.com/gin-gonic/gin@^V1.2

    • 获取依赖包的 子包
      dep ensure -add github.com/prometheus/client_golang/prometheus/push

    • 获取两个子包的情况
      dep ensure -add github.com/prometheus/client_golang/prometheus/push github.com/prometheus/client_golang/prometheus/promhttp

    • 获取过程:根据命令先判断本地是否有缓存(缓存地址:$GOPATH/src/dep),存在则直接使用缓存,不存在则,先获取 git 版本/分支/tag 根据命令找到对应的版本下载。

    FQAs

    • 当拉取过程中如果出现 timeout 则请自备梯子.
    • 当拉取出现未知的错误,可以先手动删除 缓存 在尝试一次
    • 当出现 *build.NoGoError 错误,可能是 build 时当前依赖包并没有 main 函数,这种情况一般是需要拉取依赖包的子包
    • 当已存在的项目 dep init 会遍历当前项目的依赖包,并下载,所以时间会很久

    转自

    https://studygolang.com/articles/13990/comment/18351

  • 相关阅读:
    Zabbix 管理界面中文出现乱码解决方法
    zabbix应用监控实践
    linux系统基础优化
    linux下创建软链--laravel软链
    php使用webservice调用C#服务端/调用PHP服务端
    php+ajax远程加载避免重复提交
    date
    函数类型
    DOM及其扩展
    字符串的截取方法
  • 原文地址:https://www.cnblogs.com/radio/p/10522359.html
Copyright © 2011-2022 走看看