aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/modfetch/coderepo.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2018-07-17 10:16:38 -0400
committerRuss Cox <rsc@golang.org>2018-07-19 18:15:26 +0000
commit9430c1a669b6d4a832f740ba0c9f67c4267d9170 (patch)
tree1f3f19226edcab56850d6442d926879505b23196 /src/cmd/go/internal/modfetch/coderepo.go
parent472e92609a7fa6a1983052d1d8e07bc9e4dcb396 (diff)
downloadgo-9430c1a669b6d4a832f740ba0c9f67c4267d9170.tar.gz
go-9430c1a669b6d4a832f740ba0c9f67c4267d9170.zip
cmd/go/internal/modfetch: move to new pseudo-version design
The original pseudo-version design used versions of the form v0.0.0-yyyymmddhhmmss-abcdef123456 These were intentionally chosen to be valid semantic versions that sort below any explicitly-chosen semantic version (even v0.0.0), so that they could be used before anything was tagged but after that would essentially only be useful in replace statements (because the max operation during MVS would always prefer a tagged version). Then we changed the go command to accept hashes on the command line, so that you can say go get github.com/my/proj@abcdef and it will download and use v0.0.0-yyyymmddhhmmss-abcdef123456. If you were using v1.10.1 before and this commit is just little bit newer than that commit, calling it v0.0.0-xxx is confusing but also harmful: the go command sees the change from v1.10.1 to the v0.0.0 pseudoversion as a downgrade, and it downgrades other modules in the build. In particular if some other module has a requirement of github.com/my/proj v1.9.0 (or later), the pseudo-version appears to be before that, so go get would downgrade that module too. It might even remove it entirely, if every available version needs a post-v0.0.0 version of my/proj. This CL introduces new pseudo-version forms that can be used to slot in after the most recent explicit tag before the commit. If the most recent tagged commit before abcdef is v1.10.1, then now we will use v1.10.2-0.yyyymmddhhmmss-abcdef123456 This has the right properties for downgrades and the like, since it is after v1.10.1 but before almost any possible successor, such as v1.10.2, v1.10.2-1, or v1.10.2-pre. This CL also uses those pseudo-version forms as appropriate when mapping a hash to a pseudo-version. This fixes the downgrade problem. Overall, this CL reflects our growing recognition of pseudo-versions as being like "untagged prereleases". Issue #26150 was about documenting best practices for how to work around this kind of accidental downgrade problem with additional steps. Now there are no additional steps: the problem is avoided by default. Fixes #26150. Change-Id: I402feeccb93e8e937bafcaa26402d88572e9b14c Reviewed-on: https://go-review.googlesource.com/124515 Reviewed-by: Bryan C. Mills <bcmills@google.com>
Diffstat (limited to 'src/cmd/go/internal/modfetch/coderepo.go')
-rw-r--r--src/cmd/go/internal/modfetch/coderepo.go88
1 files changed, 9 insertions, 79 deletions
diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
index f5d2e3e27f..c45833cbdd 100644
--- a/src/cmd/go/internal/modfetch/coderepo.go
+++ b/src/cmd/go/internal/modfetch/coderepo.go
@@ -6,15 +6,12 @@ package modfetch
import (
"archive/zip"
- "errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
- "regexp"
"strings"
- "time"
"cmd/go/internal/modfetch/codehost"
"cmd/go/internal/modfile"
@@ -194,7 +191,7 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
}
}
- tagOK := func(v string) string {
+ tagToVersion := func(v string) string {
if !strings.HasPrefix(v, p) {
return ""
}
@@ -212,18 +209,21 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
}
// If info.Version is OK, use it.
- if v := tagOK(info.Version); v != "" {
+ if v := tagToVersion(info.Version); v != "" {
info2.Version = v
} else {
// Otherwise look through all known tags for latest in semver ordering.
for _, tag := range info.Tags {
- if v := tagOK(tag); v != "" && semver.Compare(info2.Version, v) < 0 {
+ if v := tagToVersion(tag); v != "" && semver.Compare(info2.Version, v) < 0 {
info2.Version = v
}
}
// Otherwise make a pseudo-version.
if info2.Version == "" {
- info2.Version = PseudoVersion(r.pseudoMajor, info.Time, info.Short)
+ tag, _ := r.code.RecentTag(statVers, p)
+ v = tagToVersion(tag)
+ // TODO: Check that v is OK for r.pseudoMajor or else is OK for incompatible.
+ info2.Version = PseudoVersion(r.pseudoMajor, v, info.Time, info.Short)
}
}
}
@@ -231,7 +231,6 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
// Do not allow a successful stat of a pseudo-version for a subdirectory
// unless the subdirectory actually does have a go.mod.
if IsPseudoVersion(info2.Version) && r.codeDir != "" {
- // TODO: git describe --first-parent --match 'v[0-9]*' --tags
_, _, _, err := r.findDir(info2.Version)
if err != nil {
// TODO: It would be nice to return an error like "not a module".
@@ -246,9 +245,8 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
func (r *codeRepo) revToRev(rev string) string {
if semver.IsValid(rev) {
if IsPseudoVersion(rev) {
- i := strings.Index(rev, "-")
- j := strings.Index(rev[i+1:], "-")
- return rev[i+1+j+1:]
+ r, _ := PseudoVersionRev(rev)
+ return r
}
if semver.Build(rev) == "+incompatible" {
rev = rev[:len(rev)-len("+incompatible")]
@@ -598,71 +596,3 @@ func isVendoredPackage(name string) bool {
}
return strings.Contains(name[i:], "/")
}
-
-func PseudoVersion(major string, t time.Time, rev string) string {
- if major == "" {
- major = "v0"
- }
- return fmt.Sprintf("%s.0.0-%s-%s", major, t.UTC().Format("20060102150405"), rev)
-}
-
-var ErrNotPseudoVersion = errors.New("not a pseudo-version")
-
-/*
-func ParsePseudoVersion(repo Repo, version string) (rev string, err error) {
- major := semver.Major(version)
- if major == "" {
- return "", ErrNotPseudoVersion
- }
- majorPrefix := major + ".0.0-"
- if !strings.HasPrefix(version, majorPrefix) || !strings.Contains(version[len(majorPrefix):], "-") {
- return "", ErrNotPseudoVersion
- }
- versionSuffix := version[len(majorPrefix):]
- for i := 0; versionSuffix[i] != '-'; i++ {
- c := versionSuffix[i]
- if c < '0' || '9' < c {
- return "", ErrNotPseudoVersion
- }
- }
- rev = versionSuffix[strings.Index(versionSuffix, "-")+1:]
- if rev == "" {
- return "", ErrNotPseudoVersion
- }
- if proxyURL != "" {
- return version, nil
- }
- fullRev, t, err := repo.CommitInfo(rev)
- if err != nil {
- return "", fmt.Errorf("unknown pseudo-version %s: loading %v: %v", version, rev, err)
- }
- v := PseudoVersion(major, t, repo.ShortRev(fullRev))
- if v != version {
- return "", fmt.Errorf("unknown pseudo-version %s: %v is %v", version, rev, v)
- }
- return fullRev, nil
-}
-*/
-
-var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.0\.0-[0-9]{14}-[A-Za-z0-9]+$`)
-
-// IsPseudoVersion reports whether v is a pseudo-version.
-func IsPseudoVersion(v string) bool {
- return pseudoVersionRE.MatchString(v)
-}
-
-// PseudoVersionTime returns the time stamp of the pseudo-version v.
-// It returns an error if v is not a pseudo-version or if the time stamp
-// embedded in the pseudo-version is not a valid time.
-func PseudoVersionTime(v string) (time.Time, error) {
- if !IsPseudoVersion(v) {
- return time.Time{}, fmt.Errorf("not a pseudo-version")
- }
- i := strings.Index(v, "-") + 1
- j := i + strings.Index(v[i:], "-")
- t, err := time.Parse("20060102150405", v[i:j])
- if err != nil {
- return time.Time{}, fmt.Errorf("malformed pseudo-version %q", v)
- }
- return t, nil
-}