Repository: nomad-software/vend
Branch: master
Commit: a1ea6c775ac2
Files: 10
Total size: 10.9 KB
Directory structure:
gitextract_7qwgw9ce/
├── LICENSE
├── README.md
├── cli/
│ ├── cli.go
│ └── cmd.go
├── file/
│ ├── dep.go
│ ├── file.go
│ └── mod.go
├── go.mod
├── main.go
└── output/
└── output.go
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Gary Willoughby
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Vend
**A small command line utility for fully vendoring module dependencies**
---
## Why?
[Because Google have a different idea of what vendoring means than the rest
of us.](https://github.com/golang/go/issues/26366) If you use the built-in
`go mod vendor` command, it will only cherry pick certain files for inclusion
in the vendor folder. This can cause problems when using
[Cgo](https://blog.golang.org/c-go-cgo) because it [ignores C files that are
not in the package
directory](https://github.com/golang/go/issues/26366#issuecomment-405683150).
Tests and examples for dependencies are ignored too.
This tool copies the entire dependency tree into the vendor folder like every
other package manager does and how every sane developer would expect it to
work. It can be used safely in the `$GOPATH` or elsewhere.
This package expects that the new [module
system](https://github.com/golang/go/wiki/Modules) [introduced in
v1.11](https://golang.org/doc/go1.11) is being used.
## What does it do?
This tool fully copies all files from your project's imported dependencies
into the `vendor` folder. This allows you to:
1. Always have access to _all_ files in your dependencies, even if they go offline
2. Always be able to build your project on a disconnected computer
3. Always be able to run the tests or benchmarks for all your dependencies
## Supported Go versions
* v1.11+
## Install
```
$ go get github.com/nomad-software/vend
```
## Usage
```
$ cd $GOPATH/mypackage
$ vend
```
## Help
Run the following command for help.
```
$ vend -help
```
================================================
FILE: cli/cli.go
================================================
package cli
import (
"flag"
"fmt"
)
// Options contains CLI arguments passed to the program.
type Options struct {
Help bool
PkgOnly bool
}
// ParseOptions parses the command line options and returns a struct filled with
// the relevant options.
func ParseOptions() Options {
var opt Options
flag.BoolVar(&opt.Help, "help", false, "Show help.")
flag.Parse()
return opt
}
// PrintUsage prints the usage of this tool.
func (opt *Options) PrintUsage() {
const banner string = ` _
__ _____ _ __ __| |
\ \ / / _ \ '_ \ / _' |
\ V / __/ | | | (_| |
\_/ \___|_| |_|\__,_|
`
fmt.Println(banner)
fmt.Printf("A small command line utility for fully vendoring module dependencies\n\n")
flag.Usage()
}
================================================
FILE: cli/cmd.go
================================================
package cli
import (
"os"
"os/exec"
"github.com/nomad-software/vend/output"
)
// UpdateModule makes sure the module is updated ready to vendor the
// dependencies.
func UpdateModule() {
var commands = []string{"tidy", "download", "vendor"}
for _, command := range commands {
cmd := exec.Command("go", "mod", command)
cmd.Env = buildEnv()
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
output.OnError(err, command)
}
}
// ReadModJSON reads the module file and returns a Json string.
func ReadModJSON() string {
cmd := exec.Command("go", "mod", "edit", "-json")
cmd.Env = buildEnv()
cmd.Stderr = os.Stderr
b, err := cmd.Output()
output.OnError(err, "Error running 'go mod edit'")
return string(b)
}
// ReadDownloadJSON reads dependency information and returns a Json string.
func ReadDownloadJSON() string {
cmd := exec.Command("go", "mod", "download", "-json")
cmd.Env = buildEnv()
cmd.Stderr = os.Stderr
b, err := cmd.Output()
output.OnError(err, "Error running 'go mod download'")
return string(b)
}
// BuildEnv creates the environment in which to run the commands.
func buildEnv() []string {
env := os.Environ()
env = append(env, "GO111MODULE=on")
return env
}
================================================
FILE: file/dep.go
================================================
package file
import (
"encoding/json"
"io"
"strings"
"github.com/nomad-software/vend/output"
)
// ParseDownloadJSON parses the dependency file into a data structure.
func ParseDownloadJSON(raw string) []Dep {
decoder := json.NewDecoder(strings.NewReader(raw))
data := make([]Dep, 0, 10)
for {
var dep Dep
err := decoder.Decode(&dep)
if err != nil {
if err == io.EOF {
break
}
output.OnError(err, "Error decoding dependency json")
}
data = append(data, dep)
}
return data
}
// Dep represents parsed dependency json data.
type Dep struct {
Path string
Version string
Error string
Info string
GoMod string
Zip string
Dir string
Sum string
GoModSum string
}
================================================
FILE: file/file.go
================================================
package file
import (
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"github.com/nomad-software/vend/cli"
"github.com/nomad-software/vend/output"
)
// VendorDir represents a vendor directory.
type VendorDir struct {
basePath string
modFileContent []byte
mod GoMod
deps []Dep
}
// InitVendorDir creates a new vendor directory.
func InitVendorDir() VendorDir {
wd, err := os.Getwd()
output.OnError(err, "Error getting the current directory")
v := VendorDir{
basePath: path.Join(wd, "vendor"),
mod: ParseModJSON(cli.ReadModJSON()),
deps: ParseDownloadJSON(cli.ReadDownloadJSON()),
}
if !v.exists(v.basePath) {
output.Fatal("vend: no dependencies to vendor")
}
return v
}
// CopyDependencies copies remote module level dependencies transitively.
func (v *VendorDir) CopyDependencies() {
v.clear()
for _, d := range v.deps {
fmt.Printf("vend: copying %s (%s)\n", d.Path, d.Version)
v.copy(d.Dir, v.vendPath(d.Path))
}
for _, r := range v.mod.Replace {
if r.Old.Path != r.New.Path {
fmt.Printf("vend: replacing %s with %s\n", r.Old.Path, r.New.Path)
newPath := v.vendPath(r.New.Path)
oldPath := v.vendPath(r.Old.Path)
// If the directory is in the vendor folder it was copied from the
// module cache so we can just rename it. Otherwise it's a local
// directory located somewhere else that needs copying in.
if v.exists(newPath) {
v.copy(newPath, oldPath)
v.remove(newPath)
} else {
v.copy(r.New.Path, oldPath)
}
}
}
}
// exists checks if a file exists.
func (v *VendorDir) exists(file string) bool {
_, err := os.Stat(file)
return !os.IsNotExist(err)
}
// remove removes a path.
func (v *VendorDir) remove(p string) {
err := os.RemoveAll(p)
output.OnError(err, "Error removing path")
}
// vendPath creates a vendor directory path.
func (v *VendorDir) vendPath(p string) string {
return path.Join(v.basePath, p)
}
// copyModFile internally copies and saves the modules.txt file.
func (v *VendorDir) copyModFile() {
var err error
v.modFileContent, err = ioutil.ReadFile(v.vendPath("modules.txt"))
output.OnError(err, "Error reading modules.txt")
}
// writeModFile writes the modules.txt file into the vendor directory.
func (v *VendorDir) writeModFile() {
err := ioutil.WriteFile(v.vendPath("modules.txt"), v.modFileContent, 0644)
output.OnError(err, "Error saving modules.txt")
}
// clear removes all dependencies from the vendor directory.
func (v *VendorDir) clear() {
v.copyModFile()
v.remove(v.basePath)
err := os.MkdirAll(v.basePath, 0755)
output.OnError(err, "Error creating vendor directory")
v.writeModFile()
}
// copy will copy files and directories.
func (v *VendorDir) copy(src string, dest string) {
info, err := os.Lstat(src)
output.OnError(err, "Error getting information about source")
if info.Mode()&os.ModeSymlink != 0 {
return // Completely ignore symlinks.
}
if info.IsDir() {
v.copyDirectory(src, dest)
} else {
v.copyFile(src, dest)
}
}
// copyDirectory will copy directories.
func (v *VendorDir) copyDirectory(src string, dest string) {
err := os.MkdirAll(dest, 0755)
output.OnError(err, "Error creating directories")
contents, err := ioutil.ReadDir(src)
output.OnError(err, "Error reading source directory")
for _, content := range contents {
s := filepath.Join(src, content.Name())
d := filepath.Join(dest, content.Name())
v.copy(s, d)
}
}
// copyFile will copy files.
func (v *VendorDir) copyFile(src string, dest string) {
err := os.MkdirAll(filepath.Dir(dest), 0755)
output.OnError(err, "Error creating directories")
d, err := os.Create(dest)
output.OnError(err, "Error creating file")
defer d.Close()
s, err := os.Open(src)
output.OnError(err, "Error opening file")
defer s.Close()
_, err = io.Copy(d, s)
output.OnError(err, "Error copying file")
}
================================================
FILE: file/mod.go
================================================
package file
import (
"encoding/json"
"github.com/nomad-software/vend/output"
)
// ParseModJSON parses the mode file into a data structure.
func ParseModJSON(raw string) GoMod {
data := GoMod{
Module: Module{},
Require: make([]Require, 0, 10),
Exclude: make([]Module, 0, 10),
Replace: make([]Replace, 0, 10),
Retract: make([]Retract, 0, 10),
}
err := json.Unmarshal([]byte(raw), &data)
output.OnError(err, "Error parsing module json")
return data
}
// GoMod represents parsed module json data.
type GoMod struct {
Module Module
Go string
Require []Require
Exclude []Module
Replace []Replace
Retract []Retract
}
// Module represents parsed module json data.
type Module struct {
Path string
Version string
}
// Require represents parsed module json data.
type Require struct {
Path string
Version string
Indirect bool
}
// Replace represents parsed module json data.
type Replace struct {
Old Module
New Module
}
// Retract represents dependency version that are retracted.
type Retract struct {
Low string
High string
Rationale string
}
================================================
FILE: go.mod
================================================
module github.com/nomad-software/vend
go 1.16
================================================
FILE: main.go
================================================
package main
import (
"github.com/nomad-software/vend/cli"
"github.com/nomad-software/vend/file"
)
func main() {
options := cli.ParseOptions()
if options.Help {
options.PrintUsage()
} else {
cli.UpdateModule()
dir := file.InitVendorDir()
dir.CopyDependencies()
}
}
================================================
FILE: output/output.go
================================================
package output
import (
"fmt"
"os"
)
// OnError prints an error if err is not nil and exits the program.
func OnError(err error, text string) {
if err != nil {
Fatal("%s:, %s", text, err.Error())
}
}
// Fatal prints an error and exits the program.
func Fatal(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, format+"\n", args...)
os.Exit(1)
}
// Info prints information.
func Info(format string, args ...interface{}) {
fmt.Printf(format+"\n", args...)
}
gitextract_7qwgw9ce/
├── LICENSE
├── README.md
├── cli/
│ ├── cli.go
│ └── cmd.go
├── file/
│ ├── dep.go
│ ├── file.go
│ └── mod.go
├── go.mod
├── main.go
└── output/
└── output.go
SYMBOL INDEX (31 symbols across 7 files)
FILE: cli/cli.go
type Options (line 9) | type Options struct
method PrintUsage (line 26) | func (opt *Options) PrintUsage() {
function ParseOptions (line 16) | func ParseOptions() Options {
FILE: cli/cmd.go
function UpdateModule (line 12) | func UpdateModule() {
function ReadModJSON (line 28) | func ReadModJSON() string {
function ReadDownloadJSON (line 41) | func ReadDownloadJSON() string {
function buildEnv (line 54) | func buildEnv() []string {
FILE: file/dep.go
function ParseDownloadJSON (line 12) | func ParseDownloadJSON(raw string) []Dep {
type Dep (line 34) | type Dep struct
FILE: file/file.go
type VendorDir (line 16) | type VendorDir struct
method CopyDependencies (line 42) | func (v *VendorDir) CopyDependencies() {
method exists (line 69) | func (v *VendorDir) exists(file string) bool {
method remove (line 75) | func (v *VendorDir) remove(p string) {
method vendPath (line 81) | func (v *VendorDir) vendPath(p string) string {
method copyModFile (line 86) | func (v *VendorDir) copyModFile() {
method writeModFile (line 93) | func (v *VendorDir) writeModFile() {
method clear (line 99) | func (v *VendorDir) clear() {
method copy (line 110) | func (v *VendorDir) copy(src string, dest string) {
method copyDirectory (line 126) | func (v *VendorDir) copyDirectory(src string, dest string) {
method copyFile (line 141) | func (v *VendorDir) copyFile(src string, dest string) {
function InitVendorDir (line 24) | func InitVendorDir() VendorDir {
FILE: file/mod.go
function ParseModJSON (line 10) | func ParseModJSON(raw string) GoMod {
type GoMod (line 26) | type GoMod struct
type Module (line 36) | type Module struct
type Require (line 42) | type Require struct
type Replace (line 49) | type Replace struct
type Retract (line 55) | type Retract struct
FILE: main.go
function main (line 8) | func main() {
FILE: output/output.go
function OnError (line 9) | func OnError(err error, text string) {
function Fatal (line 16) | func Fatal(format string, args ...interface{}) {
function Info (line 22) | func Info(format string, args ...interface{}) {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (12K chars).
[
{
"path": "LICENSE",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2018 Gary Willoughby\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "README.md",
"chars": 1567,
"preview": "# Vend\n\n**A small command line utility for fully vendoring module dependencies**\n\n---\n\n## Why?\n\n[Because Google have a d"
},
{
"path": "cli/cli.go",
"chars": 741,
"preview": "package cli\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n)\n\n// Options contains CLI arguments passed to the program.\ntype Options struct {\n\t"
},
{
"path": "cli/cmd.go",
"chars": 1227,
"preview": "package cli\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\n\t\"github.com/nomad-software/vend/output\"\n)\n\n// UpdateModule makes sure the modul"
},
{
"path": "file/dep.go",
"chars": 733,
"preview": "package file\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/nomad-software/vend/output\"\n)\n\n// ParseDownloadJS"
},
{
"path": "file/file.go",
"chars": 3869,
"preview": "package file\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\n\t\"github.com/nomad-software/vend/cli\"\n\t"
},
{
"path": "file/mod.go",
"chars": 1106,
"preview": "package file\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/nomad-software/vend/output\"\n)\n\n// ParseModJSON parses the mode fil"
},
{
"path": "go.mod",
"chars": 47,
"preview": "module github.com/nomad-software/vend\n\ngo 1.16\n"
},
{
"path": "main.go",
"chars": 285,
"preview": "package main\n\nimport (\n\t\"github.com/nomad-software/vend/cli\"\n\t\"github.com/nomad-software/vend/file\"\n)\n\nfunc main() {\n\n\to"
},
{
"path": "output/output.go",
"chars": 479,
"preview": "package output\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\n// OnError prints an error if err is not nil and exits the program.\nfunc OnErro"
}
]
About this extraction
This page contains the full source code of the nomad-software/vend GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (10.9 KB), approximately 3.0k tokens, and a symbol index with 31 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.