@@ -31,12 +31,14 @@ import (
31
31
"time"
32
32
33
33
"golang.org/x/mod/module"
34
+ "golang.org/x/mod/semver"
34
35
goimp "golang.org/x/tools/imports"
35
36
)
36
37
37
38
type imports struct {
38
- packages map [string ]string // alias => import path
39
- modules map [string ]string // module path => version
39
+ packages map [string ]string // alias => import path
40
+ modules map [string ]string // module path => version
41
+ onlySemVer bool
40
42
}
41
43
42
44
func (* imports ) String () string {
@@ -71,6 +73,7 @@ func (imp *imports) Set(s string) error {
71
73
imp .modules = make (map [string ]string )
72
74
}
73
75
imp .modules [path ] = version
76
+ imp .onlySemVer = imp .onlySemVer && semver .IsValid (version ) && version == semver .Canonical (version )
74
77
} else if alias == "" {
75
78
alias = " " + path // special alias
76
79
}
@@ -104,7 +107,7 @@ func runSilent(cmd *exec.Cmd) error {
104
107
105
108
func runX (cmd * exec.Cmd ) error {
106
109
// Inject -x in go commands
107
- if cmd .Args [0 ] == "go" {
110
+ if cmd .Args [0 ] == "go" && cmd . Args [ 1 ] != "env" {
108
111
cmd .Args = append ([]string {"go" , cmd .Args [1 ], "-x" }, cmd .Args [2 :]... )
109
112
}
110
113
fmt .Printf ("%s\n " , cmd .Args )
@@ -118,6 +121,25 @@ func runTime(cmd *exec.Cmd) error {
118
121
return cmd .Run ()
119
122
}
120
123
124
+ var goCmd = "go"
125
+
126
+ func getGOMODCACHE (env []string ) (string , error ) {
127
+ var out bytes.Buffer
128
+ cmd := exec .Command (goCmd , "env" , "GOMODCACHE" )
129
+ cmd .Stderr = os .Stderr
130
+ cmd .Stdout = & out
131
+ cmd .Env = env
132
+ err := run (cmd )
133
+ if err != nil {
134
+ return "" , err
135
+ }
136
+ b := bytes .TrimRight (out .Bytes (), "\r \n " )
137
+ if len (b ) == 0 {
138
+ return "" , errors .New ("can't retrieve GOMODCACHE" )
139
+ }
140
+ return string (b ), nil
141
+ }
142
+
121
143
func main () {
122
144
err := _main ()
123
145
if exit , ok := err .(* exec.ExitError ); ok && exit .ExitCode () > 0 {
@@ -129,7 +151,8 @@ func main() {
129
151
130
152
func _main () error {
131
153
imports := imports {
132
- packages : map [string ]string {" " : "os" },
154
+ packages : map [string ]string {" " : "os" },
155
+ onlySemVer : true ,
133
156
}
134
157
flag .Var (& imports , "i" , "import package: [alias=]import-path" )
135
158
@@ -193,6 +216,16 @@ func _main() error {
193
216
var dir , origDir string
194
217
195
218
if moduleMode {
219
+ // "go get" is not yet as smart as we want, so let's help
220
+ // https://go.dev/issue/43646
221
+ preferCache := imports .onlySemVer
222
+ var gomodcache string
223
+ if preferCache {
224
+ var err error
225
+ gomodcache , err = getGOMODCACHE (env )
226
+ preferCache = err == nil
227
+ }
228
+
196
229
var err error
197
230
if dir , err = os .MkdirTemp ("" , "goeval*" ); err != nil {
198
231
log .Fatal (err )
@@ -216,15 +249,28 @@ func _main() error {
216
249
gogetArgs = append (gogetArgs , "get" , "--" )
217
250
for mod , ver := range imports .modules {
218
251
gogetArgs = append (gogetArgs , mod + "@" + ver )
252
+ if preferCache {
253
+ // Keep preferCache as long as we find modules in the cache
254
+ _ , err := os .Stat (gomodcache + "/cache/download/" + mod + "/@v/" + ver + ".mod" )
255
+ preferCache = err == nil
256
+ }
219
257
}
220
258
for _ , path := range imports .packages {
221
259
if _ , seen := imports .modules [path ]; ! seen {
222
260
gogetArgs = append (gogetArgs , path )
223
261
}
224
262
}
225
263
264
+ // fmt.Println("preferCache", preferCache)
265
+
226
266
cmd := exec .Command ("go" , gogetArgs ... )
227
- cmd .Env = env
267
+ if preferCache {
268
+ // As we found all modules in the cache, tell "go get" to not use the proxy.
269
+ // See https://go.dev/issue/43646
270
+ cmd .Env = append (env , "GOPROXY=file://" + filepath .ToSlash (gomodcache )+ "/cache/download" )
271
+ } else {
272
+ cmd .Env = env
273
+ }
228
274
cmd .Dir = dir
229
275
cmd .Stdin = nil
230
276
cmd .Stdout = nil
0 commit comments