I started to learn the language Golang in 2018. At that time, vendor was widely used in package management. During project development, we only need to perform vendor initialization (govendor Init) in the root directory of the project, and the file directory vendor/ for package management will be produced in the root directory of the project. There is a vendor.json file in this directory, which is similar to the godep tool for describing the version of the file.

Here is an example of this file

{ "comment": "", "ignore": "", "package": [ { "checksumSHA1": "qL4naKgOOJE2hXxKKYu+5W2ULHU=", "path": "github.com/certifi/gocertifi", "revision": "0944d244cd40db6fa14fa14fc8c53b29f0ad66e4", "revisionTime": "2019-10-21T19:10:39Z" }, ...... ] , "rootPath": "/path/to/project" }Copy the code

Of course, when the project is created, the contents of the package list are not available before the package is imported. When a package is introduced during project development, simply execute the govendor add +external command to add the referenced package to the package list.

In addition, the current version of the package is placed in the vendor directory, as shown in the example below

In the project code management system, we need to manage vendor files uniformly.

Recently in the new project, we introduced the package management tool mod from Golang 1.11 1.12.

This is different from the vendor. Let’s look at how mods manage packages.

A module is a collection of Go packages stored in a file tree, with the go.mod file in its root directory. The go.mod file defines the module path for the module (which is also the import path for the root directory) and its dependency requirements, which are the other modules needed for a successful build. Each dependency requirement is written as a module path and a specific semantic version.

Take a look at a simple example

Let’s take the greeter example from Micro and write a simple hello World in client-server mode.

First take a look at the greeter.proto file

syntax = "proto3";

service Greeter {
        rpc Hello(HelloRequest) returns (HelloResponse) {}
}

message HelloRequest {
        string name = 1;
}

message HelloResponse {
        string greeting = 2;
}
Copy the code

The function of the whole project is very simple, so let’s see how to manage packages through mod

First, we initialize with go mod init /path/to/project. This will produce a go.mod file in the root directory of the project

The module modtest go 1.13Copy the code

We produce the corresponding GO code via Protoc.

protoc  --micro_out=. --go_out=. ./greeter/greeter.proto 
Copy the code

Then implement a simple server

➜ server more server.go package main import ("context" "FMT" proto "modtest/greeter" micro" github.com/micro/go-micro" ) type Greeter struct{} func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error { rsp.Greeting = "Hello " + req.Name return nil } func main() { // Create a new service.  Optionally include some options here. service := micro.NewService( micro.Name("greeter"), ) // Init will parse the command line flags. service.Init() // Register handler proto.RegisterGreeterHandler(service.Server(), new(Greeter)) // Run the server if err := service.Run(); err ! = nil { fmt.Println(err) } }Copy the code

After running the server, implement a client to communicate with the server

➜  client more client.go 
package main

import (
        "context"
        "fmt"

        proto "modtest/greeter"

        micro "github.com/micro/go-micro"
)

func main() {
        // Create a new service. Optionally include some options here.
        service := micro.NewService(micro.Name("greeter.client"))
        service.Init()

        // Create new greeter client
        greeter := proto.NewGreeterService("greeter", service.Client())

        // Call the greeter
        rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "John"})
        if err != nil {
                fmt.Println(err)
        }

        // Print response
        fmt.Println(rsp.Greeting)
}
Copy the code

Now let’s look at the management of its dependency packages

➜  modtest more go.mod 
module modtest

go 1.13

require github.com/micro/go-micro v1.18.0
Copy the code

Automatic introduction of the Go-Micro package. And the version is specified. At the same time, you’ll notice that in the project directory, there’s a file called go.sum. Take some of it and look at it

