@@ -329,7 +329,7 @@ func newStdlibInfo(version string) (_ *Info, err error) {
329
329
// example.com/a/b.git/c
330
330
// then repo="example.com/a/b" and relativeModulePath="c"; the ".git" is omitted, since it is neither
331
331
// part of the repo nor part of the relative path to the module within the repo.
332
- func matchStatic (moduleOrRepoPath string ) (repo , relativeModulePath string , _ urlTemplates , transformCommit func ( string , bool ) string , _ error ) {
332
+ func matchStatic (moduleOrRepoPath string ) (repo , relativeModulePath string , _ urlTemplates , transformCommit transformCommitFunc , _ error ) {
333
333
for _ , pat := range patterns {
334
334
matches := pat .re .FindStringSubmatch (moduleOrRepoPath )
335
335
if matches == nil {
@@ -395,7 +395,12 @@ func moduleInfoDynamic(ctx context.Context, client *Client, modulePath, version
395
395
var repo string
396
396
repo , _ , templates , transformCommit , _ = matchStatic (removeHTTPScheme (sourceMeta .dirTemplate ))
397
397
if templates == (urlTemplates {}) {
398
- log .Infof (ctx , "no templates for repo URL %q from meta tag: err=%v" , sourceMeta .repoURL , err )
398
+ if err == nil {
399
+ templates , transformCommit = matchLegacyTemplates (ctx , sourceMeta )
400
+ repoURL = strings .TrimSuffix (repoURL , ".git" )
401
+ } else {
402
+ log .Infof (ctx , "no templates for repo URL %q from meta tag: err=%v" , sourceMeta .repoURL , err )
403
+ }
399
404
} else {
400
405
// Use the repo from the template, not the original one.
401
406
repoURL = "https://" + repo
@@ -414,6 +419,63 @@ func moduleInfoDynamic(ctx context.Context, client *Client, modulePath, version
414
419
}, nil
415
420
}
416
421
422
+ // List of template regexps and their corresponding likely templates,
423
+ // used by matchLegacyTemplates below.
424
+ var legacyTemplateMatches = []struct {
425
+ fileRegexp * regexp.Regexp
426
+ templates urlTemplates
427
+ transformCommit transformCommitFunc
428
+ }{
429
+ {
430
+ regexp .MustCompile (`/src/branch/\w+\{/dir\}/\{file\}#L\{line\}$` ),
431
+ giteaURLTemplates , giteaTransformCommit ,
432
+ },
433
+ {
434
+ regexp .MustCompile (`/src/\w+\{/dir\}/\{file\}#L\{line\}$` ),
435
+ giteaURLTemplates , nil ,
436
+ },
437
+ {
438
+ regexp .MustCompile (`/-/blob/\w+\{/dir\}/\{file\}#L\{line\}$` ),
439
+ gitlab2URLTemplates , nil ,
440
+ },
441
+ {
442
+ regexp .MustCompile (`/tree\{/dir\}/\{file\}#n\{line\}$` ),
443
+ fdioURLTemplates , fdioTransformCommit ,
444
+ },
445
+ }
446
+
447
+ // matchLegacyTemplates matches the templates from the go-source meta tag
448
+ // against some known patterns to guess the version-aware URL templates. If it
449
+ // can't find a match, it falls back using the go-source templates with some
450
+ // small replacements. These will not be version-aware but will still serve
451
+ // source at a fixed commit, which is better than nothing.
452
+ func matchLegacyTemplates (ctx context.Context , sm * sourceMeta ) (_ urlTemplates , transformCommit transformCommitFunc ) {
453
+ if sm .fileTemplate == "" {
454
+ return urlTemplates {}, nil
455
+ }
456
+ for _ , ltm := range legacyTemplateMatches {
457
+ if ltm .fileRegexp .MatchString (sm .fileTemplate ) {
458
+ return ltm .templates , ltm .transformCommit
459
+ }
460
+ }
461
+ log .Infof (ctx , "matchLegacyTemplates: no matches for repo URL %q; replacing" , sm .repoURL )
462
+ rep := strings .NewReplacer (
463
+ "{/dir}/{file}" , "/{file}" ,
464
+ "{dir}/{file}" , "{file}" ,
465
+ "{/dir}" , "/{dir}" )
466
+ line := rep .Replace (sm .fileTemplate )
467
+ file := line
468
+ if i := strings .LastIndexByte (line , '#' ); i > 0 {
469
+ file = line [:i ]
470
+ }
471
+ return urlTemplates {
472
+ Repo : sm .repoURL ,
473
+ Directory : rep .Replace (sm .dirTemplate ),
474
+ File : file ,
475
+ Line : line ,
476
+ }, nil
477
+ }
478
+
417
479
// adjustVersionedModuleDirectory changes info.moduleDir if necessary to
418
480
// correctly reflect the repo structure. info.moduleDir will be wrong if it has
419
481
// a suffix "/vN" for N > 1, and the repo uses the "major branch" convention,
@@ -463,6 +525,8 @@ func removeVersionSuffix(s string) string {
463
525
return strings .TrimSuffix (dir , "/" )
464
526
}
465
527
528
+ type transformCommitFunc func (commit string , isHash bool ) string
529
+
466
530
// Patterns for determining repo and URL templates from module paths or repo
467
531
// URLs. Each regexp must match a prefix of the target string, and must have a
468
532
// group named "repo".
@@ -471,7 +535,7 @@ var patterns = []struct {
471
535
templates urlTemplates
472
536
re * regexp.Regexp
473
537
// transformCommit may alter the commit before substitution
474
- transformCommit func ( commit string , isHash bool ) string
538
+ transformCommit transformCommitFunc
475
539
}{
476
540
{
477
541
pattern : `^(?P<repo>github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)` ,
@@ -504,30 +568,13 @@ var patterns = []struct {
504
568
},
505
569
},
506
570
{
507
- pattern : `^(?P<repo>git\.fd\.io/[a-z0-9A-Z_.\-]+)` ,
508
- templates : urlTemplates {
509
- Directory : "{repo}/tree/{dir}?{commit}" ,
510
- File : "{repo}/tree/{file}?{commit}" ,
511
- Line : "{repo}/tree/{file}?{commit}#n{line}" ,
512
- Raw : "{repo}/plain/{file}?{commit}" ,
513
- },
514
- transformCommit : func (commit string , isHash bool ) string {
515
- // hashes use "?id=", tags use "?h="
516
- p := "h"
517
- if isHash {
518
- p = "id"
519
- }
520
- return fmt .Sprintf ("%s=%s" , p , commit )
521
- },
571
+ pattern : `^(?P<repo>git\.fd\.io/[a-z0-9A-Z_.\-]+)` ,
572
+ templates : fdioURLTemplates ,
573
+ transformCommit : fdioTransformCommit ,
522
574
},
523
575
{
524
- pattern : `^(?P<repo>git\.pirl\.io/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)` ,
525
- templates : urlTemplates {
526
- Directory : "{repo}/-/tree/{commit}/{dir}" ,
527
- File : "{repo}/-/blob/{commit}/{file}" ,
528
- Line : "{repo}/-/blob/{commit}/{file}#L{line}" ,
529
- Raw : "{repo}/-/raw/{commit}/{file}" ,
530
- },
576
+ pattern : `^(?P<repo>git\.pirl\.io/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)` ,
577
+ templates : gitlab2URLTemplates ,
531
578
},
532
579
{
533
580
pattern : `^(?P<repo>gitea\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(\.git|$)` ,
@@ -617,6 +664,15 @@ func giteaTransformCommit(commit string, isHash bool) string {
617
664
return "tag/" + commit
618
665
}
619
666
667
+ func fdioTransformCommit (commit string , isHash bool ) string {
668
+ // hashes use "?id=", tags use "?h="
669
+ p := "h"
670
+ if isHash {
671
+ p = "id"
672
+ }
673
+ return fmt .Sprintf ("%s=%s" , p , commit )
674
+ }
675
+
620
676
// urlTemplates describes how to build URLs from bits of source information.
621
677
// The fields are exported for JSON encoding.
622
678
//
@@ -664,6 +720,18 @@ var (
664
720
Line : "{repo}/+/{commit}/{file}#{line}" ,
665
721
// Gitiles has no support for serving raw content at this time.
666
722
}
723
+ gitlab2URLTemplates = urlTemplates {
724
+ Directory : "{repo}/-/tree/{commit}/{dir}" ,
725
+ File : "{repo}/-/blob/{commit}/{file}" ,
726
+ Line : "{repo}/-/blob/{commit}/{file}#L{line}" ,
727
+ Raw : "{repo}/-/raw/{commit}/{file}" ,
728
+ }
729
+ fdioURLTemplates = urlTemplates {
730
+ Directory : "{repo}/tree/{dir}?{commit}" ,
731
+ File : "{repo}/tree/{file}?{commit}" ,
732
+ Line : "{repo}/tree/{file}?{commit}#n{line}" ,
733
+ Raw : "{repo}/plain/{file}?{commit}" ,
734
+ }
667
735
)
668
736
669
737
// commitFromVersion returns a string that refers to a commit corresponding to version.
0 commit comments