cmd/go/internal/get: export RepoRootForImportPath for use by modfetch

Because we've decided to keep support for the old meta tags
and hosting repository special cases, it makes sense for
package modfetch to import package get to translate an
import path to the enclosing repository root.

This CL exports RepoRootForImportPath from package get
for use in package modfetch. It also adjusts the import graph
to make it possible for modfetch to import get.
Before this CL, the graph has get -> load -> vgo -> modfetch,
so modfetch cannot import get. This CL reverses the load -> vgo
so that vgo is once again a higher-level package, and then
there's no problem with modfetch importing get.
Eventually some of the details currently isolated to package vgo
will move out to the packages that need them, and then we
won't have these awkward func values being set during
initialization.

This CL does not make modfetch import get; it only does the
preparation necessary to enable that.

Change-Id: I985964c40be3d3e7bd34be9d939c2fb8c76107fd
Reviewed-on: https://go-review.googlesource.com/119675
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/vendor/cmd/go/internal/get/discovery.go b/vendor/cmd/go/internal/get/discovery.go
index 97aa1d7..6ba5c09 100644
--- a/vendor/cmd/go/internal/get/discovery.go
+++ b/vendor/cmd/go/internal/get/discovery.go
@@ -28,7 +28,7 @@
 
 // parseMetaGoImports returns meta imports from the HTML in r.
 // Parsing ends at the end of the <head> section or the beginning of the <body>.
-func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
+func parseMetaGoImports(r io.Reader, mod ModuleMode) (imports []metaImport, err error) {
 	d := xml.NewDecoder(r)
 	d.CharsetReader = charsetReader
 	d.Strict = false
@@ -39,13 +39,13 @@
 			if err == io.EOF || len(imports) > 0 {
 				err = nil
 			}
-			return
+			break
 		}
 		if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
-			return
+			break
 		}
 		if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
-			return
+			break
 		}
 		e, ok := t.(xml.StartElement)
 		if !ok || !strings.EqualFold(e.Name.Local, "meta") {
@@ -55,13 +55,6 @@
 			continue
 		}
 		if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
-			// Ignore VCS type "mod", which is new Go modules.
-			// This code is for old go get and must ignore the new mod lines.
-			// Otherwise matchGoImport will complain about two
-			// different metaImport lines for the same Prefix.
-			if f[1] == "mod" {
-				continue
-			}
 			imports = append(imports, metaImport{
 				Prefix:   f[0],
 				VCS:      f[1],
@@ -69,6 +62,27 @@
 			})
 		}
 	}
+
+	// Extract mod entries if we are paying attention to them.
+	var list []metaImport
+	var have map[string]bool
+	if mod == PreferMod {
+		have = make(map[string]bool)
+		for _, m := range imports {
+			if m.VCS == "mod" {
+				have[m.Prefix] = true
+				list = append(list, m)
+			}
+		}
+	}
+
+	// Append non-mod entries, ignoring those superseded by a mod entry.
+	for _, m := range imports {
+		if m.VCS != "mod" && !have[m.Prefix] {
+			list = append(list, m)
+		}
+	}
+	return list, nil
 }
 
 // attrValue returns the attribute value for the case-insensitive key
diff --git a/vendor/cmd/go/internal/get/get.go b/vendor/cmd/go/internal/get/get.go
index 6eabc4e..eeae4b1 100644
--- a/vendor/cmd/go/internal/get/get.go
+++ b/vendor/cmd/go/internal/get/get.go
@@ -18,7 +18,6 @@
 	"cmd/go/internal/load"
 	"cmd/go/internal/search"
 	"cmd/go/internal/str"
-	"cmd/go/internal/vgo"
 	"cmd/go/internal/web"
 	"cmd/go/internal/work"
 )
@@ -92,7 +91,8 @@
 }
 
 func runGet(cmd *base.Command, args []string) {
-	if vgo.Enabled() {
+	if load.VgoLookup != nil {
+		// Should not happen: main.go should install the separate vgo-enabled get code.
 		base.Fatalf("go get: vgo not implemented")
 	}
 
@@ -402,16 +402,16 @@
 			}
 			repo = remote
 			if !*getF && err == nil {
-				if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
-					repo := rr.repo
+				if rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security); err == nil {
+					repo := rr.Repo
 					if rr.vcs.resolveRepo != nil {
 						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
 						if err == nil {
 							repo = resolved
 						}
 					}
-					if remote != repo && rr.isCustom {
-						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
+					if remote != repo && rr.IsCustom {
+						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote)
 					}
 				}
 			}