➜ modtest more go.sum cloud.google.com/go v0.26.0/go.mod H1 :aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod H1 :aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod H1:990 n + gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU = contrib. Go. Opencensus. IO/exporter/ocagent v0.4.12 / go mod H1:450 aplntsr6frvc3ctrqyosudstrb9un7sox2k/cka = 9 github.com/Azure/azure-sdk-for-go v32.4.0 + incompatible. / go to the mod H1:9 xxnku + eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc = github.com/Azure/go-ansiterm v0.0.0-20170929234023 - d6e3b3328b78 / go. Mod H1: LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8 = github.com/Azure/go-autorest/autorest v0.1.0 / go mod H1: AKyIcETwSUFxIcs / + kwCtlEYGUVd7FPNb2slmg Wnq/C = github.com/Azure/go-autorest/autorest v0.5.0 / go mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=Copy the code

These are cryptographic hashes for software versions. Ensure that later downloads of these modules are the same bits retrieved during the first download to ensure that the modules on which your project depends do not change accidentally due to malicious, accidental, or other reasons.

Both go.mod and go.sum should be committed to code version control.

So what if we upgrade dependencies?

$go list -m all github.com/coreos/bbolt v1.3.3 github.com/coreos/etcd v3.3.17+incompatible github.com/coreos/go-semver V0.3.0 github.com/coreos/go-systemd v0.0.0-20190719114852 - fd7a80b32e1f github.com/coreos/pkg Ea9e2e55f v0.0.0-20180928190104-399Copy the code

Did you notice that some versions are specified directly, while others are given directly as V0.0.0

A given release is divided into three parts: body, minor release, and patch, such as V1.3.3, major release 1, minor release 3, and patch 3. This v0.0.0 is the unmarked version. In other words, we can upgrade this version to the latest version without any impact, and the project can still run normally.

➜  modtest go get github.com/coreos/pkg
go: finding github.com/coreos/pkg latest
Copy the code

Let’s run our project

Go run server.go error

➜ server go run for server go # github.com/coreos/etcd/clientv3/balancer/resolver/endpoint.. /.. /.. /.. / pkg/mod/github.com/coreos/[email protected]+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:114:78: undefined: resolver.BuildOption .. /.. /.. /.. / pkg/mod/github.com/coreos/[email protected]+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:182:31: undefined: resolver.ResolveNowOption # github.com/coreos/etcd/clientv3/balancer/picker .. /.. /.. /.. / pkg/mod/github.com/coreos/[email protected]+incompatible/clientv3/balancer/picker/err.go:37:44: undefined: balancer.PickOptions .. /.. /.. /.. / pkg/mod/github.com/coreos/[email protected]+incompatible/clientv3/balancer/picker/roundrobin_balanced.go:55:54: undefined: balancer.PickOptionsCopy the code

Check out our go.mod

➜ modtest more go. Mod module modtest go 1.13 the require (github.com/golang/protobuf v1.4.1 github.com/micro/go-micro V1.18.0 google.golang.org/protobuf v1.25.0)Copy the code

Software versions are incompatible. So how do we solve this problem? We want to see what’s valuable in the error message, and indeed everyone can see incompatibilities, who’s incompatibilities with whom, and how do we solve incompatibilities. Now let’s look at etcd of the codebase 3.3.17 library version, this version of its associated code can go with us. The mod packages have management namely google.golang.org/protobuf, we go. Version is v1.25.0 mod.

whileEtcd 3.3.17The required version isv1.23.0Version of thegrpc. Looking at thev1.23.0Version of thegrpc

So versions that resolve such conflicts will either upgrade etCD or degrade Protobuf. The solution for ease of use and thinking is to update the protobuf version directly.

After the protobuf version in go.mod is updated to v1.23.0, the server is started successfully

1.13 the require module modtest go (github.com/golang/protobuf v1.4.1 github.com/micro/go-micro v1.18.0 Google.golang.org/protobuf v1.23.0)Copy the code

Finally, many unnecessary versions may have been introduced during debugging. Go.mod is confusing and can be passed at this time

$go mod tidy
Copy the code

Manage update packages.

What do you think about modding software package dependency management and vendor? Which one do you prefer? Welcome to join the discussion