1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
package testjson
import (
"bytes"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)
// RelativePackagePath attempts to remove a common prefix from a package path.
// The common prefix is determined either by looking at the GOPATH or reading
// the package value from go.mod file.
// If the pkgpath does not match the common prefix it will be returned
// unmodified.
// If the pkgpath matches the common prefix exactly then '.' will be returned.
func RelativePackagePath(pkgpath string) string {
if pkgpath == pkgPathPrefix {
return "."
}
return strings.TrimPrefix(pkgpath, pkgPathPrefix+"/")
}
func getPkgPathPrefix() string {
cwd, _ := os.Getwd()
if isGoModuleEnabled() {
prefix := getPkgPathPrefixFromGoModule(cwd)
if prefix != "" {
return prefix
}
}
return getPkgPathPrefixGoPath(cwd)
}
func isGoModuleEnabled() bool {
version := runtime.Version()
if strings.HasPrefix(version, "go1.10") {
return false
}
// Go modules may not be enabled if env var is unset, or set to auto, however
// we can always fall back to using GOPATH as the prefix if a go.mod is not
// found.
return os.Getenv("GO111MODULE") != "off"
}
// TODO: might not work on windows
func getPkgPathPrefixGoPath(cwd string) string {
gopaths := strings.Split(build.Default.GOPATH, string(filepath.ListSeparator))
for _, gopath := range gopaths {
gosrcpath := gopath + "/src/"
if strings.HasPrefix(cwd, gosrcpath) {
return strings.TrimPrefix(cwd, gosrcpath)
}
}
return ""
}
func getPkgPathPrefixFromGoModule(cwd string) string {
filename := goModuleFilePath(cwd)
if filename == "" {
return ""
}
raw, err := ioutil.ReadFile(filename)
if err != nil {
// TODO: log.Warn
return ""
}
return pkgPathFromGoModuleFile(raw)
}
var (
slashSlash = []byte("//")
moduleStr = []byte("module")
)
// Copy of ModulePath from golang.org/src/cmd/go/internal/modfile/read.go
func pkgPathFromGoModuleFile(mod []byte) string {
for len(mod) > 0 {
line := mod
mod = nil
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, mod = line[:i], line[i+1:]
}
if i := bytes.Index(line, slashSlash); i >= 0 {
line = line[:i]
}
line = bytes.TrimSpace(line)
if !bytes.HasPrefix(line, moduleStr) {
continue
}
line = line[len(moduleStr):]
n := len(line)
line = bytes.TrimSpace(line)
if len(line) == n || len(line) == 0 {
continue
}
if line[0] == '"' || line[0] == '`' {
p, err := strconv.Unquote(string(line))
if err != nil {
return "" // malformed quoted string or multi-line module path
}
return p
}
return string(line)
}
return "" // missing module path
}
// A rough re-implementation of FindModuleRoot from
// golang.org/src/cmd/go/internal/modload/init.go
func goModuleFilePath(cwd string) string {
dir := filepath.Clean(cwd)
for {
path := filepath.Join(dir, "go.mod")
if _, err := os.Stat(path); err == nil {
return path
}
parent := filepath.Dir(dir)
if parent == dir {
return ""
}
dir = parent
}
}
var pkgPathPrefix = getPkgPathPrefix()
|