142 lines
3.0 KiB
Go
142 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"go/build"
|
|
"io"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"regexp"
|
|
|
|
"path/filepath"
|
|
|
|
. "github.com/dave/jennifer/jen"
|
|
)
|
|
|
|
func hints(w io.Writer, pkg, name, goListPath, filter string, standard, novendor bool) error {
|
|
|
|
// notest
|
|
|
|
file := NewFile(pkg)
|
|
|
|
file.HeaderComment("This file is generated - do not edit.")
|
|
file.Line()
|
|
|
|
packages, err := getPackages(goListPath, filter, standard, novendor)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
/*
|
|
// <name> contains package name hints
|
|
var <name> = map[string]string{
|
|
...
|
|
}
|
|
*/
|
|
file.Commentf("%s contains package name hints", name)
|
|
file.Var().Id(name).Op("=").Map(String()).String().Values(DictFunc(func(d Dict) {
|
|
for path, name := range packages {
|
|
d[Lit(path)] = Lit(name)
|
|
}
|
|
}))
|
|
|
|
return file.Render(w)
|
|
}
|
|
|
|
func getPackages(goListPath, filter string, standard, novendor bool) (map[string]string, error) {
|
|
|
|
// notest
|
|
|
|
r, err := regexp.Compile(filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cmd := exec.Command("go", "list", "-e", "-f", "{{ .Standard }} {{ .ImportPath }} {{ .Name }}", goListPath)
|
|
cmd.Env = []string{
|
|
fmt.Sprintf("GOPATH=%s", build.Default.GOPATH),
|
|
fmt.Sprintf("GOROOT=%s", build.Default.GOROOT),
|
|
}
|
|
if standard {
|
|
cmd.Dir = filepath.Join(build.Default.GOROOT, "src")
|
|
} else {
|
|
cmd.Dir = filepath.Join(build.Default.GOPATH, "src")
|
|
}
|
|
b, err := cmd.Output()
|
|
if err != nil {
|
|
if x, ok := err.(*exec.ExitError); ok {
|
|
return nil, fmt.Errorf("go list command returned an error - %s: %s", err.Error(), string(x.Stderr))
|
|
}
|
|
return nil, fmt.Errorf("go list command returned an error: %s", err.Error())
|
|
}
|
|
all := strings.Split(strings.TrimSpace(string(b)), "\n")
|
|
|
|
packages := map[string]string{}
|
|
for _, j := range all {
|
|
|
|
parts := strings.Split(j, " ")
|
|
|
|
isStandard := parts[0] == "true"
|
|
if isStandard != standard {
|
|
continue
|
|
}
|
|
|
|
path := parts[1]
|
|
name := parts[2]
|
|
|
|
if novendor && hasVendor(path) {
|
|
continue
|
|
}
|
|
|
|
if name == "main" {
|
|
continue
|
|
}
|
|
|
|
if !r.MatchString(path) {
|
|
continue
|
|
}
|
|
|
|
path = unvendorPath(path)
|
|
|
|
if packages[path] != "" {
|
|
continue
|
|
}
|
|
|
|
packages[path] = name
|
|
}
|
|
return packages, nil
|
|
}
|
|
|
|
func unvendorPath(path string) string {
|
|
// notest
|
|
i, ok := findVendor(path)
|
|
if !ok {
|
|
return path
|
|
}
|
|
return path[i+len("vendor/"):]
|
|
}
|
|
|
|
// FindVendor looks for the last non-terminating "vendor" path element in the given import path.
|
|
// If there isn't one, FindVendor returns ok=false.
|
|
// Otherwise, FindVendor returns ok=true and the index of the "vendor".
|
|
// Copied from cmd/go/internal/load
|
|
func findVendor(path string) (index int, ok bool) {
|
|
// notest
|
|
// Two cases, depending on internal at start of string or not.
|
|
// The order matters: we must return the index of the final element,
|
|
// because the final one is where the effective import path starts.
|
|
switch {
|
|
case strings.Contains(path, "/vendor/"):
|
|
return strings.LastIndex(path, "/vendor/") + 1, true
|
|
case strings.HasPrefix(path, "vendor/"):
|
|
return 0, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func hasVendor(path string) bool {
|
|
// notest
|
|
_, v := findVendor(path)
|
|
return v
|
|
}
|