@@ -176,10 +176,13 @@ func findGoModFiles(root string) []string {
176
176
return util .FindAllFilesWithName (root , "go.mod" , "vendor" )
177
177
}
178
178
179
+ // A regular expression for the Go toolchain version syntax.
180
+ var toolchainVersionRe * regexp.Regexp = regexp .MustCompile (`(?m)^([0-9]+\.[0-9]+\.[0-9]+)$` )
181
+
179
182
// Given a list of `go.mod` file paths, try to parse them all. The resulting array of `GoModule` objects
180
183
// will be the same length as the input array and the objects will contain at least the `go.mod` path.
181
184
// If parsing the corresponding file is successful, then the parsed contents will also be available.
182
- func LoadGoModules (goModFilePaths []string ) []* GoModule {
185
+ func LoadGoModules (emitDiagnostics bool , goModFilePaths []string ) []* GoModule {
183
186
results := make ([]* GoModule , len (goModFilePaths ))
184
187
185
188
for i , goModFilePath := range goModFilePaths {
@@ -201,6 +204,15 @@ func LoadGoModules(goModFilePaths []string) []*GoModule {
201
204
}
202
205
203
206
results [i ].Module = modFile
207
+
208
+ // If this `go.mod` file specifies a Go language version, that version is `1.21` or greater, and
209
+ // there is no `toolchain` directive, check that it is a valid Go toolchain version. Otherwise,
210
+ // `go` commands which try to download the right version of the Go toolchain will fail. We detect
211
+ // this situation and emit a diagnostic.
212
+ if modFile .Toolchain == nil && modFile .Go != nil &&
213
+ ! toolchainVersionRe .Match ([]byte (modFile .Go .Version )) && semver .Compare ("v" + modFile .Go .Version , "v1.21.0" ) >= 0 {
214
+ diagnostics .EmitInvalidToolchainVersion (goModFilePath , modFile .Go .Version )
215
+ }
204
216
}
205
217
206
218
return results
@@ -209,7 +221,7 @@ func LoadGoModules(goModFilePaths []string) []*GoModule {
209
221
// Given a path to a `go.work` file, this function attempts to parse the `go.work` file. If unsuccessful,
210
222
// we attempt to discover `go.mod` files within subdirectories of the directory containing the `go.work`
211
223
// file ourselves.
212
- func discoverWorkspace (workFilePath string ) GoWorkspace {
224
+ func discoverWorkspace (emitDiagnostics bool , workFilePath string ) GoWorkspace {
213
225
log .Printf ("Loading %s...\n " , workFilePath )
214
226
baseDir := filepath .Dir (workFilePath )
215
227
workFileSrc , err := os .ReadFile (workFilePath )
@@ -223,7 +235,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
223
235
224
236
return GoWorkspace {
225
237
BaseDir : baseDir ,
226
- Modules : LoadGoModules (goModFilePaths ),
238
+ Modules : LoadGoModules (emitDiagnostics , goModFilePaths ),
227
239
DepMode : GoGetWithModules ,
228
240
ModMode : getModMode (GoGetWithModules , baseDir ),
229
241
}
@@ -240,7 +252,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
240
252
241
253
return GoWorkspace {
242
254
BaseDir : baseDir ,
243
- Modules : LoadGoModules (goModFilePaths ),
255
+ Modules : LoadGoModules (emitDiagnostics , goModFilePaths ),
244
256
DepMode : GoGetWithModules ,
245
257
ModMode : getModMode (GoGetWithModules , baseDir ),
246
258
}
@@ -263,7 +275,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
263
275
return GoWorkspace {
264
276
BaseDir : baseDir ,
265
277
WorkspaceFile : workFile ,
266
- Modules : LoadGoModules (goModFilePaths ),
278
+ Modules : LoadGoModules (emitDiagnostics , goModFilePaths ),
267
279
DepMode : GoGetWithModules ,
268
280
ModMode : ModReadonly , // Workspaces only support "readonly"
269
281
}
@@ -286,7 +298,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
286
298
for i , goModFile := range goModFiles {
287
299
results [i ] = GoWorkspace {
288
300
BaseDir : filepath .Dir (goModFile ),
289
- Modules : LoadGoModules ([]string {goModFile }),
301
+ Modules : LoadGoModules (emitDiagnostics , []string {goModFile }),
290
302
DepMode : GoGetWithModules ,
291
303
ModMode : getModMode (GoGetWithModules , filepath .Dir (goModFile )),
292
304
}
@@ -303,7 +315,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
303
315
304
316
results := make ([]GoWorkspace , len (goWorkFiles ))
305
317
for i , workFilePath := range goWorkFiles {
306
- results [i ] = discoverWorkspace (workFilePath )
318
+ results [i ] = discoverWorkspace (emitDiagnostics , workFilePath )
307
319
}
308
320
309
321
// Add all stray `go.mod` files (i.e. those not referenced by `go.work` files)
@@ -335,7 +347,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
335
347
log .Printf ("Module %s is not referenced by any go.work file; adding it separately.\n " , goModFile )
336
348
results = append (results , GoWorkspace {
337
349
BaseDir : filepath .Dir (goModFile ),
338
- Modules : LoadGoModules ([]string {goModFile }),
350
+ Modules : LoadGoModules (emitDiagnostics , []string {goModFile }),
339
351
DepMode : GoGetWithModules ,
340
352
ModMode : getModMode (GoGetWithModules , filepath .Dir (goModFile )),
341
353
})
0 commit comments