Skip to content

Commit e9188d1

Browse files
author
Bryan C. Mills
committed
cmd/go/internal/modfetch: re-resolve commit hashes in readDiskStat
Previously, when we resolved a commit hash (not a complete version), we always checked the contents of the module cache for any pseudo-version matching that commit. However, there are many possible names for a given commit. Generally the semantically-highest valid name is the best, and that may change over time as new tags are added, so if we are able to fetch a better name from upstream we should do so. Otherwise, we should fall back to the highest appropriate name found in the cache. Fixes #27171 Updates #27173 Change-Id: Ib5c7d99eb463af84674e969813039cbbee7e395b Reviewed-on: https://go-review.googlesource.com/c/go/+/182178 Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Jay Conrod <[email protected]> Reviewed-by: roger peppe <[email protected]>
1 parent 18107ed commit e9188d1

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

src/cmd/go/internal/modfetch/cache.go

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"strings"
1616

1717
"cmd/go/internal/base"
18+
"cmd/go/internal/cfg"
1819
"cmd/go/internal/lockedfile"
1920
"cmd/go/internal/modfetch/codehost"
2021
"cmd/go/internal/module"
@@ -385,8 +386,29 @@ var errNotCached = fmt.Errorf("not in cache")
385386
func readDiskStat(path, rev string) (file string, info *RevInfo, err error) {
386387
file, data, err := readDiskCache(path, rev, "info")
387388
if err != nil {
388-
if file, info, err := readDiskStatByHash(path, rev); err == nil {
389-
return file, info, nil
389+
// If the cache already contains a pseudo-version with the given hash, we
390+
// would previously return that pseudo-version without checking upstream.
391+
// However, that produced an unfortunate side-effect: if the author added a
392+
// tag to the repository, 'go get' would not pick up the effect of that new
393+
// tag on the existing commits, and 'go' commands that referred to those
394+
// commits would use the previous name instead of the new one.
395+
//
396+
// That's especially problematic if the original pseudo-version starts with
397+
// v0.0.0-, as was the case for all pseudo-versions during vgo development,
398+
// since a v0.0.0- pseudo-version has lower precedence than pretty much any
399+
// tagged version.
400+
//
401+
// In practice, we're only looking up by hash during initial conversion of a
402+
// legacy config and during an explicit 'go get', and a little extra latency
403+
// for those operations seems worth the benefit of picking up more accurate
404+
// versions.
405+
//
406+
// Fall back to this resolution scheme only if the GOPROXY setting prohibits
407+
// us from resolving upstream tags.
408+
if cfg.GOPROXY == "off" {
409+
if file, info, err := readDiskStatByHash(path, rev); err == nil {
410+
return file, info, nil
411+
}
390412
}
391413
return file, nil, err
392414
}
@@ -436,13 +458,23 @@ func readDiskStatByHash(path, rev string) (file string, info *RevInfo, err error
436458
if err != nil {
437459
return "", nil, errNotCached
438460
}
461+
462+
// A given commit hash may map to more than one pseudo-version,
463+
// depending on which tags are present on the repository.
464+
// Take the highest such version.
465+
var maxVersion string
439466
suffix := "-" + rev + ".info"
467+
err = errNotCached
440468
for _, name := range names {
441-
if strings.HasSuffix(name, suffix) && IsPseudoVersion(strings.TrimSuffix(name, ".info")) {
442-
return readDiskStat(path, strings.TrimSuffix(name, ".info"))
469+
if strings.HasSuffix(name, suffix) {
470+
v := strings.TrimSuffix(name, ".info")
471+
if IsPseudoVersion(v) && semver.Max(maxVersion, v) == v {
472+
maxVersion = v
473+
file, info, err = readDiskStat(path, strings.TrimSuffix(name, ".info"))
474+
}
443475
}
444476
}
445-
return "", nil, errNotCached
477+
return file, info, err
446478
}
447479

448480
// oldVgoPrefix is the prefix in the old auto-generated cached go.mod files.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[!net] skip
2+
[!exec:git] skip
3+
4+
env GO111MODULE=on
5+
env GOPROXY=direct
6+
env GOSUMDB=off
7+
8+
# Regression test for golang.org/issue/27171: after resolving an older
9+
# pseudo-version of a commit, future resolution of that commit by hash should
10+
# choose the highest appropriate pseudo-version instead of the cached one.
11+
12+
go mod download -json golang.org/x/[email protected]
13+
stdout '"Version": "v0.0.0-20171215141712-a1b916ed6726",'
14+
15+
# If GOPROXY is 'off', lookups should use whatever pseudo-version is available.
16+
env GOPROXY=off
17+
go mod download -json golang.org/x/text@a1b916ed6726
18+
stdout '"Version": "v0.0.0-20171215141712-a1b916ed6726",'
19+
20+
# If we can re-resolve the commit to a pseudo-version, fetching the commit by
21+
# hash should use the highest such pseudo-version appropriate to the commit.
22+
env GOPROXY=direct
23+
go mod download -json golang.org/x/text@a1b916ed6726
24+
stdout '"Version": "v0.3.1-0.20171215141712-a1b916ed6726",'
25+
26+
# If GOPROXY is 'off', lookups should use the highest pseudo-version in the cache.
27+
env GOPROXY=off
28+
go mod download -json golang.org/x/text@a1b916ed6726
29+
stdout '"Version": "v0.3.1-0.20171215141712-a1b916ed6726",'

0 commit comments

Comments
 (0)