@@ -419,11 +419,11 @@
 	} else {
 		// Analyze the import path to determine the version control system,
 		// repository, and the import path for the root of the repository.
-		rr, err := repoRootForImportPath(p.ImportPath, security)
+		rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security)
 		if err != nil {
 			return err
 		}
-		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
+		vcs, repo, rootPath = rr.vcs, rr.Repo, rr.Root
 	}
 	if !blindRepo && !vcs.isSecure(repo) && !*getInsecure {
 		return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
diff --git a/vendor/cmd/go/internal/get/pkg_test.go b/vendor/cmd/go/internal/get/pkg_test.go
index 1179d86..2f61365 100644
--- a/vendor/cmd/go/internal/get/pkg_test.go
+++ b/vendor/cmd/go/internal/get/pkg_test.go
@@ -33,15 +33,18 @@
 
 var parseMetaGoImportsTests = []struct {
 	in  string
+	mod ModuleMode
 	out []metaImport
 }{
 	{
 		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+		IgnoreMod,
 		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
 	},
 	{
 		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
 		<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+		IgnoreMod,
 		[]metaImport{
 			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
 			{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
@@ -50,6 +53,7 @@
 	{
 		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
 		<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">`,
+		IgnoreMod,
 		[]metaImport{
 			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
 		},
@@ -57,35 +61,48 @@
 	{
 		`<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
 		<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+		IgnoreMod,
 		[]metaImport{
 			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
 		},
 	},
 	{
+		`<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
+		<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+		PreferMod,
+		[]metaImport{
+			{"foo/bar", "mod", "http://github.com/rsc/baz/quux"},
+		},
+	},
+	{
 		`<head>
 		<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
 		</head>`,
+		IgnoreMod,
 		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
 	},
 	{
 		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
 		<body>`,
+		IgnoreMod,
 		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
 	},
 	{
 		`<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+		IgnoreMod,
 		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
 	},
 	{
 		// XML doesn't like <div style=position:relative>.
 		`<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
+		IgnoreMod,
 		[]metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
 	},
 }
 
 func TestParseMetaGoImports(t *testing.T) {
 	for i, tt := range parseMetaGoImportsTests {
-		out, err := parseMetaGoImports(strings.NewReader(tt.in))
+		out, err := parseMetaGoImports(strings.NewReader(tt.in), tt.mod)
 		if err != nil {
 			t.Errorf("test#%d: %v", i, err)
 			continue
diff --git a/vendor/cmd/go/internal/get/vcs.go b/vendor/cmd/go/internal/get/vcs.go
index 45fc69a..73b3dd0 100644
--- a/vendor/cmd/go/internal/get/vcs.go
+++ b/vendor/cmd/go/internal/get/vcs.go
@@ -624,27 +624,29 @@
 	return nil
 }
 
-// repoRoot represents a version control system, a repo, and a root of
-// where to put it on disk.
-type repoRoot struct {
-	vcs *vcsCmd
+// RepoRoot describes the repository root for a tree of source code.
+type RepoRoot struct {
+	Repo     string // repository URL, including scheme
+	Root     string // import path corresponding to root of repo
+	IsCustom bool   // defined by served <meta> tags (as opposed to hard-coded pattern)
+	VCS      string // vcs type ("mod", "git", ...)
 
-	// repo is the repository URL, including scheme
-	repo string
-
-	// root is the import path corresponding to the root of the
-	// repository
-	root string
-
-	// isCustom is true for custom import paths (those defined by HTML meta tags)
-	isCustom bool
+	vcs *vcsCmd // internal: vcs command access
 }
 
 var httpPrefixRE = regexp.MustCompile(`^https?:`)
 
-// repoRootForImportPath analyzes importPath to determine the
+// ModuleMode specifies whether to prefer modules when looking up code sources.
+type ModuleMode int
+
+const (
+	IgnoreMod ModuleMode = iota
+	PreferMod
+)
+
+// RepoRootForImportPath analyzes importPath to determine the
 // version control system, and code repository to use.
-func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) {
+func RepoRootForImportPath(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
 	rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
 	if err == errUnknownSite {
 		// If there are wildcards, look up the thing before the wildcard,
@@ -654,7 +656,7 @@
 		if i := strings.Index(lookup, "/.../"); i >= 0 {
 			lookup = lookup[:i]
 		}
-		rr, err = repoRootForImportDynamic(lookup, security)
+		rr, err = repoRootForImportDynamic(lookup, mod, security)
 		if err != nil {
 			err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
 		}
@@ -667,7 +669,7 @@
 		}
 	}
 
-	if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
+	if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") {
 		// Do not allow wildcards in the repo root.
 		rr = nil
 		err = fmt.Errorf("cannot expand ... in %q", importPath)
@@ -680,7 +682,7 @@
 // repoRootFromVCSPaths attempts to map importPath to a repoRoot
 // using the mappings defined in vcsPaths.
 // If scheme is non-empty, that scheme is forced.
-func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
+func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) {
 	// A common error is to use https://packagepath because that's what
 	// hg and git require. Diagnose this helpfully.
 	if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
@@ -740,21 +742,22 @@
 				}
 			}
 		}
-		rr := &repoRoot{
+		rr := &RepoRoot{
+			Repo: match["repo"],
+			Root: match["root"],
+			VCS:  vcs.cmd,
 			vcs:  vcs,
-			repo: match["repo"],
-			root: match["root"],
 		}
 		return rr, nil
 	}
 	return nil, errUnknownSite
 }
 
-// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
+// repoRootForImportDynamic finds a *RepoRoot for a custom domain that's not
 // statically known by repoRootForImportPathStatic.
 //
 // This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
-func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*repoRoot, error) {
+func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
 	slash := strings.Index(importPath, "/")
 	if slash < 0 {
 		slash = len(importPath)
@@ -772,7 +775,7 @@
 		return nil, fmt.Errorf(msg, err)
 	}
 	defer body.Close()
-	imports, err := parseMetaGoImports(body)
+	imports, err := parseMetaGoImports(body, mod)
 	if err != nil {
 		return nil, fmt.Errorf("parsing %s: %v", importPath, err)
 	}
@@ -799,7 +802,7 @@
 		}
 		urlStr0 := urlStr
 		var imports []metaImport
-		urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security)
+		urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, mod, security)
 		if err != nil {
 			return nil, err
 		}
@@ -812,15 +815,18 @@
 	if err := validateRepoRoot(mmi.RepoRoot); err != nil {
 		return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err)
 	}
-	rr := &repoRoot{
-		vcs:      vcsByCmd(mmi.VCS),
-		repo:     mmi.RepoRoot,
-		root:     mmi.Prefix,
-		isCustom: true,
-	}
-	if rr.vcs == nil {
+	vcs := vcsByCmd(mmi.VCS)
+	if vcs == nil && mmi.VCS != "mod" {
 		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
 	}
+
+	rr := &RepoRoot{
+		Repo:     mmi.RepoRoot,
+		Root:     mmi.Prefix,
+		IsCustom: true,
+		VCS:      mmi.VCS,
+		vcs:      vcs,
+	}
 	return rr, nil
 }
 
@@ -851,7 +857,7 @@
 // It is an error if no imports are found.
 // urlStr will still be valid if err != nil.
 // The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
-func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
+func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
 	setCache := func(res fetchResult) (fetchResult, error) {
 		fetchCacheMu.Lock()
 		defer fetchCacheMu.Unlock()
@@ -871,7 +877,7 @@
 		if err != nil {
 			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
 		}
-		imports, err := parseMetaGoImports(body)
+		imports, err := parseMetaGoImports(body, mod)
 		if err != nil {
 			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
 		}
diff --git a/vendor/cmd/go/internal/get/vcs_test.go b/vendor/cmd/go/internal/get/vcs_test.go
index 1ce9b73..142701a 100644
--- a/vendor/cmd/go/internal/get/vcs_test.go
+++ b/vendor/cmd/go/internal/get/vcs_test.go
@@ -16,43 +16,43 @@
 	"cmd/go/internal/web"
 )
 
-// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
+// Test that RepoRootForImportPath determines the correct RepoRoot for a given importPath.
 // TODO(cmang): Add tests for SVN and BZR.
 func TestRepoRootForImportPath(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
 	tests := []struct {
 		path string
-		want *repoRoot
+		want *RepoRoot
 	}{
 		{
 			"github.com/golang/groupcache",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://github.com/golang/groupcache",
+				Repo: "https://github.com/golang/groupcache",
 			},
 		},
 		// Unicode letters in directories (issue 18660).
 		{
 			"github.com/user/unicode/испытание",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://github.com/user/unicode",
+				Repo: "https://github.com/user/unicode",
 			},
 		},
 		// IBM DevOps Services tests
 		{
 			"hub.jazz.net/git/user1/pkgname",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://hub.jazz.net/git/user1/pkgname",
+				Repo: "https://hub.jazz.net/git/user1/pkgname",
 			},
 		},
 		{
 			"hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://hub.jazz.net/git/user1/pkgname",
+				Repo: "https://hub.jazz.net/git/user1/pkgname",
 			},
 		},
 		{
@@ -91,9 +91,9 @@
 		},
 		{
 			"hub.jazz.net/git/user/pkg.name",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://hub.jazz.net/git/user/pkg.name",
+				Repo: "https://hub.jazz.net/git/user/pkg.name",
 			},
 		},
 		// User names cannot have uppercase letters
@@ -104,9 +104,9 @@
 		// OpenStack tests
 		{
 			"git.openstack.org/openstack/swift",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://git.openstack.org/openstack/swift",
+				Repo: "https://git.openstack.org/openstack/swift",
 			},
 		},
 		// Trailing .git is less preferred but included for
@@ -114,16 +114,16 @@
 		// be compilable on both old and new go
 		{
 			"git.openstack.org/openstack/swift.git",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://git.openstack.org/openstack/swift.git",
+				Repo: "https://git.openstack.org/openstack/swift.git",
 			},
 		},
 		{
 			"git.openstack.org/openstack/swift/go/hummingbird",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://git.openstack.org/openstack/swift",
+				Repo: "https://git.openstack.org/openstack/swift",
 			},
 		},
 		{
@@ -150,23 +150,23 @@
 		},
 		{
 			"git.apache.org/package-name.git",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://git.apache.org/package-name.git",
+				Repo: "https://git.apache.org/package-name.git",
 			},
 		},
 		{
 			"git.apache.org/package-name_2.x.git/path/to/lib",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsGit,
-				repo: "https://git.apache.org/package-name_2.x.git",
+				Repo: "https://git.apache.org/package-name_2.x.git",
 			},
 		},
 		{
 			"chiselapp.com/user/kyle/repository/fossilgg",
-			&repoRoot{
+			&RepoRoot{
 				vcs:  vcsFossil,
-				repo: "https://chiselapp.com/user/kyle/repository/fossilgg",
+				Repo: "https://chiselapp.com/user/kyle/repository/fossilgg",
 			},
 		},
 		{
@@ -181,21 +181,21 @@
 	}
 
 	for _, test := range tests {
-		got, err := repoRootForImportPath(test.path, web.Secure)
+		got, err := RepoRootForImportPath(test.path, IgnoreMod, web.Secure)
 		want := test.want
 
 		if want == nil {
 			if err == nil {
-				t.Errorf("repoRootForImportPath(%q): Error expected but not received", test.path)
+				t.Errorf("RepoRootForImportPath(%q): Error expected but not received", test.path)
 			}
 			continue
 		}
 		if err != nil {
-			t.Errorf("repoRootForImportPath(%q): %v", test.path, err)
+			t.Errorf("RepoRootForImportPath(%q): %v", test.path, err)
 			continue
 		}
-		if got.vcs.name != want.vcs.name || got.repo != want.repo {
-			t.Errorf("repoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
+		if got.vcs.name != want.vcs.name || got.Repo != want.Repo {
+			t.Errorf("RepoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.Repo, want.vcs, want.Repo)
 		}
 	}
 }
@@ -227,18 +227,18 @@
 			f.Close()
 		}
 
-		want := repoRoot{
+		want := RepoRoot{
 			vcs:  vcs,
-			root: path.Join("example.com", vcs.name),
+			Root: path.Join("example.com", vcs.name),
 		}
-		var got repoRoot
-		got.vcs, got.root, err = vcsFromDir(dir, tempDir)
+		var got RepoRoot
+		got.vcs, got.Root, err = vcsFromDir(dir, tempDir)
 		if err != nil {
 			t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
 			continue
 		}
-		if got.vcs.name != want.vcs.name || got.root != want.root {
-			t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.root, want.vcs, want.root)
+		if got.vcs.name != want.vcs.name || got.Root != want.Root {
+			t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.Root, want.vcs, want.Root)
 		}
 	}
 }
diff --git a/vendor/cmd/go/internal/load/pkg.go b/vendor/cmd/go/internal/load/pkg.go
index 400b338..0977825 100644
--- a/vendor/cmd/go/internal/load/pkg.go
+++ b/vendor/cmd/go/internal/load/pkg.go
@@ -25,7 +25,17 @@
 	"cmd/go/internal/modinfo"
 	"cmd/go/internal/search"
 	"cmd/go/internal/str"
-	"cmd/go/internal/vgo"
+)
+
+var (
+	// module (vgo) hooks; nil if vgo is disabled
+	VgoBinDir            func() string                                                   // return effective bin directory
+	VgoLookup            func(parentPath, path string) (dir, realPath string, err error) // lookup effective meaning of import
+	VgoPackageModuleInfo func(path string) *modinfo.ModulePublic                         // return module info for Package struct
+	VgoImportPaths       func(args []string) []string                                    // expand import paths
+	VgoPackageBuildInfo  func(main string, deps []string) string                         // return module info to embed in binary
+	VgoModInfoProg       func(info string) []byte                                        // wrap module info in .go code for binary
+	VgoAddImports        func([]string)                                                  // update go.mod to add modules for imports in these files
 )
 
 var IgnoreImports bool // control whether we ignore imports in packages
@@ -427,13 +437,13 @@
 	var vgoErr error
 	if isLocal {
 		importPath = dirToImportPath(filepath.Join(srcDir, path))
-	} else if vgo.Enabled() {
+	} else if VgoLookup != nil {
 		parentPath := ""
 		if parent != nil {
 			parentPath = parent.ImportPath
 		}
 		var p string
-		vgoDir, p, vgoErr = vgo.Lookup(parentPath, path)
+		vgoDir, p, vgoErr = VgoLookup(parentPath, path)
 		if vgoErr == nil {
 			importPath = p
 		}
@@ -479,8 +489,8 @@
 		bp.ImportPath = importPath
 		if cfg.GOBIN != "" {
 			bp.BinDir = cfg.GOBIN
-		} else if vgo.Enabled() {
-			bp.BinDir = vgo.BinDir()
+		} else if VgoBinDir != nil {
+			bp.BinDir = VgoBinDir()
 		}
 		if vgoDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
 			!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
@@ -569,12 +579,12 @@
 // If vendor expansion doesn't trigger, then the path is also subject to
 // Go 1.11 vgo legacy conversion (golang.org/issue/25069).
 func ResolveImportPath(parent *Package, path string) (found string) {
-	if vgo.Enabled() {
+	if VgoLookup != nil {
 		parentPath := ""
 		if parent != nil {
 			parentPath = parent.ImportPath
 		}
-		if _, p, e := vgo.Lookup(parentPath, path); e == nil {
+		if _, p, e := VgoLookup(parentPath, path); e == nil {
 			return p
 		}
 		return path
@@ -1156,8 +1166,8 @@
 			// Install cross-compiled binaries to subdirectories of bin.
 			elem = full
 		}
-		if p.Internal.Build.BinDir == "" && vgo.Enabled() {
-			p.Internal.Build.BinDir = vgo.BinDir()
+		if p.Internal.Build.BinDir == "" && VgoBinDir != nil {
+			p.Internal.Build.BinDir = VgoBinDir()
 		}
 		if p.Internal.Build.BinDir != "" {
 			// Install to GOBIN or bin of GOPATH entry.
@@ -1410,10 +1420,10 @@
 		return
 	}
 
-	if vgo.Enabled() {
-		p.Module = vgo.PackageModuleInfo(p.ImportPath)
+	if VgoPackageModuleInfo != nil {
+		p.Module = VgoPackageModuleInfo(p.ImportPath)
 		if p.Name == "main" {
-			p.Internal.BuildInfo = vgo.PackageBuildInfo(p.ImportPath, p.Deps)
+			p.Internal.BuildInfo = VgoPackageBuildInfo(p.ImportPath, p.Deps)
 		}
 	}
 }
@@ -1694,7 +1704,10 @@
 	if cmdlineMatchers == nil {
 		SetCmdlinePatterns(search.CleanImportPaths(args))
 	}
-	return vgo.ImportPaths(args)
+	if VgoImportPaths != nil {
+		return VgoImportPaths(args)
+	}
+	return search.ImportPaths(args)
 }
 
 func ImportPathsForGoGet(args []string) []string {
@@ -1789,7 +1802,9 @@
 	}
 	ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
 
-	vgo.AddImports(gofiles)
+	if VgoAddImports != nil {
+		VgoAddImports(gofiles)
+	}
 
 	var err error
 	if dir == "" {
@@ -1819,8 +1834,8 @@
 		}
 		if cfg.GOBIN != "" {
 			pkg.Target = filepath.Join(cfg.GOBIN, exe)
-		} else if vgo.Enabled() {
-			pkg.Target = filepath.Join(vgo.BinDir(), exe)
+		} else if VgoBinDir != nil {
+			pkg.Target = filepath.Join(VgoBinDir(), exe)
 		}
 	}
 
diff --git a/vendor/cmd/go/internal/vgo/get.go b/vendor/cmd/go/internal/vgo/get.go
index ce632bf..6a12e06 100644
--- a/vendor/cmd/go/internal/vgo/get.go
+++ b/vendor/cmd/go/internal/vgo/get.go
@@ -12,6 +12,7 @@
 	"cmd/go/internal/module"
 	"cmd/go/internal/mvs"
 	"cmd/go/internal/semver"
+	"cmd/go/internal/work"
 )
 
 var CmdGet = &base.Command{
@@ -39,6 +40,7 @@
 
 func init() {
 	CmdGet.Run = runGet // break init loop
+	work.AddBuildFlags(CmdGet)
 }
 
 func runGet(cmd *base.Command, args []string) {
@@ -143,9 +145,6 @@
 	WriteGoMod()
 
 	if len(args) > 0 {
-		InstallHook(args)
+		work.CmdInstall.Run(work.CmdInstall, args)
 	}
 }
-
-// Call into "go install". Set by internal/work, which imports us.
-var InstallHook func([]string)
diff --git a/vendor/cmd/go/internal/vgo/init.go b/vendor/cmd/go/internal/vgo/init.go
index f0ff6f7..94741bb 100644
--- a/vendor/cmd/go/internal/vgo/init.go
+++ b/vendor/cmd/go/internal/vgo/init.go
@@ -8,6 +8,7 @@
 	"bytes"
 	"cmd/go/internal/base"
 	"cmd/go/internal/cfg"
+	"cmd/go/internal/load"
 	"cmd/go/internal/modconv"
 	"cmd/go/internal/modfetch"
 	"cmd/go/internal/modfetch/codehost"
@@ -147,6 +148,14 @@
 	}
 
 	enabled = true
+	load.VgoBinDir = BinDir
+	load.VgoLookup = Lookup
+	load.VgoPackageModuleInfo = PackageModuleInfo
+	load.VgoImportPaths = ImportPaths
+	load.VgoPackageBuildInfo = PackageBuildInfo
+	load.VgoModInfoProg = ModInfoProg
+	load.VgoAddImports = AddImports
+
 	search.SetModRoot(ModRoot)
 }
 
diff --git a/vendor/cmd/go/internal/work/exec.go b/vendor/cmd/go/internal/work/exec.go
index 6b97356..1725493 100644
--- a/vendor/cmd/go/internal/work/exec.go
+++ b/vendor/cmd/go/internal/work/exec.go
@@ -30,15 +30,8 @@
 	"cmd/go/internal/cfg"
 	"cmd/go/internal/load"
 	"cmd/go/internal/str"
-	"cmd/go/internal/vgo"
 )
 
-func init() {
-	vgo.InstallHook = func(args []string) {
-		CmdInstall.Run(CmdInstall, args)
-	}
-}
-
 // actionList returns the list of actions in the dag rooted at root
 // as visited in a depth-first post-order traversal.
 func actionList(root *Action) []*Action {
@@ -606,8 +599,8 @@
 		fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)
 	}
 
-	if p.Internal.BuildInfo != "" {
-		if err := b.writeFile(objdir+"_gomod_.go", vgo.ModInfoProg(p.Internal.BuildInfo)); err != nil {
+	if p.Internal.BuildInfo != "" && load.VgoModInfoProg != nil {
+		if err := b.writeFile(objdir+"_gomod_.go", load.VgoModInfoProg(p.Internal.BuildInfo)); err != nil {
 			return err
 		}
 		gofiles = append(gofiles, objdir+"_gomod_.go")
diff --git a/vendor/cmd/go/internal/work/init.go b/vendor/cmd/go/internal/work/init.go
index 41aecad..3cc3fae 100644
--- a/vendor/cmd/go/internal/work/init.go
+++ b/vendor/cmd/go/internal/work/init.go
@@ -9,7 +9,7 @@
 import (
 	"cmd/go/internal/base"
 	"cmd/go/internal/cfg"
-	"cmd/go/internal/vgo"
+	"cmd/go/internal/load"
 	"flag"
 	"fmt"
 	"os"
@@ -231,7 +231,7 @@
 		// ok
 	case "local", "vendor":
 		// ok but check for vgo
-		if !vgo.Enabled() {
+		if load.VgoLookup == nil {
 			base.Fatalf("build flag -getmode=%s only valid when using modules", cfg.BuildGetmode)
 		}
 	default:
diff --git a/vendor/cmd/go/main.go b/vendor/cmd/go/main.go
index cecd7d3..1190808 100644
--- a/vendor/cmd/go/main.go
+++ b/vendor/cmd/go/main.go
@@ -84,7 +84,6 @@
 
 	if vgo.MustBeVgo {
 		// If running as vgo or with -vgo, change get now to change help message.
-		work.AddBuildFlags(vgo.CmdGet)
 		*get.CmdGet = *vgo.CmdGet
 	}
 
@@ -144,7 +143,6 @@
 		vgo.Init()
 		if !vgo.MustBeVgo && vgo.Enabled() {
 			// Didn't do this above, so do it now.
-			work.AddBuildFlags(vgo.CmdGet)
 			*get.CmdGet = *vgo.CmdGet
 		}
 	}
diff --git a/vendor/cmd/go/vgo_test.go b/vendor/cmd/go/vgo_test.go
index 366e33c..ef911bc 100644
--- a/vendor/cmd/go/vgo_test.go
+++ b/vendor/cmd/go/vgo_test.go
@@ -590,7 +590,7 @@
 		require github.com/gorilla/mux v1.6.1
 	`), 0666))
 	tg.run("-vgo", "build")
-	tg.grepStderr("finding github.com/gorilla/mux v1.6.2", "find version 1.6.2")
+	tg.grepStderr("github.com/gorilla/mux v1.6.2", "find version 1.6.2")
 
 	tg.must(ioutil.WriteFile(tg.path("x/go.mod"), []byte(`
 		module x
@@ -598,7 +598,7 @@
 		require github.com/gorilla/mux v1.6.1
 	`), 0666))
 	tg.run("-vgo", "build")
-	tg.grepStderr("finding github.com/gorilla/mux v1.6.1", "find version 1.6.1")
+	tg.grepStderr("github.com/gorilla/mux v1.6.1", "find version 1.6.1")
 }
 
 func TestConvertLegacyConfig(t *testing.T) {