@@ -73,7 +73,7 @@ func (s *snapshot) ParseMod(ctx context.Context, modFH source.FileHandle) (*sour
73
73
// Attempt to convert the error to a standardized parse error.
74
74
var parseErrors []* source.Error
75
75
if err != nil {
76
- if parseErr , extractErr := extractErrorWithPosition (ctx , err .Error (), s ); extractErr = = nil {
76
+ if parseErr := extractErrorWithPosition (ctx , err .Error (), s ); parseErr ! = nil {
77
77
parseErrors = []* source.Error {parseErr }
78
78
}
79
79
}
@@ -341,29 +341,39 @@ var moduleAtVersionRe = regexp.MustCompile(`^(?P<module>.*)@(?P<version>.*)$`)
341
341
342
342
// extractGoCommandError tries to parse errors that come from the go command
343
343
// and shape them into go.mod diagnostics.
344
- func (s * snapshot ) extractGoCommandError (ctx context.Context , snapshot source.Snapshot , fh source.FileHandle , goCmdError string ) * source.Error {
344
+ func (s * snapshot ) extractGoCommandErrors (ctx context.Context , snapshot source.Snapshot , fh source.FileHandle , goCmdError string ) []* source.Error {
345
+ var srcErrs []* source.Error
346
+ if srcErr := s .parseModError (ctx , fh , goCmdError ); srcErr != nil {
347
+ srcErrs = append (srcErrs , srcErr )
348
+ }
345
349
// If the error message contains a position, use that. Don't pass a file
346
350
// handle in, as it might not be the file associated with the error.
347
- if srcErr , err := extractErrorWithPosition (ctx , goCmdError , s ); err == nil {
348
- return srcErr
351
+ if srcErr := extractErrorWithPosition (ctx , goCmdError , s ); srcErr != nil {
352
+ srcErrs = append (srcErrs , srcErr )
353
+ } else if srcErr := s .matchErrorToModule (ctx , fh , goCmdError ); srcErr != nil {
354
+ srcErrs = append (srcErrs , srcErr )
349
355
}
350
- // We try to match module versions in error messages. Some examples:
351
- //
352
- // example.com@v1.2.2: reading example.com/@v/v1.2.2.mod: no such file or directory
353
- // go: github.com/cockroachdb/apd/v2@v2.0.72: reading github.com/cockroachdb/apd/go.mod at revision v2.0.72: unknown revision v2.0.72
354
- // go: example.com@v1.2.3 requires\n\trandom.org@v1.2.3: parsing go.mod:\n\tmodule declares its path as: bob.org\n\tbut was required as: random.org
355
- //
356
- // We split on colons and whitespace, and attempt to match on something
357
- // that matches module@version. If we're able to find a match, we try to
358
- // find anything that matches it in the go.mod file.
356
+ return srcErrs
357
+ }
358
+
359
+ // matchErrorToModule attempts to match module version in error messages.
360
+ // Some examples:
361
+ //
362
+ // example.com@v1.2.2: reading example.com/@v/v1.2.2.mod: no such file or directory
363
+ // go: github.com/cockroachdb/apd/v2@v2.0.72: reading github.com/cockroachdb/apd/go.mod at revision v2.0.72: unknown revision v2.0.72
364
+ // go: example.com@v1.2.3 requires\n\trandom.org@v1.2.3: parsing go.mod:\n\tmodule declares its path as: bob.org\n\tbut was required as: random.org
365
+ //
366
+ // We split on colons and whitespace, and attempt to match on something
367
+ // that matches module@version. If we're able to find a match, we try to
368
+ // find anything that matches it in the go.mod file.
369
+ func (s * snapshot ) matchErrorToModule (ctx context.Context , fh source.FileHandle , goCmdError string ) * source.Error {
359
370
var v module.Version
360
371
fields := strings .FieldsFunc (goCmdError , func (r rune ) bool {
361
372
return unicode .IsSpace (r ) || r == ':'
362
373
})
363
- for _ , s := range fields {
364
- s = strings .TrimSpace (s )
365
- match := moduleAtVersionRe .FindStringSubmatch (s )
366
- if match == nil || len (match ) < 3 {
374
+ for _ , field := range fields {
375
+ match := moduleAtVersionRe .FindStringSubmatch (field )
376
+ if match == nil {
367
377
continue
368
378
}
369
379
path , version := match [1 ], match [2 ]
@@ -378,7 +388,7 @@ func (s *snapshot) extractGoCommandError(ctx context.Context, snapshot source.Sn
378
388
v .Path , v .Version = path , version
379
389
break
380
390
}
381
- pm , err := snapshot .ParseMod (ctx , fh )
391
+ pm , err := s .ParseMod (ctx , fh )
382
392
if err != nil {
383
393
return nil
384
394
}
@@ -387,13 +397,19 @@ func (s *snapshot) extractGoCommandError(ctx context.Context, snapshot source.Sn
387
397
if err != nil {
388
398
return nil
389
399
}
390
- if v .Path != "" && strings .Contains (goCmdError , "disabled by GOPROXY=off" ) {
400
+ disabledByGOPROXY := strings .Contains (goCmdError , "disabled by GOPROXY=off" )
401
+ shouldAddDep := strings .Contains (goCmdError , "to add it" )
402
+ if v .Path != "" && (disabledByGOPROXY || shouldAddDep ) {
391
403
args , err := source .MarshalArgs (fh .URI (), false , []string {fmt .Sprintf ("%v@%v" , v .Path , v .Version )})
392
404
if err != nil {
393
405
return nil
394
406
}
407
+ msg := goCmdError
408
+ if disabledByGOPROXY {
409
+ msg = fmt .Sprintf ("%v@%v has not been downloaded" , v .Path , v .Version )
410
+ }
395
411
return & source.Error {
396
- Message : fmt . Sprintf ( "%v@%v has not been downloaded" , v . Path , v . Version ) ,
412
+ Message : msg ,
397
413
Kind : source .ListError ,
398
414
Range : rng ,
399
415
URI : fh .URI (),
@@ -411,6 +427,7 @@ func (s *snapshot) extractGoCommandError(ctx context.Context, snapshot source.Sn
411
427
Message : goCmdError ,
412
428
Range : rng ,
413
429
URI : fh .URI (),
430
+ Kind : source .ListError ,
414
431
}
415
432
}
416
433
// Check if there are any require, exclude, or replace statements that
@@ -449,10 +466,10 @@ var errorPositionRe = regexp.MustCompile(`(?P<pos>.*:([\d]+)(:([\d]+))?): (?P<ms
449
466
// information for the given unstructured error. If a file handle is provided,
450
467
// the error position will be on that file. This is useful for parse errors,
451
468
// where we already know the file with the error.
452
- func extractErrorWithPosition (ctx context.Context , goCmdError string , src source.FileSource ) ( * source.Error , error ) {
469
+ func extractErrorWithPosition (ctx context.Context , goCmdError string , src source.FileSource ) * source.Error {
453
470
matches := errorPositionRe .FindStringSubmatch (strings .TrimSpace (goCmdError ))
454
471
if len (matches ) == 0 {
455
- return nil , fmt . Errorf ( "error message doesn't contain a position" )
472
+ return nil
456
473
}
457
474
var pos , msg string
458
475
for i , name := range errorPositionRe .SubexpNames () {
@@ -466,11 +483,11 @@ func extractErrorWithPosition(ctx context.Context, goCmdError string, src source
466
483
spn := span .Parse (pos )
467
484
fh , err := src .GetFile (ctx , spn .URI ())
468
485
if err != nil {
469
- return nil , err
486
+ return nil
470
487
}
471
488
content , err := fh .Read ()
472
489
if err != nil {
473
- return nil , err
490
+ return nil
474
491
}
475
492
m := & protocol.ColumnMapper {
476
493
URI : spn .URI (),
@@ -479,7 +496,7 @@ func extractErrorWithPosition(ctx context.Context, goCmdError string, src source
479
496
}
480
497
rng , err := m .Range (spn )
481
498
if err != nil {
482
- return nil , err
499
+ return nil
483
500
}
484
501
category := GoCommandError
485
502
if fh != nil {
@@ -490,5 +507,5 @@ func extractErrorWithPosition(ctx context.Context, goCmdError string, src source
490
507
Message : msg ,
491
508
Range : rng ,
492
509
URI : spn .URI (),
493
- }, nil
510
+ }
494
511
}
0 commit comments