|
1 | 1 | package util |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "encoding/json" |
5 | 4 | "errors" |
6 | | - "io" |
7 | 5 | "io/fs" |
8 | 6 | "log" |
9 | 7 | "net/url" |
@@ -35,154 +33,6 @@ func Getenv(key string, aliases ...string) string { |
35 | 33 | return "" |
36 | 34 | } |
37 | 35 |
|
38 | | -// runGoList is a helper function for running go list with format `format` and flags `flags` on |
39 | | -// package `pkgpath`. |
40 | | -func runGoList(format string, patterns []string, flags ...string) (string, error) { |
41 | | - return runGoListWithEnv(format, patterns, nil, flags...) |
42 | | -} |
43 | | - |
44 | | -func runGoListWithEnv(format string, patterns []string, additionalEnv []string, flags ...string) (string, error) { |
45 | | - args := append([]string{"list", "-e", "-f", format}, flags...) |
46 | | - args = append(args, patterns...) |
47 | | - cmd := exec.Command("go", args...) |
48 | | - cmd.Env = append(os.Environ(), additionalEnv...) |
49 | | - out, err := cmd.Output() |
50 | | - |
51 | | - if err != nil { |
52 | | - if err, ok := err.(*exec.ExitError); ok { |
53 | | - log.Printf("Warning: go list command failed, output below:\nstdout:\n%s\nstderr:\n%s\n", out, err.Stderr) |
54 | | - } else { |
55 | | - log.Printf("Warning: Failed to run go list: %s", err.Error()) |
56 | | - } |
57 | | - return "", err |
58 | | - } |
59 | | - |
60 | | - return strings.TrimSpace(string(out)), nil |
61 | | -} |
62 | | - |
63 | | -// PkgInfo holds package directory and module directory (if any) for a package |
64 | | -type PkgInfo struct { |
65 | | - PkgDir string // the directory directly containing source code of this package |
66 | | - ModDir string // the module directory containing this package, empty if not a module |
67 | | -} |
68 | | - |
69 | | -// GetPkgsInfo gets the absolute module and package root directories for the packages matched by the |
70 | | -// patterns `patterns`. It passes to `go list` the flags specified by `flags`. If `includingDeps` |
71 | | -// is true, all dependencies will also be included. |
72 | | -func GetPkgsInfo(patterns []string, includingDeps bool, flags ...string) (map[string]PkgInfo, error) { |
73 | | - // enable module mode so that we can find a module root if it exists, even if go module support is |
74 | | - // disabled by a build |
75 | | - if includingDeps { |
76 | | - // the flag `-deps` causes all dependencies to be retrieved |
77 | | - flags = append(flags, "-deps") |
78 | | - } |
79 | | - |
80 | | - // using -json overrides -f format |
81 | | - output, err := runGoList("", patterns, append(flags, "-json")...) |
82 | | - if err != nil { |
83 | | - return nil, err |
84 | | - } |
85 | | - |
86 | | - // the output of `go list -json` is a stream of json object |
87 | | - type goListPkgInfo struct { |
88 | | - ImportPath string |
89 | | - Dir string |
90 | | - Module *struct { |
91 | | - Dir string |
92 | | - } |
93 | | - } |
94 | | - pkgInfoMapping := make(map[string]PkgInfo) |
95 | | - streamDecoder := json.NewDecoder(strings.NewReader(output)) |
96 | | - for { |
97 | | - var pkgInfo goListPkgInfo |
98 | | - decErr := streamDecoder.Decode(&pkgInfo) |
99 | | - if decErr == io.EOF { |
100 | | - break |
101 | | - } |
102 | | - if decErr != nil { |
103 | | - log.Printf("Error decoding output of go list -json: %s", err.Error()) |
104 | | - return nil, decErr |
105 | | - } |
106 | | - pkgAbsDir, err := filepath.Abs(pkgInfo.Dir) |
107 | | - if err != nil { |
108 | | - log.Printf("Unable to make package dir %s absolute: %s", pkgInfo.Dir, err.Error()) |
109 | | - } |
110 | | - var modAbsDir string |
111 | | - if pkgInfo.Module != nil { |
112 | | - modAbsDir, err = filepath.Abs(pkgInfo.Module.Dir) |
113 | | - if err != nil { |
114 | | - log.Printf("Unable to make module dir %s absolute: %s", pkgInfo.Module.Dir, err.Error()) |
115 | | - } |
116 | | - } |
117 | | - pkgInfoMapping[pkgInfo.ImportPath] = PkgInfo{ |
118 | | - PkgDir: pkgAbsDir, |
119 | | - ModDir: modAbsDir, |
120 | | - } |
121 | | - } |
122 | | - return pkgInfoMapping, nil |
123 | | -} |
124 | | - |
125 | | -// GetPkgInfo fills the package info structure for the specified package path. |
126 | | -// It passes the `go list` the flags specified by `flags`. |
127 | | -func GetPkgInfo(pkgpath string, flags ...string) PkgInfo { |
128 | | - return PkgInfo{ |
129 | | - PkgDir: GetPkgDir(pkgpath, flags...), |
130 | | - ModDir: GetModDir(pkgpath, flags...), |
131 | | - } |
132 | | -} |
133 | | - |
134 | | -// GetModDir gets the absolute directory of the module containing the package with path |
135 | | -// `pkgpath`. It passes the `go list` the flags specified by `flags`. |
136 | | -func GetModDir(pkgpath string, flags ...string) string { |
137 | | - // enable module mode so that we can find a module root if it exists, even if go module support is |
138 | | - // disabled by a build |
139 | | - mod, err := runGoListWithEnv("{{.Module}}", []string{pkgpath}, []string{"GO111MODULE=on"}, flags...) |
140 | | - if err != nil || mod == "<nil>" { |
141 | | - // if the command errors or modules aren't being used, return the empty string |
142 | | - return "" |
143 | | - } |
144 | | - |
145 | | - modDir, err := runGoListWithEnv("{{.Module.Dir}}", []string{pkgpath}, []string{"GO111MODULE=on"}, flags...) |
146 | | - if err != nil { |
147 | | - return "" |
148 | | - } |
149 | | - |
150 | | - abs, err := filepath.Abs(modDir) |
151 | | - if err != nil { |
152 | | - log.Printf("Warning: unable to make %s absolute: %s", modDir, err.Error()) |
153 | | - return "" |
154 | | - } |
155 | | - return abs |
156 | | -} |
157 | | - |
158 | | -// GetPkgDir gets the absolute directory containing the package with path `pkgpath`. It passes the |
159 | | -// `go list` command the flags specified by `flags`. |
160 | | -func GetPkgDir(pkgpath string, flags ...string) string { |
161 | | - pkgDir, err := runGoList("{{.Dir}}", []string{pkgpath}, flags...) |
162 | | - if err != nil { |
163 | | - return "" |
164 | | - } |
165 | | - |
166 | | - abs, err := filepath.Abs(pkgDir) |
167 | | - if err != nil { |
168 | | - log.Printf("Warning: unable to make %s absolute: %s", pkgDir, err.Error()) |
169 | | - return "" |
170 | | - } |
171 | | - return abs |
172 | | -} |
173 | | - |
174 | | -// DepErrors checks there are any errors resolving dependencies for `pkgpath`. It passes the `go |
175 | | -// list` command the flags specified by `flags`. |
176 | | -func DepErrors(pkgpath string, flags ...string) bool { |
177 | | - out, err := runGoList("{{if .DepsErrors}}error{{else}}{{end}}", []string{pkgpath}, flags...) |
178 | | - if err != nil { |
179 | | - // if go list failed, assume dependencies are broken |
180 | | - return false |
181 | | - } |
182 | | - |
183 | | - return out != "" |
184 | | -} |
185 | | - |
186 | 36 | // FileExists tests whether the file at `filename` exists and is not a directory. |
187 | 37 | func FileExists(filename string) bool { |
188 | 38 | info, err := os.Stat(filename) |
|
0 commit comments