cmd/go/internal/modcmd: implement -vendor, dropping 'vgo vendor'

Change-Id: If86e55b57e6fe6fc8fbddeb3e031f68c9130f0e2
Reviewed-on: https://go-review.googlesource.com/118876
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/vendor/cmd/go/internal/modcmd/mod.go b/vendor/cmd/go/internal/modcmd/mod.go
index 194ba02..55c7a61 100644
--- a/vendor/cmd/go/internal/modcmd/mod.go
+++ b/vendor/cmd/go/internal/modcmd/mod.go
@@ -18,12 +18,14 @@
 )
 
 var CmdMod = &base.Command{
-	UsageLine: "mod [maintenance flags]",
+	UsageLine: "mod [-v] [maintenance flags]",
 	Short:     "module maintenance",
 	Long: `
 Mod performs module maintenance operations as specified by the
 following flags, which may be combined.
 
+The -v flag enables additional output about operations performed.
+
 The first group of operations provide low-level editing operations
 for manipulating go.mod from the command line or in scripts or
 other tools. They read only go.mod itself; they do not look up any
@@ -146,6 +148,8 @@
 }
 
 var (
+	modV = CmdMod.Flag.Bool("v", false, "")
+
 	modFmt      = CmdMod.Flag.Bool("fmt", false, "")
 	modFix      = CmdMod.Flag.Bool("fix", false, "")
 	modJSON     = CmdMod.Flag.Bool("json", false, "")
@@ -244,7 +248,7 @@
 		}
 		vgo.WriteGoMod()
 		if *modVendor {
-			panic("TODO: move runVendor over")
+			runVendor()
 		}
 	}
 
diff --git a/vendor/cmd/go/internal/vgo/vendor.go b/vendor/cmd/go/internal/modcmd/vendor.go
similarity index 73%
rename from vendor/cmd/go/internal/vgo/vendor.go
rename to vendor/cmd/go/internal/modcmd/vendor.go
index cbdf084..441aacf 100644
--- a/vendor/cmd/go/internal/vgo/vendor.go
+++ b/vendor/cmd/go/internal/modcmd/vendor.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package vgo
+package modcmd
 
 import (
 	"bytes"
@@ -15,48 +15,23 @@
 
 	"cmd/go/internal/base"
 	"cmd/go/internal/module"
+	"cmd/go/internal/vgo"
 )
 
-var CmdVendor = &base.Command{
-	UsageLine: "vendor [-v]",
-	Short:     "vendor dependencies of current module",
-	Long: `
-Vendor resets the module's vendor directory to include all
-packages needed to build and test all packages in the module
-and their dependencies.
-
-The -v flag causes vendor to print to standard error the
-module paths of the modules processed and the import paths
-of the packages copied.
-	`,
-}
-
-var vendorV = CmdVendor.Flag.Bool("v", false, "")
 var copiedDir map[string]bool
 
-func init() {
-	CmdVendor.Run = runVendor // break init cycle
-}
+func runVendor() {
+	pkgs := vgo.ImportPaths([]string{"ALL"})
 
-func runVendor(cmd *base.Command, args []string) {
-	if Init(); !Enabled() {
-		base.Fatalf("vgo vendor: cannot use -m outside module")
-	}
-	if len(args) != 0 {
-		base.Fatalf("vgo vendor: vendor takes no arguments")
-	}
-	InitMod()
-	pkgs := ImportPaths([]string{"ALL"})
-
-	vdir := filepath.Join(ModRoot, "vendor")
+	vdir := filepath.Join(vgo.ModRoot, "vendor")
 	if err := os.RemoveAll(vdir); err != nil {
 		base.Fatalf("vgo vendor: %v", err)
 	}
 
 	modpkgs := make(map[module.Version][]string)
 	for _, pkg := range pkgs {
-		m := pkgmod[pkg]
-		if m == Target {
+		m := vgo.PackageModule(pkg)
+		if m == vgo.Target {
 			continue
 		}
 		modpkgs[m] = append(modpkgs[m], pkg)
@@ -64,22 +39,22 @@
 
 	var buf bytes.Buffer
 	copiedDir = make(map[string]bool)
-	for _, m := range buildList[1:] {
+	for _, m := range vgo.BuildList()[1:] {
 		if pkgs := modpkgs[m]; len(pkgs) > 0 {
 			repl := ""
-			if r := replaced(m); r != nil {
-				repl = " => " + r.New.Path
-				if r.New.Version != "" {
-					repl += " " + r.New.Version
+			if r := vgo.Replacement(m); r.Path != "" {
+				repl = " => " + r.Path
+				if r.Version != "" {
+					repl += " " + r.Version
 				}
 			}
 			fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl)
-			if *vendorV {
+			if *modV {
 				fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl)
 			}
 			for _, pkg := range pkgs {
 				fmt.Fprintf(&buf, "%s\n", pkg)
-				if *vendorV {
+				if *modV {
 					fmt.Fprintf(os.Stderr, "%s\n", pkg)
 				}
 				vendorPkg(vdir, pkg)
@@ -96,20 +71,20 @@
 }
 
 func vendorPkg(vdir, pkg string) {
-	realPath := importmap[pkg]
-	if realPath != pkg && importmap[realPath] != "" {
+	realPath := vgo.ImportMap(pkg)
+	if realPath != pkg && vgo.ImportMap(realPath) != "" {
 		fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg)
 	}
 
 	dst := filepath.Join(vdir, pkg)
-	src := pkgdir[realPath]
+	src := vgo.PackageDir(realPath)
 	if src == "" {
 		fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath)
 	}
 
 	copyDir(dst, src, false)
-	if mod, ok := pkgmod[pkg]; ok {
-		copyTestdata(mod.Path, pkg, dst, src)
+	if m := vgo.PackageModule(realPath); m.Path != "" {
+		copyTestdata(m.Path, realPath, dst, src)
 	}
 }
 
diff --git a/vendor/cmd/go/internal/vgo/build.go b/vendor/cmd/go/internal/vgo/build.go
index ba10309..c48acf5 100644
--- a/vendor/cmd/go/internal/vgo/build.go
+++ b/vendor/cmd/go/internal/vgo/build.go
@@ -76,14 +76,14 @@
 		if mv == "" {
 			mv = "(devel)"
 		}
-		r := replaced(mod)
+		r := Replacement(mod)
 		h := ""
-		if r == nil {
+		if r.Path == "" {
 			h = "\t" + findModHash(mod)
 		}
 		fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mod.Version, h)
-		if r := replaced(mod); r != nil {
-			fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.New.Path, r.New.Version, findModHash(r.New))
+		if r.Path != "" {
+			fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.Path, r.Version, findModHash(r))
 		}
 	}
 	return buf.String()
diff --git a/vendor/cmd/go/internal/vgo/fetch.go b/vendor/cmd/go/internal/vgo/fetch.go
index 7cec65a..fba60dc 100644
--- a/vendor/cmd/go/internal/vgo/fetch.go
+++ b/vendor/cmd/go/internal/vgo/fetch.go
@@ -26,15 +26,15 @@
 // holding the root of mod's source tree.
 // It downloads the module if needed.
 func fetch(mod module.Version) (dir string, err error) {
-	if r := replaced(mod); r != nil {
-		if r.New.Version == "" {
-			dir = r.New.Path
+	if r := Replacement(mod); r.Path != "" {
+		if r.Version == "" {
+			dir = r.Path
 			if !filepath.IsAbs(dir) {
 				dir = filepath.Join(ModRoot, dir)
 			}
 			return dir, nil
 		}
-		mod = r.New
+		mod = r
 	}
 
 	modpath := mod.Path + "@" + mod.Version
diff --git a/vendor/cmd/go/internal/vgo/list.go b/vendor/cmd/go/internal/vgo/list.go
index c6656c2..d3511c1 100644
--- a/vendor/cmd/go/internal/vgo/list.go
+++ b/vendor/cmd/go/internal/vgo/list.go
@@ -67,8 +67,8 @@
 			v = "-"
 		}
 		rows = append(rows, []string{mod.Path, v})
-		if r := replaced(mod); r != nil {
-			rows = append(rows, []string{" => " + r.New.Path, r.New.Version})
+		if r := Replacement(mod); r.Path != "" {
+			rows = append(rows, []string{" => " + r.Path, r.Version})
 		}
 	}
 	printTable(w, rows)
diff --git a/vendor/cmd/go/internal/vgo/load.go b/vendor/cmd/go/internal/vgo/load.go
index 09dd0d5..30349cc 100644
--- a/vendor/cmd/go/internal/vgo/load.go
+++ b/vendor/cmd/go/internal/vgo/load.go
@@ -78,9 +78,30 @@
 	return buildList
 }
 
-// PkgMod returns a map from package import path to the module supplying that package.
-func PkgMod() map[string]module.Version {
-	return pkgmod
+// BuildList returns the module build list,
+// typically constructed by a previous call to
+// LoadBuildList or ImportPaths.
+func BuildList() []module.Version {
+	return buildList
+}
+
+// ImportMap returns the actual package import path
+// for an import path found in source code.
+// If the given import path does not appear in the source code
+// for the packages that have been loaded, ImportMap returns the empty string.
+func ImportMap(path string) string {
+	return importmap[path]
+}
+
+// PackageDir returns the directory containing the source code
+// for the package named by the import path.
+func PackageDir(path string) string {
+	return pkgdir[path]
+}
+
+// PackageModule returns the module providing the package named by the import path.
+func PackageModule(path string) module.Version {
+	return pkgmod[path]
 }
 
 func ImportPaths(args []string) []string {
@@ -321,14 +342,20 @@
 	return ""
 }
 
-func replaced(mod module.Version) *modfile.Replace {
+// Replacement the replacement for mod, if any, from go.mod.
+// If there is no replacement for mod, Replacement returns
+// a module.Version with Path == "".
+func Replacement(mod module.Version) module.Version {
 	var found *modfile.Replace
 	for _, r := range modFile.Replace {
 		if r.Old == mod {
 			found = r // keep going
 		}
 	}
-	return found
+	if found == nil {
+		return module.Version{}
+	}
+	return found.New
 }
 
 func importPathInModule(path, mpath string) bool {
@@ -421,10 +448,10 @@
 	}
 
 	origPath := mod.Path
-	if repl := replaced(mod); repl != nil {
-		if repl.New.Version == "" {
+	if repl := Replacement(mod); repl.Path != "" {
+		if repl.Version == "" {
 			// TODO: need to slip the new version into the tags list etc.
-			dir := repl.New.Path
+			dir := repl.Path
 			if !filepath.IsAbs(dir) {
 				dir = filepath.Join(ModRoot, dir)
 			}
@@ -443,7 +470,7 @@
 			}
 			return list, nil
 		}
-		mod = repl.New
+		mod = repl
 	}
 
 	if mod.Version == "none" {
diff --git a/vendor/cmd/go/main.go b/vendor/cmd/go/main.go
index 3f3518f..7327ef1 100644
--- a/vendor/cmd/go/main.go
+++ b/vendor/cmd/go/main.go
@@ -54,7 +54,6 @@
 		run.CmdRun,
 		test.CmdTest,
 		tool.CmdTool,
-		vgo.CmdVendor,
 		version.CmdVersion,
 		vet.CmdVet,
 
@@ -126,12 +125,15 @@
 	}
 
 	switch args[0] {
-	case "verify":
-		fmt.Fprintf(os.Stderr, "go verify is now go mod -verify\n")
-		os.Exit(2)
 	case "mod":
 		// Skip vgo.Init (which may insist on go.mod existing)
 		// so that go mod -init has a chance to write the file.
+	case "vendor":
+		fmt.Fprintf(os.Stderr, "go vendor is now go mod -vendor\n")
+		os.Exit(2)
+	case "verify":
+		fmt.Fprintf(os.Stderr, "go verify is now go mod -verify\n")
+		os.Exit(2)
 	default:
 		// Run vgo.Init so that each subcommand doesn't have to worry about it.
 		// Also install the vgo get command instead of the old go get command in vgo mode.
diff --git a/vendor/cmd/go/vgo_test.go b/vendor/cmd/go/vgo_test.go
index 10e0d6b..b659c28 100644
--- a/vendor/cmd/go/vgo_test.go
+++ b/vendor/cmd/go/vgo_test.go
@@ -369,7 +369,7 @@
 
 	wd, _ := os.Getwd()
 	tg.cd(filepath.Join(wd, "testdata/vendormod"))
-	defer tg.must(os.RemoveAll(filepath.Join(wd, "testdata/vendormod/vendor")))
+	defer os.RemoveAll(filepath.Join(wd, "testdata/vendormod/vendor"))
 
 	tg.run("-vgo", "list", "-m")
 	tg.grepStdout(`^x`, "expected to see module x")
@@ -385,7 +385,7 @@
 	tg.run("-vgo", "list", "-f={{.Dir}}", "x")
 	tg.grepStdout(`vendormod[/\\]x$`, "expected x in vendormod/x")
 
-	tg.run("-vgo", "vendor", "-v")
+	tg.run("-vgo", "mod", "-vendor", "-v")
 	tg.grepStderr(`^# x v1.0.0 => ./x`, "expected to see module x with replacement")
 	tg.grepStderr(`^x`, "expected to see package x")
 	tg.grepStderr(`^# y v1.0.0 => ./y`, "expected to see module y with replacement")
@@ -531,7 +531,7 @@
 `), 0666))
 	tg.must(ioutil.WriteFile(tg.path("x/x.go"), []byte(`package x`), 0666))
 	tg.cd(tg.path("x"))
-	tg.run("-vgo", "verify")
+	tg.run("-vgo", "mod", "-verify")
 	tg.mustNotExist(filepath.Join(tg.path("gp"), "/src/v/cache/github.com/pkg/errors/@v/v0.8.0.zip"))
 	tg.mustNotExist(filepath.Join(tg.path("gp"), "/src/v/github.com/pkg"))
 }
@@ -545,6 +545,6 @@
 	tg.must(ioutil.WriteFile(tg.path("x/main.go"), []byte(`package x`), 0666))
 	tg.must(ioutil.WriteFile(tg.path("x/go.mod"), []byte(`module x`), 0666))
 	tg.cd(tg.path("x"))
-	tg.run("-vgo", "vendor")
+	tg.run("-vgo", "mod", "-vendor")
 	tg.grepStderr("vgo: no dependencies to vendor", "print vendor info")
 }