β

Golang 项目依赖管理

奇虎360-addops 564 阅读

Golang 项目依赖管理

golang官方提供了包管理工具 go get ,它将下载的第三方包放到GOPATH的src目录下。项目通常由很多来源不同的包构成,它们都从GOPATH或标准库中导入。

为了项目可以正常使用这些包,我们可能需要这么做:

虽然项目间会有所不同,但大方向上是这样的。

Vendor

Vendor 是什么?

Go 1.5发布了一个新的发现包的方法,不需要在代码或编译器中做任何修改。如果项目中包含一个叫vendor的目录,go将会从这个目录搜索依赖的包,这些包会在标准库之前被找到。

Go 1.5开启这个功能需要修改环境变量 GO15VENDOREXPERIMENT=1, 1.6之后默认已开启。

比如导入了这些包

import (
    "bytes"
    "flag"
    "io"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "os"
    "path"
    "path/filepath"
    "strings"
    "sync"
    "time"

    "github.com/andybalholm/cascadia"
    "github.com/tdewolff/parse/css"
    "golang.org/x/net/html"
)
...

我们看下vendor目录

$ tree
.
├── css_test.go
├── main.go
└── vendor
    ├── github.com
    │   ├── andybalholm
    │   │   └── cascadia
    │   │       ├── LICENSE
    │   │       ├── parser.go
    │   │       ├── README.md
    │   │       └── selector.go
    │   └── tdewolff
    │       ├── buffer
    │       │   ├── buffer.go
    │       │   ├── lexer.go
    │       │   ├── LICENSE.md
    │       │   ├── reader.go
    │       │   ├── README.md
    │       │   ├── shifter.go
    │       │   └── writer.go
    │       └── parse
    │           ├── common.go
    │           ├── css
    │           │   ├── hash.go
    │           │   ├── lex.go
    │           │   ├── parse.go
    │           │   ├── README.md
    │           │   └── util.go
    │           ├── LICENSE.md
    │           ├── README.md
    │           └── util.go
    ├── golang.org
    │   └── x
    │       └── net
    │           └── html
    │               ├── atom
    │               │   ├── atom.go
    │               │   ├── gen.go
    │               │   └── table.go
    │               ├── const.go
    │               ├── doc.go
    │               ├── doctype.go
    │               ├── entity.go
    │               ├── escape.go
    │               ├── foreign.go
    │               ├── node.go
    │               ├── parse.go
    │               ├── render.go
    │               └── token.go

How to use the vendor folder

使用方式有很多种,大多是第三方软件,常用的有godep、glide,官方也刚推出dep。之前有用过glide,功能够用。但今天我们主要说说官方的dep,原生的在兼容上应该会越来越好,最近一些新的项目也在尝试使用dep。

Dep

dep is a prototype dependency management tool for Go. It requires Go 1.9 or newer to compile. dep is safe for production use.

Install

dep is the official experiment, but not yet the official tool.

在最新的1.1.10版本中仍然没加入,目前还是需要自己来安装

go get -u github.com/golang/dep/cmd/dep

Purpose

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.

New project

接下来咱就结合项目看看具体的使用方法。在此之前我们需要先给项目设置根目录,一般情况都使用\$GOPATH/src

dep init

在项目下执行 dep init

$ dep init
$ ls
Gopkg.toml Gopkg.lock vendor/

dep init有个-gopath选项,会优先从本地GOPATH导入所需要的包,能在一定程度上加快速度。

发现2个新文件,Gopkg.lock、Gopkg.toml,它们和vendor有什么关系?

Gopkg.toml 是我们主要编辑的文件,它包含了dep的几种类型规则

Dependency rules

gopkg.toml中的大多数规则声明来自 [[constraint]] [[override]] 。它们设置的参数完全相同,但dep会用不同方式解释它们。

[[constraint]]
  # Required: the root import path of the project being constrained.
  name = "github.com/user/project"
  # Recommended: the version constraint to enforce for the project.
  # Note that only one of "branch", "version" or "revision" can be specified.
  version = "1.0.0"
  branch = "master"
  revision = "abc123"

  # Optional: an alternate location (URL or import path) for the project's source.
  source = "https://github.com/myfork/package.git"

  # Optional: metadata about the constraint or override that could be used by other independent systems
  [metadata]
  key1 = "value that convey data to other systems"
  system1-data = "value that is used by a system"
  system2-data = "value that is used by another system"

这里特别需要注意,"branch", "version" or "revision" 只能写一个

Package graph rules

dep会解析代码中import语句,将这些导入的包最终形成一个图表。 required、ignored 决定导入或删除哪些包

如果项目依赖某个包,但report又没声明,可以使用required

metadata、prune 一般用的少,大家感觉可以看下 官方的介绍

dep ensure

dep ensure 是dep最主要的命令,它确保整个项目是同步的。

dep基于report语句生成Gopkg.toml文件,通过ensure同步Gopkg.lock。并确保最终vendor目录下的内容就是我们想要的。

Adding a new dependency

$ dep ensure -add github.com/sumaig/glog

如果成功,它会更新Gopkg.lock文件和vendor目录,并选择最佳版本写入Gopkg.toml。但你也可能会遇到下面的错误:

"github.com/sumaig/glog" is not imported by your project, and has been temporarily added to Gopkg.lock and vendor/.
If you run "dep ensure" again before actually importing it, it will disappear from Gopkg.lock and vendor/.

这是因为我们没有在import声明这个包

Updating dependencies

更新指定包依赖

dep ensure -update github.com/sumaig/glog

更新所有依赖

dep ensure -update

遇到以下两种情况,我们也应该运行 dep ensure 确保项目是同步的

Migrating to Dep

大多数项目直接运行 dep init 就可以完成迁移,如果之前用的是glide,dep会自动从glide.yml、glide.lock中读取项目依赖,这个也很方便。

作者:奇虎360-addops
应用运维|运维开发|opsdev|addops|虚拟化|openstack|docker|容器化|k8s|智能运维
原文地址:Golang 项目依赖管理, 感谢原作者分享。

发表评论