aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan C. Mills <bcmills@google.com>2020-07-27 13:57:12 -0400
committerBryan C. Mills <bcmills@google.com>2020-09-09 22:38:35 +0000
commit521393e7e05cd9272ae6023387fa92839d72eb4f (patch)
treef759fe284c3e6bd02cdc0eaac5ee5a68c83cef67
parent363fb4bcc814069e3d80e22bd022599179ec1c62 (diff)
downloadgo-521393e7e05cd9272ae6023387fa92839d72eb4f.tar.gz
go-521393e7e05cd9272ae6023387fa92839d72eb4f.zip
cmd/go/internal/modget: move MVS code to a separate file
For #36460 Change-Id: Ie81c03df18c6987527da765d5f6575556340cb01 Reviewed-on: https://go-review.googlesource.com/c/go/+/249877 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Matloob <matloob@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
-rw-r--r--src/cmd/go/internal/modget/get.go188
-rw-r--r--src/cmd/go/internal/modget/mvs.go202
2 files changed, 203 insertions, 187 deletions
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index 126b1f4bd4..cf9ad66b3d 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -290,7 +290,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
// what was requested.
modload.DisallowWriteGoMod()
- // Allow looking up modules for import paths outside of a module.
+ // Allow looking up modules for import paths when outside of a module.
// 'go get' is expected to do this, unlike other commands.
modload.AllowMissingModuleImports()
@@ -885,192 +885,6 @@ func getQuery(ctx context.Context, path, vers string, prevM module.Version, forc
return m, nil
}
-// An upgrader adapts an underlying mvs.Reqs to apply an
-// upgrade policy to a list of targets and their dependencies.
-type upgrader struct {
- mvs.Reqs
-
- // cmdline maps a module path to a query made for that module at a
- // specific target version. Each query corresponds to a module
- // matched by a command line argument.
- cmdline map[string]*query
-
- // upgrade is a set of modules providing dependencies of packages
- // matched by command line arguments. If -u or -u=patch is set,
- // these modules are upgraded accordingly.
- upgrade map[string]bool
-}
-
-// newUpgrader creates an upgrader. cmdline contains queries made at
-// specific versions for modules matched by command line arguments. pkgs
-// is the set of packages matched by command line arguments. If -u or -u=patch
-// is set, modules providing dependencies of pkgs are upgraded accordingly.
-func newUpgrader(cmdline map[string]*query, pkgs map[string]bool) *upgrader {
- u := &upgrader{
- Reqs: modload.Reqs(),
- cmdline: cmdline,
- }
- if getU != "" {
- u.upgrade = make(map[string]bool)
-
- // Traverse package import graph.
- // Initialize work queue with root packages.
- seen := make(map[string]bool)
- var work []string
- add := func(path string) {
- if !seen[path] {
- seen[path] = true
- work = append(work, path)
- }
- }
- for pkg := range pkgs {
- add(pkg)
- }
- for len(work) > 0 {
- pkg := work[0]
- work = work[1:]
- m := modload.PackageModule(pkg)
- u.upgrade[m.Path] = true
-
- // testImports is empty unless test imports were actually loaded,
- // i.e., -t was set or "all" was one of the arguments.
- imports, testImports := modload.PackageImports(pkg)
- for _, imp := range imports {
- add(imp)
- }
- for _, imp := range testImports {
- add(imp)
- }
- }
- }
- return u
-}
-
-// Required returns the requirement list for m.
-// For the main module, we override requirements with the modules named
-// one the command line, and we include new requirements. Otherwise,
-// we defer to u.Reqs.
-func (u *upgrader) Required(m module.Version) ([]module.Version, error) {
- rs, err := u.Reqs.Required(m)
- if err != nil {
- return nil, err
- }
- if m != modload.Target {
- return rs, nil
- }
-
- overridden := make(map[string]bool)
- for i, m := range rs {
- if q := u.cmdline[m.Path]; q != nil && q.m.Version != "none" {
- rs[i] = q.m
- overridden[q.m.Path] = true
- }
- }
- for _, q := range u.cmdline {
- if !overridden[q.m.Path] && q.m.Path != modload.Target.Path && q.m.Version != "none" {
- rs = append(rs, q.m)
- }
- }
- return rs, nil
-}
-
-// Upgrade returns the desired upgrade for m.
-//
-// If m was requested at a specific version on the command line, then
-// Upgrade returns that version.
-//
-// If -u is set and m provides a dependency of a package matched by
-// command line arguments, then Upgrade may provider a newer tagged version.
-// If m is a tagged version, then Upgrade will return the latest tagged
-// version (with the same minor version number if -u=patch).
-// If m is a pseudo-version, then Upgrade returns the latest tagged version
-// only if that version has a time-stamp newer than m. This special case
-// prevents accidental downgrades when already using a pseudo-version
-// newer than the latest tagged version.
-//
-// If none of the above cases apply, then Upgrade returns m.
-func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
- // Allow pkg@vers on the command line to override the upgrade choice v.
- // If q's version is < m.Version, then we're going to downgrade anyway,
- // and it's cleaner to avoid moving back and forth and picking up
- // extraneous other newer dependencies.
- // If q's version is > m.Version, then we're going to upgrade past
- // m.Version anyway, and again it's cleaner to avoid moving back and forth
- // picking up extraneous other newer dependencies.
- if q := u.cmdline[m.Path]; q != nil {
- return q.m, nil
- }
-
- if !u.upgrade[m.Path] {
- // Not involved in upgrade. Leave alone.
- return m, nil
- }
-
- // Run query required by upgrade semantics.
- // Note that Query "latest" is not the same as using repo.Latest,
- // which may return a pseudoversion for the latest commit.
- // Query "latest" returns the newest tagged version or the newest
- // prerelease version if there are no non-prereleases, or repo.Latest
- // if there aren't any tagged versions.
- // If we're querying "upgrade" or "patch", Query will compare the current
- // version against the chosen version and will return the current version
- // if it is newer.
- info, err := modload.Query(context.TODO(), m.Path, string(getU), m.Version, modload.CheckAllowed)
- if err != nil {
- // Report error but return m, to let version selection continue.
- // (Reporting the error will fail the command at the next base.ExitIfErrors.)
-
- // Special case: if the error is for m.Version itself and m.Version has a
- // replacement, then keep it and don't report the error: the fact that the
- // version is invalid is likely the reason it was replaced to begin with.
- var vErr *module.InvalidVersionError
- if errors.As(err, &vErr) && vErr.Version == m.Version && modload.Replacement(m).Path != "" {
- return m, nil
- }
-
- // Special case: if the error is "no matching versions" then don't
- // even report the error. Because Query does not consider pseudo-versions,
- // it may happen that we have a pseudo-version but during -u=patch
- // the query v0.0 matches no versions (not even the one we're using).
- var noMatch *modload.NoMatchingVersionError
- if !errors.As(err, &noMatch) {
- base.Errorf("go get: upgrading %s@%s: %v", m.Path, m.Version, err)
- }
- return m, nil
- }
-
- if info.Version != m.Version {
- logOncef("go: %s %s => %s", m.Path, getU, info.Version)
- }
- return module.Version{Path: m.Path, Version: info.Version}, nil
-}
-
-// buildListForLostUpgrade returns the build list for the module graph
-// rooted at lost. Unlike mvs.BuildList, the target module (lost) is not
-// treated specially. The returned build list may contain a newer version
-// of lost.
-//
-// buildListForLostUpgrade is used after a downgrade has removed a module
-// requested at a specific version. This helps us understand the requirements
-// implied by each downgrade.
-func buildListForLostUpgrade(lost module.Version, reqs mvs.Reqs) ([]module.Version, error) {
- return mvs.BuildList(lostUpgradeRoot, &lostUpgradeReqs{Reqs: reqs, lost: lost})
-}
-
-var lostUpgradeRoot = module.Version{Path: "lost-upgrade-root", Version: ""}
-
-type lostUpgradeReqs struct {
- mvs.Reqs
- lost module.Version
-}
-
-func (r *lostUpgradeReqs) Required(mod module.Version) ([]module.Version, error) {
- if mod == lostUpgradeRoot {
- return []module.Version{r.lost}, nil
- }
- return r.Reqs.Required(mod)
-}
-
// reportRetractions prints warnings if any modules in the build list are
// retracted.
func reportRetractions(ctx context.Context) {
diff --git a/src/cmd/go/internal/modget/mvs.go b/src/cmd/go/internal/modget/mvs.go
new file mode 100644
index 0000000000..19fffd2947
--- /dev/null
+++ b/src/cmd/go/internal/modget/mvs.go
@@ -0,0 +1,202 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modget
+
+import (
+ "context"
+ "errors"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/mvs"
+
+ "golang.org/x/mod/module"
+)
+
+// An upgrader adapts an underlying mvs.Reqs to apply an
+// upgrade policy to a list of targets and their dependencies.
+type upgrader struct {
+ mvs.Reqs
+
+ // cmdline maps a module path to a query made for that module at a
+ // specific target version. Each query corresponds to a module
+ // matched by a command line argument.
+ cmdline map[string]*query
+
+ // upgrade is a set of modules providing dependencies of packages
+ // matched by command line arguments. If -u or -u=patch is set,
+ // these modules are upgraded accordingly.
+ upgrade map[string]bool
+}
+
+// newUpgrader creates an upgrader. cmdline contains queries made at
+// specific versions for modules matched by command line arguments. pkgs
+// is the set of packages matched by command line arguments. If -u or -u=patch
+// is set, modules providing dependencies of pkgs are upgraded accordingly.
+func newUpgrader(cmdline map[string]*query, pkgs map[string]bool) *upgrader {
+ u := &upgrader{
+ Reqs: modload.Reqs(),
+ cmdline: cmdline,
+ }
+ if getU != "" {
+ u.upgrade = make(map[string]bool)
+
+ // Traverse package import graph.
+ // Initialize work queue with root packages.
+ seen := make(map[string]bool)
+ var work []string
+ add := func(path string) {
+ if !seen[path] {
+ seen[path] = true
+ work = append(work, path)
+ }
+ }
+ for pkg := range pkgs {
+ add(pkg)
+ }
+ for len(work) > 0 {
+ pkg := work[0]
+ work = work[1:]
+ m := modload.PackageModule(pkg)
+ u.upgrade[m.Path] = true
+
+ // testImports is empty unless test imports were actually loaded,
+ // i.e., -t was set or "all" was one of the arguments.
+ imports, testImports := modload.PackageImports(pkg)
+ for _, imp := range imports {
+ add(imp)
+ }
+ for _, imp := range testImports {
+ add(imp)
+ }
+ }
+ }
+ return u
+}
+
+// Required returns the requirement list for m.
+// For the main module, we override requirements with the modules named
+// one the command line, and we include new requirements. Otherwise,
+// we defer to u.Reqs.
+func (u *upgrader) Required(m module.Version) ([]module.Version, error) {
+ rs, err := u.Reqs.Required(m)
+ if err != nil {
+ return nil, err
+ }
+ if m != modload.Target {
+ return rs, nil
+ }
+
+ overridden := make(map[string]bool)
+ for i, m := range rs {
+ if q := u.cmdline[m.Path]; q != nil && q.m.Version != "none" {
+ rs[i] = q.m
+ overridden[q.m.Path] = true
+ }
+ }
+ for _, q := range u.cmdline {
+ if !overridden[q.m.Path] && q.m.Path != modload.Target.Path && q.m.Version != "none" {
+ rs = append(rs, q.m)
+ }
+ }
+ return rs, nil
+}
+
+// Upgrade returns the desired upgrade for m.
+//
+// If m was requested at a specific version on the command line, then
+// Upgrade returns that version.
+//
+// If -u is set and m provides a dependency of a package matched by
+// command line arguments, then Upgrade may provider a newer tagged version.
+// If m is a tagged version, then Upgrade will return the latest tagged
+// version (with the same minor version number if -u=patch).
+// If m is a pseudo-version, then Upgrade returns the latest tagged version
+// only if that version has a time-stamp newer than m. This special case
+// prevents accidental downgrades when already using a pseudo-version
+// newer than the latest tagged version.
+//
+// If none of the above cases apply, then Upgrade returns m.
+func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
+ // Allow pkg@vers on the command line to override the upgrade choice v.
+ // If q's version is < m.Version, then we're going to downgrade anyway,
+ // and it's cleaner to avoid moving back and forth and picking up
+ // extraneous other newer dependencies.
+ // If q's version is > m.Version, then we're going to upgrade past
+ // m.Version anyway, and again it's cleaner to avoid moving back and forth
+ // picking up extraneous other newer dependencies.
+ if q := u.cmdline[m.Path]; q != nil {
+ return q.m, nil
+ }
+
+ if !u.upgrade[m.Path] {
+ // Not involved in upgrade. Leave alone.
+ return m, nil
+ }
+
+ // Run query required by upgrade semantics.
+ // Note that Query "latest" is not the same as using repo.Latest,
+ // which may return a pseudoversion for the latest commit.
+ // Query "latest" returns the newest tagged version or the newest
+ // prerelease version if there are no non-prereleases, or repo.Latest
+ // if there aren't any tagged versions.
+ // If we're querying "upgrade" or "patch", Query will compare the current
+ // version against the chosen version and will return the current version
+ // if it is newer.
+ info, err := modload.Query(context.TODO(), m.Path, string(getU), m.Version, modload.CheckAllowed)
+ if err != nil {
+ // Report error but return m, to let version selection continue.
+ // (Reporting the error will fail the command at the next base.ExitIfErrors.)
+
+ // Special case: if the error is for m.Version itself and m.Version has a
+ // replacement, then keep it and don't report the error: the fact that the
+ // version is invalid is likely the reason it was replaced to begin with.
+ var vErr *module.InvalidVersionError
+ if errors.As(err, &vErr) && vErr.Version == m.Version && modload.Replacement(m).Path != "" {
+ return m, nil
+ }
+
+ // Special case: if the error is "no matching versions" then don't
+ // even report the error. Because Query does not consider pseudo-versions,
+ // it may happen that we have a pseudo-version but during -u=patch
+ // the query v0.0 matches no versions (not even the one we're using).
+ var noMatch *modload.NoMatchingVersionError
+ if !errors.As(err, &noMatch) {
+ base.Errorf("go get: upgrading %s@%s: %v", m.Path, m.Version, err)
+ }
+ return m, nil
+ }
+
+ if info.Version != m.Version {
+ logOncef("go: %s %s => %s", m.Path, getU, info.Version)
+ }
+ return module.Version{Path: m.Path, Version: info.Version}, nil
+}
+
+// buildListForLostUpgrade returns the build list for the module graph
+// rooted at lost. Unlike mvs.BuildList, the target module (lost) is not
+// treated specially. The returned build list may contain a newer version
+// of lost.
+//
+// buildListForLostUpgrade is used after a downgrade has removed a module
+// requested at a specific version. This helps us understand the requirements
+// implied by each downgrade.
+func buildListForLostUpgrade(lost module.Version, reqs mvs.Reqs) ([]module.Version, error) {
+ return mvs.BuildList(lostUpgradeRoot, &lostUpgradeReqs{Reqs: reqs, lost: lost})
+}
+
+var lostUpgradeRoot = module.Version{Path: "lost-upgrade-root", Version: ""}
+
+type lostUpgradeReqs struct {
+ mvs.Reqs
+ lost module.Version
+}
+
+func (r *lostUpgradeReqs) Required(mod module.Version) ([]module.Version, error) {
+ if mod == lostUpgradeRoot {
+ return []module.Version{r.lost}, nil
+ }
+ return r.Reqs.Required(mod)
+}