go/vcs: delete

This will also close issues 10159, 12079, 19362, and 22556
as 'not planned'.

Fixes golang/go#57051.

Change-Id: I1cc6851a60c554d2266b5c03b8c010270919f5be
Reviewed-on: https://go-review.googlesource.com/c/tools/+/505956
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
diff --git a/README.md b/README.md
index 0a2fcf1..4dbf6d6 100644
--- a/README.md
+++ b/README.md
@@ -62,12 +62,11 @@
 
 Numerous other packages provide more esoteric functionality.
 
-<!-- Some that didn't make the cut: 
+<!-- Some that didn't make the cut:
 
 golang.org/x/tools/benchmark/parse
 golang.org/x/tools/go/ast/astutil
 golang.org/x/tools/go/types/typeutil
-golang.org/x/tools/go/vcs
 golang.org/x/tools/playground
 golang.org/x/tools/present
 golang.org/x/tools/refactor/importgraph
diff --git a/go/vcs/discovery.go b/go/vcs/discovery.go
deleted file mode 100644
index 7d179bc..0000000
--- a/go/vcs/discovery.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2012 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 vcs
-
-import (
-	"encoding/xml"
-	"fmt"
-	"io"
-	"strings"
-)
-
-// charsetReader returns a reader for the given charset. Currently
-// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
-// error which is printed by go get, so the user can find why the package
-// wasn't downloaded if the encoding is not supported. Note that, in
-// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
-// greater than 0x7f are not rejected).
-func charsetReader(charset string, input io.Reader) (io.Reader, error) {
-	switch strings.ToLower(charset) {
-	case "ascii":
-		return input, nil
-	default:
-		return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
-	}
-}
-
-// parseMetaGoImports returns meta imports from the HTML in r.
-// Parsing ends at the end of the <head> section or the beginning of the <body>.
-//
-// This copy of cmd/go/internal/vcs.parseMetaGoImports always operates
-// in IgnoreMod ModuleMode.
-func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
-	d := xml.NewDecoder(r)
-	d.CharsetReader = charsetReader
-	d.Strict = false
-	var t xml.Token
-	for {
-		t, err = d.RawToken()
-		if err != nil {
-			if err == io.EOF || len(imports) > 0 {
-				err = nil
-			}
-			return
-		}
-		if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
-			return
-		}
-		if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
-			return
-		}
-		e, ok := t.(xml.StartElement)
-		if !ok || !strings.EqualFold(e.Name.Local, "meta") {
-			continue
-		}
-		if attrValue(e.Attr, "name") != "go-import" {
-			continue
-		}
-		if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
-			// Ignore VCS type "mod", which is applicable only in module mode.
-			if f[1] == "mod" {
-				continue
-			}
-			imports = append(imports, metaImport{
-				Prefix:   f[0],
-				VCS:      f[1],
-				RepoRoot: f[2],
-			})
-		}
-	}
-}
-
-// attrValue returns the attribute value for the case-insensitive key
-// `name', or the empty string if nothing is found.
-func attrValue(attrs []xml.Attr, name string) string {
-	for _, a := range attrs {
-		if strings.EqualFold(a.Name.Local, name) {
-			return a.Value
-		}
-	}
-	return ""
-}
diff --git a/go/vcs/env.go b/go/vcs/env.go
deleted file mode 100644
index 189210c..0000000
--- a/go/vcs/env.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2013 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 vcs
-
-import (
-	"os"
-	"strings"
-)
-
-// envForDir returns a copy of the environment
-// suitable for running in the given directory.
-// The environment is the current process's environment
-// but with an updated $PWD, so that an os.Getwd in the
-// child will be faster.
-func envForDir(dir string) []string {
-	env := os.Environ()
-	// Internally we only use rooted paths, so dir is rooted.
-	// Even if dir is not rooted, no harm done.
-	return mergeEnvLists([]string{"PWD=" + dir}, env)
-}
-
-// mergeEnvLists merges the two environment lists such that
-// variables with the same name in "in" replace those in "out".
-func mergeEnvLists(in, out []string) []string {
-NextVar:
-	for _, inkv := range in {
-		k := strings.SplitAfterN(inkv, "=", 2)[0]
-		for i, outkv := range out {
-			if strings.HasPrefix(outkv, k) {
-				out[i] = inkv
-				continue NextVar
-			}
-		}
-		out = append(out, inkv)
-	}
-	return out
-}
diff --git a/go/vcs/go.mod b/go/vcs/go.mod
deleted file mode 100644
index 74da6cb..0000000
--- a/go/vcs/go.mod
+++ /dev/null
@@ -1,7 +0,0 @@
-// Deprecated: This module contains one deprecated package.
-// See the package deprecation notice for more information.
-module golang.org/x/tools/go/vcs
-
-go 1.19
-
-require golang.org/x/sys v0.9.0
diff --git a/go/vcs/go.sum b/go/vcs/go.sum
deleted file mode 100644
index cb35c1f..0000000
--- a/go/vcs/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
-golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/go/vcs/http.go b/go/vcs/http.go
deleted file mode 100644
index 5836511..0000000
--- a/go/vcs/http.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2012 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 vcs
-
-import (
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"net/url"
-)
-
-// httpClient is the default HTTP client, but a variable so it can be
-// changed by tests, without modifying http.DefaultClient.
-var httpClient = http.DefaultClient
-
-// httpGET returns the data from an HTTP GET request for the given URL.
-func httpGET(url string) ([]byte, error) {
-	resp, err := httpClient.Get(url)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-	if resp.StatusCode != 200 {
-		return nil, fmt.Errorf("%s: %s", url, resp.Status)
-	}
-	b, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return nil, fmt.Errorf("%s: %v", url, err)
-	}
-	return b, nil
-}
-
-// httpsOrHTTP returns the body of either the importPath's
-// https resource or, if unavailable, the http resource.
-func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
-	fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
-		u, err := url.Parse(scheme + "://" + importPath)
-		if err != nil {
-			return "", nil, err
-		}
-		u.RawQuery = "go-get=1"
-		urlStr = u.String()
-		if Verbose {
-			log.Printf("Fetching %s", urlStr)
-		}
-		res, err = httpClient.Get(urlStr)
-		return
-	}
-	closeBody := func(res *http.Response) {
-		if res != nil {
-			res.Body.Close()
-		}
-	}
-	urlStr, res, err := fetch("https")
-	if err != nil || res.StatusCode != 200 {
-		if Verbose {
-			if err != nil {
-				log.Printf("https fetch failed.")
-			} else {
-				log.Printf("ignoring https fetch with status code %d", res.StatusCode)
-			}
-		}
-		closeBody(res)
-		urlStr, res, err = fetch("http")
-	}
-	if err != nil {
-		closeBody(res)
-		return "", nil, err
-	}
-	// Note: accepting a non-200 OK here, so people can serve a
-	// meta import in their http 404 page.
-	if Verbose {
-		log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
-	}
-	return urlStr, res.Body, nil
-}
diff --git a/go/vcs/vcs.go b/go/vcs/vcs.go
deleted file mode 100644
index 232177d..0000000
--- a/go/vcs/vcs.go
+++ /dev/null
@@ -1,764 +0,0 @@
-// Copyright 2012 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 vcs exposes functions for resolving import paths
-// and using version control systems, which can be used to
-// implement behavior similar to the standard "go get" command.
-//
-// Deprecated: Use the go list command with -json flag instead,
-// which implements up-to-date import path resolution behavior,
-// module support, and includes the latest security fixes.
-//
-// This package was a copy of internal code in package cmd/go/internal/get
-// before module support, modified to make the identifiers exported.
-// It was provided here for developers who wanted to write tools with similar semantics.
-// It needed to be manually kept in sync with upstream when changes were
-// made to cmd/go/internal/get, as tracked in go.dev/issue/11490.
-// By now, it has diverged significantly from upstream cmd/go/internal/get
-// behavior and will not receive any further updates.
-package vcs // import "golang.org/x/tools/go/vcs"
-
-import (
-	"bytes"
-	"encoding/json"
-	"errors"
-	"fmt"
-	exec "golang.org/x/sys/execabs"
-	"log"
-	"net/url"
-	"os"
-	"path/filepath"
-	"regexp"
-	"strconv"
-	"strings"
-)
-
-// Verbose enables verbose operation logging.
-var Verbose bool
-
-// ShowCmd controls whether VCS commands are printed.
-var ShowCmd bool
-
-// A Cmd describes how to use a version control system
-// like Mercurial, Git, or Subversion.
-type Cmd struct {
-	Name string
-	Cmd  string // name of binary to invoke command
-
-	CreateCmd   string // command to download a fresh copy of a repository
-	DownloadCmd string // command to download updates into an existing repository
-
-	TagCmd         []TagCmd // commands to list tags
-	TagLookupCmd   []TagCmd // commands to lookup tags before running tagSyncCmd
-	TagSyncCmd     string   // command to sync to specific tag
-	TagSyncDefault string   // command to sync to default tag
-
-	LogCmd string // command to list repository changelogs in an XML format
-
-	Scheme  []string
-	PingCmd string
-}
-
-// A TagCmd describes a command to list available tags
-// that can be passed to Cmd.TagSyncCmd.
-type TagCmd struct {
-	Cmd     string // command to list tags
-	Pattern string // regexp to extract tags from list
-}
-
-// vcsList lists the known version control systems
-var vcsList = []*Cmd{
-	vcsHg,
-	vcsGit,
-	vcsSvn,
-	vcsBzr,
-}
-
-// ByCmd returns the version control system for the given
-// command name (hg, git, svn, bzr).
-func ByCmd(cmd string) *Cmd {
-	for _, vcs := range vcsList {
-		if vcs.Cmd == cmd {
-			return vcs
-		}
-	}
-	return nil
-}
-
-// vcsHg describes how to use Mercurial.
-var vcsHg = &Cmd{
-	Name: "Mercurial",
-	Cmd:  "hg",
-
-	CreateCmd:   "clone -U {repo} {dir}",
-	DownloadCmd: "pull",
-
-	// We allow both tag and branch names as 'tags'
-	// for selecting a version.  This lets people have
-	// a go.release.r60 branch and a go1 branch
-	// and make changes in both, without constantly
-	// editing .hgtags.
-	TagCmd: []TagCmd{
-		{"tags", `^(\S+)`},
-		{"branches", `^(\S+)`},
-	},
-	TagSyncCmd:     "update -r {tag}",
-	TagSyncDefault: "update default",
-
-	LogCmd: "log --encoding=utf-8 --limit={limit} --template={template}",
-
-	Scheme:  []string{"https", "http", "ssh"},
-	PingCmd: "identify {scheme}://{repo}",
-}
-
-// vcsGit describes how to use Git.
-var vcsGit = &Cmd{
-	Name: "Git",
-	Cmd:  "git",
-
-	CreateCmd:   "clone {repo} {dir}",
-	DownloadCmd: "pull --ff-only",
-
-	TagCmd: []TagCmd{
-		// tags/xxx matches a git tag named xxx
-		// origin/xxx matches a git branch named xxx on the default remote repository
-		{"show-ref", `(?:tags|origin)/(\S+)$`},
-	},
-	TagLookupCmd: []TagCmd{
-		{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
-	},
-	TagSyncCmd:     "checkout {tag}",
-	TagSyncDefault: "checkout master",
-
-	Scheme:  []string{"git", "https", "http", "git+ssh"},
-	PingCmd: "ls-remote {scheme}://{repo}",
-}
-
-// vcsBzr describes how to use Bazaar.
-var vcsBzr = &Cmd{
-	Name: "Bazaar",
-	Cmd:  "bzr",
-
-	CreateCmd: "branch {repo} {dir}",
-
-	// Without --overwrite bzr will not pull tags that changed.
-	// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
-	DownloadCmd: "pull --overwrite",
-
-	TagCmd:         []TagCmd{{"tags", `^(\S+)`}},
-	TagSyncCmd:     "update -r {tag}",
-	TagSyncDefault: "update -r revno:-1",
-
-	Scheme:  []string{"https", "http", "bzr", "bzr+ssh"},
-	PingCmd: "info {scheme}://{repo}",
-}
-
-// vcsSvn describes how to use Subversion.
-var vcsSvn = &Cmd{
-	Name: "Subversion",
-	Cmd:  "svn",
-
-	CreateCmd:   "checkout {repo} {dir}",
-	DownloadCmd: "update",
-
-	// There is no tag command in subversion.
-	// The branch information is all in the path names.
-
-	LogCmd: "log --xml --limit={limit}",
-
-	Scheme:  []string{"https", "http", "svn", "svn+ssh"},
-	PingCmd: "info {scheme}://{repo}",
-}
-
-func (v *Cmd) String() string {
-	return v.Name
-}
-
-// run runs the command line cmd in the given directory.
-// keyval is a list of key, value pairs.  run expands
-// instances of {key} in cmd into value, but only after
-// splitting cmd into individual arguments.
-// If an error occurs, run prints the command line and the
-// command's combined stdout+stderr to standard error.
-// Otherwise run discards the command's output.
-func (v *Cmd) run(dir string, cmd string, keyval ...string) error {
-	_, err := v.run1(dir, cmd, keyval, true)
-	return err
-}
-
-// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
-func (v *Cmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
-	_, err := v.run1(dir, cmd, keyval, false)
-	return err
-}
-
-// runOutput is like run but returns the output of the command.
-func (v *Cmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
-	return v.run1(dir, cmd, keyval, true)
-}
-
-// run1 is the generalized implementation of run and runOutput.
-func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
-	m := make(map[string]string)
-	for i := 0; i < len(keyval); i += 2 {
-		m[keyval[i]] = keyval[i+1]
-	}
-	args := strings.Fields(cmdline)
-	for i, arg := range args {
-		args[i] = expand(m, arg)
-	}
-
-	_, err := exec.LookPath(v.Cmd)
-	if err != nil {
-		fmt.Fprintf(os.Stderr,
-			"go: missing %s command. See http://golang.org/s/gogetcmd\n",
-			v.Name)
-		return nil, err
-	}
-
-	cmd := exec.Command(v.Cmd, args...)
-	cmd.Dir = dir
-	cmd.Env = envForDir(cmd.Dir)
-	if ShowCmd {
-		fmt.Printf("cd %s\n", dir)
-		fmt.Printf("%s %s\n", v.Cmd, strings.Join(args, " "))
-	}
-	var buf bytes.Buffer
-	cmd.Stdout = &buf
-	cmd.Stderr = &buf
-	err = cmd.Run()
-	out := buf.Bytes()
-	if err != nil {
-		if verbose || Verbose {
-			fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.Cmd, strings.Join(args, " "))
-			os.Stderr.Write(out)
-		}
-		return nil, err
-	}
-	return out, nil
-}
-
-// Ping pings the repo to determine if scheme used is valid.
-// This repo must be pingable with this scheme and VCS.
-func (v *Cmd) Ping(scheme, repo string) error {
-	return v.runVerboseOnly(".", v.PingCmd, "scheme", scheme, "repo", repo)
-}
-
-// Create creates a new copy of repo in dir.
-// The parent of dir must exist; dir must not.
-func (v *Cmd) Create(dir, repo string) error {
-	return v.run(".", v.CreateCmd, "dir", dir, "repo", repo)
-}
-
-// CreateAtRev creates a new copy of repo in dir at revision rev.
-// The parent of dir must exist; dir must not.
-// rev must be a valid revision in repo.
-func (v *Cmd) CreateAtRev(dir, repo, rev string) error {
-	if err := v.Create(dir, repo); err != nil {
-		return err
-	}
-	return v.run(dir, v.TagSyncCmd, "tag", rev)
-}
-
-// Download downloads any new changes for the repo in dir.
-// dir must be a valid VCS repo compatible with v.
-func (v *Cmd) Download(dir string) error {
-	return v.run(dir, v.DownloadCmd)
-}
-
-// Tags returns the list of available tags for the repo in dir.
-// dir must be a valid VCS repo compatible with v.
-func (v *Cmd) Tags(dir string) ([]string, error) {
-	var tags []string
-	for _, tc := range v.TagCmd {
-		out, err := v.runOutput(dir, tc.Cmd)
-		if err != nil {
-			return nil, err
-		}
-		re := regexp.MustCompile(`(?m-s)` + tc.Pattern)
-		for _, m := range re.FindAllStringSubmatch(string(out), -1) {
-			tags = append(tags, m[1])
-		}
-	}
-	return tags, nil
-}
-
-// TagSync syncs the repo in dir to the named tag, which is either a
-// tag returned by Tags or the empty string (the default tag).
-// dir must be a valid VCS repo compatible with v and the tag must exist.
-func (v *Cmd) TagSync(dir, tag string) error {
-	if v.TagSyncCmd == "" {
-		return nil
-	}
-	if tag != "" {
-		for _, tc := range v.TagLookupCmd {
-			out, err := v.runOutput(dir, tc.Cmd, "tag", tag)
-			if err != nil {
-				return err
-			}
-			re := regexp.MustCompile(`(?m-s)` + tc.Pattern)
-			m := re.FindStringSubmatch(string(out))
-			if len(m) > 1 {
-				tag = m[1]
-				break
-			}
-		}
-	}
-	if tag == "" && v.TagSyncDefault != "" {
-		return v.run(dir, v.TagSyncDefault)
-	}
-	return v.run(dir, v.TagSyncCmd, "tag", tag)
-}
-
-// Log logs the changes for the repo in dir.
-// dir must be a valid VCS repo compatible with v.
-func (v *Cmd) Log(dir, logTemplate string) ([]byte, error) {
-	if err := v.Download(dir); err != nil {
-		return []byte{}, err
-	}
-
-	const N = 50 // how many revisions to grab
-	return v.runOutput(dir, v.LogCmd, "limit", strconv.Itoa(N), "template", logTemplate)
-}
-
-// LogAtRev logs the change for repo in dir at the rev revision.
-// dir must be a valid VCS repo compatible with v.
-// rev must be a valid revision for the repo in dir.
-func (v *Cmd) LogAtRev(dir, rev, logTemplate string) ([]byte, error) {
-	if err := v.Download(dir); err != nil {
-		return []byte{}, err
-	}
-
-	// Append revision flag to LogCmd.
-	logAtRevCmd := v.LogCmd + " --rev=" + rev
-	return v.runOutput(dir, logAtRevCmd, "limit", strconv.Itoa(1), "template", logTemplate)
-}
-
-// A vcsPath describes how to convert an import path into a
-// version control system and repository name.
-type vcsPath struct {
-	prefix string                              // prefix this description applies to
-	re     string                              // pattern for import path
-	repo   string                              // repository to use (expand with match of re)
-	vcs    string                              // version control system to use (expand with match of re)
-	check  func(match map[string]string) error // additional checks
-	ping   bool                                // ping for scheme to use to download repo
-
-	regexp *regexp.Regexp // cached compiled form of re
-}
-
-// FromDir inspects dir and its parents to determine the
-// version control system and code repository to use.
-// On return, root is the import path
-// corresponding to the root of the repository.
-func FromDir(dir, srcRoot string) (vcs *Cmd, root string, err error) {
-	// Clean and double-check that dir is in (a subdirectory of) srcRoot.
-	dir = filepath.Clean(dir)
-	srcRoot = filepath.Clean(srcRoot)
-	if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
-		return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
-	}
-
-	var vcsRet *Cmd
-	var rootRet string
-
-	origDir := dir
-	for len(dir) > len(srcRoot) {
-		for _, vcs := range vcsList {
-			if _, err := os.Stat(filepath.Join(dir, "."+vcs.Cmd)); err == nil {
-				root := filepath.ToSlash(dir[len(srcRoot)+1:])
-				// Record first VCS we find, but keep looking,
-				// to detect mistakes like one kind of VCS inside another.
-				if vcsRet == nil {
-					vcsRet = vcs
-					rootRet = root
-					continue
-				}
-				// Allow .git inside .git, which can arise due to submodules.
-				if vcsRet == vcs && vcs.Cmd == "git" {
-					continue
-				}
-				// Otherwise, we have one VCS inside a different VCS.
-				return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
-					filepath.Join(srcRoot, rootRet), vcsRet.Cmd, filepath.Join(srcRoot, root), vcs.Cmd)
-			}
-		}
-
-		// Move to parent.
-		ndir := filepath.Dir(dir)
-		if len(ndir) >= len(dir) {
-			// Shouldn't happen, but just in case, stop.
-			break
-		}
-		dir = ndir
-	}
-
-	if vcsRet != nil {
-		return vcsRet, rootRet, nil
-	}
-
-	return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
-}
-
-// RepoRoot represents a version control system, a repo, and a root of
-// where to put it on disk.
-type RepoRoot struct {
-	VCS *Cmd
-
-	// Repo is the repository URL, including scheme.
-	Repo string
-
-	// Root is the import path corresponding to the root of the
-	// repository.
-	Root string
-}
-
-// RepoRootForImportPath analyzes importPath to determine the
-// version control system, and code repository to use.
-func RepoRootForImportPath(importPath string, verbose bool) (*RepoRoot, error) {
-	rr, err := RepoRootForImportPathStatic(importPath, "")
-	if err == errUnknownSite {
-		rr, err = RepoRootForImportDynamic(importPath, verbose)
-
-		// RepoRootForImportDynamic returns error detail
-		// that is irrelevant if the user didn't intend to use a
-		// dynamic import in the first place.
-		// Squelch it.
-		if err != nil {
-			if Verbose {
-				log.Printf("import %q: %v", importPath, err)
-			}
-			err = fmt.Errorf("unrecognized import path %q", importPath)
-		}
-	}
-
-	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)
-	}
-	return rr, err
-}
-
-var errUnknownSite = errors.New("dynamic lookup required to find mapping")
-
-// RepoRootForImportPathStatic attempts to map importPath to a
-// RepoRoot using the commonly-used VCS hosting sites in vcsPaths
-// (github.com/user/dir), or from a fully-qualified importPath already
-// containing its VCS type (foo.com/repo.git/dir)
-//
-// If scheme is non-empty, that scheme is forced.
-func RepoRootForImportPathStatic(importPath, scheme string) (*RepoRoot, error) {
-	if strings.Contains(importPath, "://") {
-		return nil, fmt.Errorf("invalid import path %q", importPath)
-	}
-	for _, srv := range vcsPaths {
-		if !strings.HasPrefix(importPath, srv.prefix) {
-			continue
-		}
-		m := srv.regexp.FindStringSubmatch(importPath)
-		if m == nil {
-			if srv.prefix != "" {
-				return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
-			}
-			continue
-		}
-
-		// Build map of named subexpression matches for expand.
-		match := map[string]string{
-			"prefix": srv.prefix,
-			"import": importPath,
-		}
-		for i, name := range srv.regexp.SubexpNames() {
-			if name != "" && match[name] == "" {
-				match[name] = m[i]
-			}
-		}
-		if srv.vcs != "" {
-			match["vcs"] = expand(match, srv.vcs)
-		}
-		if srv.repo != "" {
-			match["repo"] = expand(match, srv.repo)
-		}
-		if srv.check != nil {
-			if err := srv.check(match); err != nil {
-				return nil, err
-			}
-		}
-		vcs := ByCmd(match["vcs"])
-		if vcs == nil {
-			return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
-		}
-		if srv.ping {
-			if scheme != "" {
-				match["repo"] = scheme + "://" + match["repo"]
-			} else {
-				for _, scheme := range vcs.Scheme {
-					if vcs.Ping(scheme, match["repo"]) == nil {
-						match["repo"] = scheme + "://" + match["repo"]
-						break
-					}
-				}
-			}
-		}
-		rr := &RepoRoot{
-			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
-// statically known by RepoRootForImportPathStatic.
-//
-// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
-func RepoRootForImportDynamic(importPath string, verbose bool) (*RepoRoot, error) {
-	slash := strings.Index(importPath, "/")
-	if slash < 0 {
-		slash = len(importPath)
-	}
-	host := importPath[:slash]
-	if !strings.Contains(host, ".") {
-		return nil, errors.New("import path doesn't contain a hostname")
-	}
-	urlStr, body, err := httpsOrHTTP(importPath)
-	if err != nil {
-		return nil, fmt.Errorf("http/https fetch: %v", err)
-	}
-	defer body.Close()
-	imports, err := parseMetaGoImports(body)
-	if err != nil {
-		return nil, fmt.Errorf("parsing %s: %v", importPath, err)
-	}
-	metaImport, err := matchGoImport(imports, importPath)
-	if err != nil {
-		if err != errNoMatch {
-			return nil, fmt.Errorf("parse %s: %v", urlStr, err)
-		}
-		return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
-	}
-	if verbose {
-		log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
-	}
-	// If the import was "uni.edu/bob/project", which said the
-	// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
-	// make sure we don't trust Bob and check out evilroot.com to
-	// "uni.edu" yet (possibly overwriting/preempting another
-	// non-evil student).  Instead, first verify the root and see
-	// if it matches Bob's claim.
-	if metaImport.Prefix != importPath {
-		if verbose {
-			log.Printf("get %q: verifying non-authoritative meta tag", importPath)
-		}
-		urlStr0 := urlStr
-		urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
-		if err != nil {
-			return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
-		}
-		imports, err := parseMetaGoImports(body)
-		if err != nil {
-			return nil, fmt.Errorf("parsing %s: %v", importPath, err)
-		}
-		if len(imports) == 0 {
-			return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
-		}
-		metaImport2, err := matchGoImport(imports, importPath)
-		if err != nil || metaImport != metaImport2 {
-			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
-		}
-	}
-
-	if err := validateRepoRoot(metaImport.RepoRoot); err != nil {
-		return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, metaImport.RepoRoot, err)
-	}
-	rr := &RepoRoot{
-		VCS:  ByCmd(metaImport.VCS),
-		Repo: metaImport.RepoRoot,
-		Root: metaImport.Prefix,
-	}
-	if rr.VCS == nil {
-		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
-	}
-	return rr, nil
-}
-
-// validateRepoRoot returns an error if repoRoot does not seem to be
-// a valid URL with scheme.
-func validateRepoRoot(repoRoot string) error {
-	url, err := url.Parse(repoRoot)
-	if err != nil {
-		return err
-	}
-	if url.Scheme == "" {
-		return errors.New("no scheme")
-	}
-	return nil
-}
-
-// metaImport represents the parsed <meta name="go-import"
-// content="prefix vcs reporoot" /> tags from HTML files.
-type metaImport struct {
-	Prefix, VCS, RepoRoot string
-}
-
-// errNoMatch is returned from matchGoImport when there's no applicable match.
-var errNoMatch = errors.New("no import match")
-
-// pathPrefix reports whether sub is a prefix of s,
-// only considering entire path components.
-func pathPrefix(s, sub string) bool {
-	// strings.HasPrefix is necessary but not sufficient.
-	if !strings.HasPrefix(s, sub) {
-		return false
-	}
-	// The remainder after the prefix must either be empty or start with a slash.
-	rem := s[len(sub):]
-	return rem == "" || rem[0] == '/'
-}
-
-// matchGoImport returns the metaImport from imports matching importPath.
-// An error is returned if there are multiple matches.
-// errNoMatch is returned if none match.
-func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
-	match := -1
-	for i, im := range imports {
-		if !pathPrefix(importPath, im.Prefix) {
-			continue
-		}
-
-		if match != -1 {
-			err = fmt.Errorf("multiple meta tags match import path %q", importPath)
-			return
-		}
-		match = i
-	}
-	if match == -1 {
-		err = errNoMatch
-		return
-	}
-	return imports[match], nil
-}
-
-// expand rewrites s to replace {k} with match[k] for each key k in match.
-func expand(match map[string]string, s string) string {
-	for k, v := range match {
-		s = strings.Replace(s, "{"+k+"}", v, -1)
-	}
-	return s
-}
-
-// vcsPaths lists the known vcs paths.
-var vcsPaths = []*vcsPath{
-	// Github
-	{
-		prefix: "github.com/",
-		re:     `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[\p{L}0-9_.\-]+)*$`,
-		vcs:    "git",
-		repo:   "https://{root}",
-		check:  noVCSSuffix,
-	},
-
-	// Bitbucket
-	{
-		prefix: "bitbucket.org/",
-		re:     `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
-		repo:   "https://{root}",
-		check:  bitbucketVCS,
-	},
-
-	// Launchpad
-	{
-		prefix: "launchpad.net/",
-		re:     `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "bzr",
-		repo:   "https://{root}",
-		check:  launchpadVCS,
-	},
-
-	// Git at OpenStack
-	{
-		prefix: "git.openstack.org",
-		re:     `^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "git",
-		repo:   "https://{root}",
-		check:  noVCSSuffix,
-	},
-
-	// General syntax for any server.
-	{
-		re:   `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
-		ping: true,
-	},
-}
-
-func init() {
-	// fill in cached regexps.
-	// Doing this eagerly discovers invalid regexp syntax
-	// without having to run a command that needs that regexp.
-	for _, srv := range vcsPaths {
-		srv.regexp = regexp.MustCompile(srv.re)
-	}
-}
-
-// noVCSSuffix checks that the repository name does not
-// end in .foo for any version control system foo.
-// The usual culprit is ".git".
-func noVCSSuffix(match map[string]string) error {
-	repo := match["repo"]
-	for _, vcs := range vcsList {
-		if strings.HasSuffix(repo, "."+vcs.Cmd) {
-			return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
-		}
-	}
-	return nil
-}
-
-// bitbucketVCS determines the version control system for a
-// Bitbucket repository, by using the Bitbucket API.
-func bitbucketVCS(match map[string]string) error {
-	if err := noVCSSuffix(match); err != nil {
-		return err
-	}
-
-	var resp struct {
-		SCM string `json:"scm"`
-	}
-	url := expand(match, "https://api.bitbucket.org/2.0/repositories/{bitname}?fields=scm")
-	data, err := httpGET(url)
-	if err != nil {
-		return err
-	}
-	if err := json.Unmarshal(data, &resp); err != nil {
-		return fmt.Errorf("decoding %s: %v", url, err)
-	}
-
-	if ByCmd(resp.SCM) != nil {
-		match["vcs"] = resp.SCM
-		if resp.SCM == "git" {
-			match["repo"] += ".git"
-		}
-		return nil
-	}
-
-	return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
-}
-
-// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
-// "foo" could be a series name registered in Launchpad with its own branch,
-// and it could also be the name of a directory within the main project
-// branch one level up.
-func launchpadVCS(match map[string]string) error {
-	if match["project"] == "" || match["series"] == "" {
-		return nil
-	}
-	_, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
-	if err != nil {
-		match["root"] = expand(match, "launchpad.net/{project}")
-		match["repo"] = expand(match, "https://{root}")
-	}
-	return nil
-}
diff --git a/go/vcs/vcs_test.go b/go/vcs/vcs_test.go
deleted file mode 100644
index a17b50d..0000000
--- a/go/vcs/vcs_test.go
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright 2013 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 vcs
-
-import (
-	"errors"
-	"io/ioutil"
-	"os"
-	"path"
-	"path/filepath"
-	"reflect"
-	"runtime"
-	"strings"
-	"testing"
-)
-
-// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
-// TODO(cmang): Add tests for SVN and BZR.
-func TestRepoRootForImportPath(t *testing.T) {
-	if runtime.GOOS == "android" {
-		t.Skipf("incomplete source tree on %s", runtime.GOOS)
-	}
-
-	tests := []struct {
-		path string
-		want *RepoRoot
-	}{
-		{
-			"github.com/golang/groupcache",
-			&RepoRoot{
-				VCS:  vcsGit,
-				Repo: "https://github.com/golang/groupcache",
-			},
-		},
-		// Unicode letters in directories (issue 18660).
-		{
-			"github.com/user/unicode/испытание",
-			&RepoRoot{
-				VCS:  vcsGit,
-				Repo: "https://github.com/user/unicode",
-			},
-		},
-	}
-
-	for _, test := range tests {
-		got, err := RepoRootForImportPath(test.path, false)
-		if err != nil {
-			t.Errorf("RepoRootForImportPath(%q): %v", test.path, err)
-			continue
-		}
-		want := test.want
-		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)
-		}
-	}
-}
-
-// Test that FromDir correctly inspects a given directory and returns the right VCS and root.
-func TestFromDir(t *testing.T) {
-	tempDir, err := ioutil.TempDir("", "vcstest")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	for j, vcs := range vcsList {
-		dir := filepath.Join(tempDir, "example.com", vcs.Name, "."+vcs.Cmd)
-		if j&1 == 0 {
-			err := os.MkdirAll(dir, 0755)
-			if err != nil {
-				t.Fatal(err)
-			}
-		} else {
-			err := os.MkdirAll(filepath.Dir(dir), 0755)
-			if err != nil {
-				t.Fatal(err)
-			}
-			f, err := os.Create(dir)
-			if err != nil {
-				t.Fatal(err)
-			}
-			f.Close()
-		}
-
-		want := RepoRoot{
-			VCS:  vcs,
-			Root: path.Join("example.com", vcs.Name),
-		}
-		var got RepoRoot
-		got.VCS, got.Root, err = FromDir(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)
-		}
-	}
-}
-
-var parseMetaGoImportsTests = []struct {
-	in  string
-	out []metaImport
-}{
-	{
-		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
-		[]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">`,
-		[]metaImport{
-			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
-			{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
-		},
-	},
-	{
-		`<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">`,
-		[]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">`,
-		[]metaImport{
-			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
-		},
-	},
-	{
-		`<head>
-		<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
-		</head>`,
-		[]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>`,
-		[]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">`,
-		[]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>`,
-		[]metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
-	},
-	{
-		`<meta name="go-import" content="myitcv.io git https://github.com/myitcv/x">
-	        <meta name="go-import" content="myitcv.io/blah2 mod https://raw.githubusercontent.com/myitcv/pubx/master">
-	        `,
-		[]metaImport{{"myitcv.io", "git", "https://github.com/myitcv/x"}},
-	},
-}
-
-func TestParseMetaGoImports(t *testing.T) {
-	for i, tt := range parseMetaGoImportsTests {
-		out, err := parseMetaGoImports(strings.NewReader(tt.in))
-		if err != nil {
-			t.Errorf("test#%d: %v", i, err)
-			continue
-		}
-		if !reflect.DeepEqual(out, tt.out) {
-			t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
-		}
-	}
-}
-
-func TestValidateRepoRoot(t *testing.T) {
-	tests := []struct {
-		root string
-		ok   bool
-	}{
-		{
-			root: "",
-			ok:   false,
-		},
-		{
-			root: "http://",
-			ok:   true,
-		},
-		{
-			root: "git+ssh://",
-			ok:   true,
-		},
-		{
-			root: "http#://",
-			ok:   false,
-		},
-		{
-			root: "-config",
-			ok:   false,
-		},
-		{
-			root: "-config://",
-			ok:   false,
-		},
-	}
-
-	for _, test := range tests {
-		err := validateRepoRoot(test.root)
-		ok := err == nil
-		if ok != test.ok {
-			want := "error"
-			if test.ok {
-				want = "nil"
-			}
-			t.Errorf("validateRepoRoot(%q) = %q, want %s", test.root, err, want)
-		}
-	}
-}
-
-func TestMatchGoImport(t *testing.T) {
-	tests := []struct {
-		imports []metaImport
-		path    string
-		mi      metaImport
-		err     error
-	}{
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/foo",
-			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/foo/",
-			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-				{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/foo",
-			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-				{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/fooa",
-			mi:   metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/foo/bar",
-			err:  errors.New("should not be allowed to create nested repo"),
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/foo/bar/baz",
-			err:  errors.New("should not be allowed to create nested repo"),
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/foo/bar/baz/qux",
-			err:  errors.New("should not be allowed to create nested repo"),
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com/user/foo/bar/baz/",
-			err:  errors.New("should not be allowed to create nested repo"),
-		},
-		{
-			imports: []metaImport{
-				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
-			},
-			path: "example.com",
-			err:  errors.New("pathologically short path"),
-		},
-	}
-
-	for _, test := range tests {
-		mi, err := matchGoImport(test.imports, test.path)
-		if mi != test.mi {
-			t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi)
-		}
-
-		got := err
-		want := test.err
-		if (got == nil) != (want == nil) {
-			t.Errorf("unexpected error; got %v, want %v", got, want)
-		}
-	}
-}