Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the purpose of `go mod vendor` command?

Tags:

go

go-modules

The documentation says,

The go mod vendor command constructs a directory named vendor in the main module's root directory that contains copies of all packages needed to support builds and tests of packages in the main module. Packages that are only imported by tests of packages outside the main module are not included.

golangbyexample says:

You can also check in the vendor directory to your VCS (Version Control System). This becomes useful in sense that none of the dependency needs to be downloaded at run time as it is already present in the vendor folder checked into VCS

I think modules (go.mod,go.sum) take care of the versioning. I also think that dependencies are only downloaded when I run the program for the first time.

So, how is the command go mod vendor useful? What is its purpose or use case?

like image 709
blueray Avatar asked Jul 27 '21 12:07

blueray


People also ask

What is vendor Golang?

js land, Golang's vendor directory is basically the same as Node's node_modules . It is a directory found at the root of a Go module that stores a copy of all the code the module depends on. The vendored code is used to compile the final executable when the go build command is run.

Is Go mod necessary?

Without a go. mod file, it is not a module. A module is a collection of packages that are released, versioned, and distributed together. Modules may be downloaded directly from version control repositories or from module proxy servers.

Should I commit vendor folder Golang?

The general recommendation is no. The vendor directory (or wherever your dependencies are installed) should be added to . gitignore / svn:ignore /etc. The best practice is to then have all the developers use Composer to install the dependencies.


2 Answers

Go Modules takes care of versioning, but it doesn't necessarily take care of modules disappearing off the Internet or the Internet not being available. If a module is not available, the code cannot be built.

Go Proxy will mitigate disappearing modules to some extent by mirroring modules, but it may not do it for all modules for all time:

Why did a previously available module become unavailable in the mirror?

proxy.golang.org does not save all modules forever. There are a number of reasons for this, but one reason is if proxy.golang.org is not able to detect a suitable license. In this case, only a temporarily cached copy of the module will be made available, and may become unavailable if it is removed from the original source and becomes outdated. The checksums will still remain in the checksum database regardless of whether or not they have become unavailable in the mirror.

See more at: https://proxy.golang.org/

An alternative approach for this is to fork modules and use the Go Modules replace directive which allows redirecting an import path to another, e.g. your fork, in the go.mod file without changing your code. This approach was provided by colm.anseo.

Regarding Internet access, if you run a large server farm and need the code on multiple machines, downloading from the Internet to every machine in your farm can be inefficient and a security risk. It may be much more efficient to use go mod vendor into an internal repo and copy this around. Large companies use internal methods to deploy code to multiple servers in their data centers.

like image 77
Grokify Avatar answered Nov 14 '22 09:11

Grokify


This question gave me an idea. Sometimes I want to know how "bloated" a module is, so I wanted a way to look at the size of a module, but also any third party imports. To that end, I wrote the script below, utilizing go mod vendor:

package main

import (
   "bytes"
   "fmt"
   "io/fs"
   "os"
   "os/exec"
   "path/filepath"
   "strings"
)

func count(mod string) (int, error) {
   imp := fmt.Sprintf("package main\nimport _%q", mod)
   os.WriteFile("size.go", []byte(imp), os.ModePerm)
   exec.Command("go", "mod", "init", "size").Run()
   exec.Command("go", "mod", "vendor").Run()
   var count int
   filepath.WalkDir("vendor", func(s string, d fs.DirEntry, err error) error {
      if strings.HasSuffix(s, ".go") && !strings.HasSuffix(s, "_test.go") {
         data, err := os.ReadFile(s)
         if err != nil {
            return err
         }
         count += bytes.Count(data, []byte{'\n'})
      }
      return nil
   })
   return count, nil
}

Example:

package main

func main() {
   c, err := count("github.com/corona10/goimagehash")
   if err != nil {
      panic(err)
   }
   println(c)
}
like image 40
Zombo Avatar answered Nov 14 '22 10:11

Zombo