cmd/gomote: remove legacy gomote functions

This removes the functions which used the depricated gomote API.

Updates golang/go#54735
Updates golang/go#53272

Change-Id: I12d2ce823f140f510186109e2755cca8461a30b4
Reviewed-on: https://go-review.googlesource.com/c/build/+/456044
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Carlos Amedee <carlos@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Carlos Amedee <carlos@golang.org>
diff --git a/cmd/gomote/create.go b/cmd/gomote/create.go
index 3055944..58bd50f 100644
--- a/cmd/gomote/create.go
+++ b/cmd/gomote/create.go
@@ -19,9 +19,7 @@
 	"sync"
 	"time"
 
-	"golang.org/x/build/buildlet"
 	"golang.org/x/build/internal/gomote/protos"
-	"golang.org/x/build/types"
 	"golang.org/x/sync/errgroup"
 )
 
@@ -80,65 +78,6 @@
 	return
 }
 
-func legacyCreate(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("create", flag.ContinueOnError)
-
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "create usage: gomote create [create-opts] <type>")
-		fs.PrintDefaults()
-		fmt.Fprintln(os.Stderr, "\nValid types:")
-		for _, bt := range builders() {
-			var warn string
-			if bt.IsReverse {
-				if bt.ExpectNum > 0 {
-					warn = fmt.Sprintf("   [limited capacity: %d machines]", bt.ExpectNum)
-				} else {
-					warn = "   [limited capacity]"
-				}
-			}
-			fmt.Fprintf(os.Stderr, "  * %s%s\n", bt.Name, warn)
-		}
-		os.Exit(1)
-	}
-	var status bool
-	fs.BoolVar(&status, "status", true, "print regular status updates while waiting")
-
-	// TODO(bradfitz): restore this option, and send it to the coordinator:
-	// For now, comment it out so it's not misleading.
-	// var timeout time.Duration
-	// fs.DurationVar(&timeout, "timeout", 60*time.Minute, "how long the VM will live before being deleted.")
-
-	fs.Parse(args)
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-	builderType := fs.Arg(0)
-
-	t := time.Now()
-	cc, err := buildlet.NewCoordinatorClientFromFlags()
-	if err != nil {
-		return fmt.Errorf("failed to create coordinator client: %w", err)
-	}
-	client, err := cc.CreateBuildletWithStatus(builderType, func(st types.BuildletWaitStatus) {
-		if status {
-			if st.Message != "" {
-				fmt.Fprintf(os.Stderr, "# %s\n", st.Message)
-				return
-			}
-			fmt.Fprintf(os.Stderr, "# still creating %s after %v; %d requests ahead of you\n", builderType, time.Since(t).Round(time.Second), st.Ahead)
-		}
-	})
-	if err != nil {
-		return fmt.Errorf("failed to create buildlet: %w", err)
-	}
-	fmt.Println(client.RemoteName())
-	return nil
-}
-
 func create(args []string) error {
 	fs := flag.NewFlagSet("create", flag.ContinueOnError)
 
diff --git a/cmd/gomote/destroy.go b/cmd/gomote/destroy.go
index 9e87e92..99f7132 100644
--- a/cmd/gomote/destroy.go
+++ b/cmd/gomote/destroy.go
@@ -11,51 +11,9 @@
 	"log"
 	"os"
 
-	"golang.org/x/build/buildlet"
 	"golang.org/x/build/internal/gomote/protos"
 )
 
-func legacyDestroy(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("destroy", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "destroy usage: gomote destroy <instance>")
-		fs.PrintDefaults()
-		if fs.NArg() == 0 {
-			// List buildlets that you might want to destroy.
-			cc, err := buildlet.NewCoordinatorClientFromFlags()
-			if err != nil {
-				log.Fatal(err)
-			}
-			rbs, err := cc.RemoteBuildlets()
-			if err != nil {
-				log.Fatal(err)
-			}
-			if len(rbs) > 0 {
-				fmt.Printf("possible instances:\n")
-				for _, rb := range rbs {
-					fmt.Printf("\t%s\n", rb.Name)
-				}
-			}
-		}
-		os.Exit(1)
-	}
-
-	fs.Parse(args)
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-	name := fs.Arg(0)
-	bc, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-	return bc.Close()
-}
-
 func destroy(args []string) error {
 	fs := flag.NewFlagSet("destroy", flag.ContinueOnError)
 	fs.Usage = func() {
diff --git a/cmd/gomote/get.go b/cmd/gomote/get.go
index 86caa68..6570edf 100644
--- a/cmd/gomote/get.go
+++ b/cmd/gomote/get.go
@@ -17,40 +17,6 @@
 	"golang.org/x/sync/errgroup"
 )
 
-// legacyGetTar a .tar.gz
-func legacyGetTar(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("get", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "gettar usage: gomote gettar [get-opts] <buildlet-name>")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	var dir string
-	fs.StringVar(&dir, "dir", "", "relative directory from buildlet's work dir to tar up")
-
-	fs.Parse(args)
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-
-	name := fs.Arg(0)
-	bc, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-	tgz, err := bc.GetTar(context.Background(), dir)
-	if err != nil {
-		return err
-	}
-	defer tgz.Close()
-	_, err = io.Copy(os.Stdout, tgz)
-	return err
-}
-
 // getTar a .tar.gz
 func getTar(args []string) error {
 	fs := flag.NewFlagSet("get", flag.ContinueOnError)
diff --git a/cmd/gomote/gomote.go b/cmd/gomote/gomote.go
index cbf930f..0004eb7 100644
--- a/cmd/gomote/gomote.go
+++ b/cmd/gomote/gomote.go
@@ -148,7 +148,6 @@
 	"fmt"
 	"os"
 	"sort"
-	"strconv"
 
 	"golang.org/x/build/buildenv"
 	"golang.org/x/build/buildlet"
@@ -204,40 +203,22 @@
 	}
 }
 
-func registerCommands(version int) {
-	if version == 2 {
-		registerCommand("create", "create a buildlet; with no args, list types of buildlets", create)
-		registerCommand("destroy", "destroy a buildlet", destroy)
-		registerCommand("gettar", "extract a tar.gz from a buildlet", getTar)
-		registerCommand("group", "manage groups of instances", group)
-		registerCommand("ls", "list the contents of a directory on a buildlet", ls)
-		registerCommand("list", "list active buildlets", list)
-		registerCommand("ping", "test whether a buildlet is alive and reachable ", ping)
-		registerCommand("push", "sync your GOROOT directory to the buildlet", push)
-		registerCommand("put", "put files on a buildlet", put)
-		registerCommand("putbootstrap", "put bootstrap toolchain in place", putBootstrap)
-		registerCommand("puttar", "extract a tar.gz to a buildlet", putTar)
-		registerCommand("rdp", "RDP (Remote Desktop Protocol) to a Windows buildlet", rdp)
-		registerCommand("rm", "delete files or directories", rm)
-		registerCommand("run", "run a command on a buildlet", run)
-		registerCommand("ssh", "ssh to a buildlet", ssh)
-		return
-	}
-	registerCommand("create", "create a buildlet; with no args, list types of buildlets", legacyCreate)
-	registerCommand("destroy", "destroy a buildlet", legacyDestroy)
-	registerCommand("gettar", "extract a tar.gz from a buildlet", legacyGetTar)
-	registerCommand("ls", "list the contents of a directory on a buildlet", legacyLs)
-	registerCommand("list", "list active buildlets", legacyList)
-	registerCommand("ping", "test whether a buildlet is alive and reachable ", legacyPing)
-	registerCommand("push", "sync your GOROOT directory to the buildlet", legacyPush)
-	registerCommand("put", "put files on a buildlet", legacyPut)
-	registerCommand("put14", "put Go 1.4 in place", put14)
-	registerCommand("puttar", "extract a tar.gz to a buildlet", legacyPutTar)
-	registerCommand("rdp", "RDP (Remote Desktop Protocol) to a Windows buildlet", rdp)
-	registerCommand("rm", "delete files or directories", legacyRm)
-	registerCommand("run", "run a command on a buildlet", legacyRun)
-	registerCommand("group", "manage gomote groups (v2 only)", group)
-	registerCommand("ssh", "ssh to a buildlet", legacySSH)
+func registerCommands() {
+	registerCommand("create", "create a buildlet; with no args, list types of buildlets", create)
+	registerCommand("destroy", "destroy a buildlet", destroy)
+	registerCommand("gettar", "extract a tar.gz from a buildlet", getTar)
+	registerCommand("group", "manage groups of instances", group)
+	registerCommand("ls", "list the contents of a directory on a buildlet", ls)
+	registerCommand("list", "list active buildlets", list)
+	registerCommand("ping", "test whether a buildlet is alive and reachable ", ping)
+	registerCommand("push", "sync your GOROOT directory to the buildlet", push)
+	registerCommand("put", "put files on a buildlet", put)
+	registerCommand("putbootstrap", "put bootstrap toolchain in place", putBootstrap)
+	registerCommand("puttar", "extract a tar.gz to a buildlet", putTar)
+	registerCommand("rdp", "Unimplimented: RDP (Remote Desktop Protocol) to a Windows buildlet", rdp)
+	registerCommand("rm", "delete files or directories", rm)
+	registerCommand("run", "run a command on a buildlet", run)
+	registerCommand("ssh", "ssh to a buildlet", ssh)
 }
 
 var (
@@ -248,17 +229,7 @@
 	// Set up and parse global flags.
 	groupName := flag.String("group", os.Getenv("GOMOTE_GROUP"), "name of the gomote group to apply commands to (default is $GOMOTE_GROUP)")
 	buildlet.RegisterFlags()
-	version := 2
-	if vs := os.Getenv("GOMOTE_VERSION"); vs != "" {
-		v, err := strconv.Atoi(vs)
-		if err == nil {
-			version = v
-		}
-	}
-	if version < 1 || version > 2 {
-		fmt.Fprintf(os.Stderr, "unsupported version %d", version)
-	}
-	registerCommands(version)
+	registerCommands()
 	flag.Usage = usage
 	flag.Parse()
 	args := flag.Args()
diff --git a/cmd/gomote/list.go b/cmd/gomote/list.go
index 3e38b37..a9fd032 100644
--- a/cmd/gomote/list.go
+++ b/cmd/gomote/list.go
@@ -8,124 +8,13 @@
 	"context"
 	"flag"
 	"fmt"
-	"log"
 	"os"
 	"strings"
 	"time"
 
-	"golang.org/x/build/buildlet"
-	"golang.org/x/build/dashboard"
 	"golang.org/x/build/internal/gomote/protos"
 )
 
-func legacyList(args []string) error {
-	fs := flag.NewFlagSet("list", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "list usage: gomote list")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	fs.Parse(args)
-	if fs.NArg() != 0 {
-		fs.Usage()
-	}
-
-	cc, err := buildlet.NewCoordinatorClientFromFlags()
-	if err != nil {
-		log.Fatal(err)
-	}
-	rbs, err := cc.RemoteBuildlets()
-	if err != nil {
-		log.Fatal(err)
-	}
-	for _, rb := range rbs {
-		fmt.Printf("%s\t%s\t%s\texpires in %v\n", rb.Name, rb.BuilderType, rb.HostType, rb.Expires.Sub(time.Now()))
-	}
-
-	return nil
-}
-
-// remoteClient returns a buildlet.Client for a named remote buildlet
-// (a buildlet connection owned by the build coordinator).
-//
-// As a special case, if name contains '@', the name is expected to be
-// of the form <build-config-name>@ip[:port]. For example,
-// "windows-amd64-race@10.0.0.1".
-func remoteClient(name string) (buildlet.RemoteClient, error) {
-	bc, _, err := clientAndCondConf(name, false)
-	return bc, err
-}
-
-// clientAndConf returns a buildlet.Client and its build config for
-// a named remote buildlet (a buildlet connection owned by the build
-// coordinator).
-//
-// As a special case, if name contains '@', the name is expected to be
-// of the form <build-config-name>@ip[:port]. For example,
-// "windows-amd64-race@10.0.0.1".
-func clientAndConf(name string) (bc buildlet.RemoteClient, conf *dashboard.BuildConfig, err error) {
-	return clientAndCondConf(name, true)
-}
-
-func clientAndCondConf(name string, withConf bool) (bc buildlet.RemoteClient, conf *dashboard.BuildConfig, err error) {
-	if strings.Contains(name, "@") {
-		f := strings.SplitN(name, "@", 2)
-		if len(f) != 2 {
-			err = fmt.Errorf("unsupported name %q; for @ form expect <build-config-name>@host[:port]", name)
-			return
-		}
-		builderType := f[0]
-		if withConf {
-			var ok bool
-			conf, ok = dashboard.Builders[builderType]
-			if !ok {
-				err = fmt.Errorf("unknown builder type %q (name %q)", builderType, name)
-				return
-			}
-		}
-		ipPort := f[1]
-		if !strings.Contains(ipPort, ":") {
-			ipPort += ":80"
-		}
-		bc = buildlet.NewClient(ipPort, buildlet.NoKeyPair)
-		return
-	}
-
-	cc, err := buildlet.NewCoordinatorClientFromFlags()
-	if err != nil {
-		return
-	}
-
-	rbs, err := cc.RemoteBuildlets()
-	if err != nil {
-		return
-	}
-	var builderType string
-	var ok bool
-	for _, rb := range rbs {
-		if rb.Name == name {
-			ok = true
-			builderType = rb.BuilderType
-		}
-	}
-	if !ok {
-		err = fmt.Errorf("unknown builder %q", name)
-		return
-	}
-
-	bc, err = cc.NamedBuildlet(name)
-	if err != nil {
-		return
-	}
-
-	conf, ok = dashboard.Builders[builderType]
-	if !ok {
-		log.Fatalf("Builder type %q not known to this gomote binary. Update your gomote binary. TODO: teach gomote to fetch build configs from the server (Issue 30929)", builderType)
-	}
-
-	return bc, conf, nil
-}
-
 func list(args []string) error {
 	fs := flag.NewFlagSet("list", flag.ContinueOnError)
 	fs.Usage = func() {
diff --git a/cmd/gomote/ls.go b/cmd/gomote/ls.go
index 5ffa578..4e6e95e 100644
--- a/cmd/gomote/ls.go
+++ b/cmd/gomote/ls.go
@@ -11,50 +11,9 @@
 	"os"
 	"strings"
 
-	"golang.org/x/build/buildlet"
 	"golang.org/x/build/internal/gomote/protos"
 )
 
-func legacyLs(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("ls", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "ls usage: gomote ls <instance> [-R] [dir]")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	var recursive bool
-	fs.BoolVar(&recursive, "R", false, "recursive")
-	var digest bool
-	fs.BoolVar(&digest, "d", false, "get file digests")
-	var skip string
-	fs.StringVar(&skip, "skip", "", "comma-separated list of relative directories to skip (use forward slashes)")
-	fs.Parse(args)
-
-	dir := "."
-	if n := fs.NArg(); n < 1 || n > 2 {
-		fs.Usage()
-	} else if n == 2 {
-		dir = fs.Arg(1)
-	}
-	name := fs.Arg(0)
-	bc, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-	opts := buildlet.ListDirOpts{
-		Recursive: recursive,
-		Digest:    digest,
-		Skip:      strings.Split(skip, ","),
-	}
-	return bc.ListDir(context.Background(), dir, opts, func(bi buildlet.DirEntry) {
-		fmt.Fprintf(os.Stdout, "%s\n", bi)
-	})
-}
-
 func ls(args []string) error {
 	fs := flag.NewFlagSet("ls", flag.ContinueOnError)
 	fs.Usage = func() {
diff --git a/cmd/gomote/ping.go b/cmd/gomote/ping.go
index 9833f99..e39b3ca 100644
--- a/cmd/gomote/ping.go
+++ b/cmd/gomote/ping.go
@@ -13,40 +13,6 @@
 	"golang.org/x/build/internal/gomote/protos"
 )
 
-func legacyPing(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("ping", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "ping usage: gomote ping [--status] <instance>")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	var status bool
-	fs.BoolVar(&status, "status", false, "print buildlet status")
-	fs.Parse(args)
-
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-	name := fs.Arg(0)
-	bc, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-	ctx := context.Background()
-	wd, err := bc.WorkDir(ctx)
-	if err != nil {
-		return err
-	}
-	if status {
-		fmt.Printf("workdir: %v\n", wd)
-	}
-	return nil
-}
-
 func ping(args []string) error {
 	fs := flag.NewFlagSet("ping", flag.ContinueOnError)
 	fs.Usage = func() {
diff --git a/cmd/gomote/push.go b/cmd/gomote/push.go
index d23a46d..79f7075 100644
--- a/cmd/gomote/push.go
+++ b/cmd/gomote/push.go
@@ -27,269 +27,6 @@
 	"golang.org/x/sync/errgroup"
 )
 
-func legacyPush(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("push", flag.ContinueOnError)
-	var dryRun bool
-	fs.BoolVar(&dryRun, "dry-run", false, "print what would be done only")
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "push usage: gomote push <instance>")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	fs.Parse(args)
-
-	goroot, err := getGOROOT()
-	if err != nil {
-		return err
-	}
-
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-	name := fs.Arg(0)
-	bc, conf, err := clientAndConf(name)
-	if err != nil {
-		return err
-	}
-
-	haveGo14 := false
-	remote := map[string]buildlet.DirEntry{} // keys like "src/make.bash"
-
-	lsOpts := buildlet.ListDirOpts{
-		Recursive: true,
-		Digest:    true,
-		Skip: []string{
-			// Ignore binary output directories:
-			"go/pkg", "go/bin",
-			// We don't care about the digest of
-			// particular source files for Go 1.4.  And
-			// exclude /pkg. This leaves go1.4/bin, which
-			// is enough to know whether we have Go 1.4 or
-			// not.
-			"go1.4/src", "go1.4/pkg",
-		},
-	}
-	ctx := context.Background()
-	if err := bc.ListDir(ctx, ".", lsOpts, func(ent buildlet.DirEntry) {
-		name := ent.Name()
-		if strings.HasPrefix(name, "go1.4/") {
-			haveGo14 = true
-			return
-		}
-		if strings.HasPrefix(name, "go/") {
-			remote[name[len("go/"):]] = ent
-		}
-
-	}); err != nil {
-		return fmt.Errorf("error listing buildlet's existing files: %w", err)
-	}
-
-	if !haveGo14 {
-		if u := conf.GoBootstrapURL(buildEnv); u != "" {
-			log.Printf("installing go1.4 from %s", u)
-			if dryRun {
-				log.Printf("(Dry-run) Would have pushed go1.4 from %s", u)
-			} else {
-				if err := bc.PutTarFromURL(ctx, u, "go1.4"); err != nil {
-					return err
-				}
-			}
-		}
-	}
-
-	// Invoke 'git check-ignore' and use it to query whether paths have been gitignored.
-	// If anything goes wrong at any point, fall back to assuming that nothing is gitignored.
-	var isGitIgnored func(string) bool
-	gci := exec.Command("git", "check-ignore", "--stdin", "-n", "-v", "-z")
-	gci.Env = append(os.Environ(), "GIT_FLUSH=1")
-	gciIn, errIn := gci.StdinPipe()
-	defer gciIn.Close() // allow git process to exit
-	gciOut, errOut := gci.StdoutPipe()
-	errStart := gci.Start()
-	if errIn != nil || errOut != nil || errStart != nil {
-		isGitIgnored = func(string) bool { return false }
-	} else {
-		var failed bool
-		br := bufio.NewReader(gciOut)
-		isGitIgnored = func(path string) bool {
-			if failed {
-				return false
-			}
-			fmt.Fprintf(gciIn, "%s\x00", path)
-			// Response is of form "<source> <NULL> <linenum> <NULL> <pattern> <NULL> <pathname> <NULL>"
-			// Read all four and check that the path is correct.
-			// If so, the path is ignored iff the source (reason why ignored) is non-empty.
-			var resp [4][]byte
-			for i := range resp {
-				b, err := br.ReadBytes(0)
-				if err != nil {
-					failed = true
-					return false
-				}
-				resp[i] = b[:len(b)-1] // drop trailing NULL
-			}
-			// Sanity check
-			if string(resp[3]) != path {
-				panic("git check-ignore path did not roundtrip, got " + string(resp[3]) + " sent " + path)
-			}
-			return len(resp[0]) > 0
-		}
-	}
-
-	type fileInfo struct {
-		fi   os.FileInfo
-		sha1 string // if regular file
-	}
-	local := map[string]fileInfo{} // keys like "src/make.bash"
-	if err := filepath.Walk(goroot, func(path string, fi os.FileInfo, err error) error {
-		if isEditorBackup(path) {
-			return nil
-		}
-		if err != nil {
-			return err
-		}
-		rel, err := filepath.Rel(goroot, path)
-		if err != nil {
-			return fmt.Errorf("error calculating relative path from %q to %q", goroot, path)
-		}
-		rel = filepath.ToSlash(rel)
-		if rel == "." {
-			return nil
-		}
-		if fi.IsDir() {
-			switch rel {
-			case ".git", "pkg", "bin":
-				return filepath.SkipDir
-			}
-		}
-		inf := fileInfo{fi: fi}
-		if isGitIgnored(path) {
-			if fi.Mode().IsDir() {
-				return filepath.SkipDir
-			}
-			return nil
-		}
-		if fi.Mode().IsRegular() {
-			inf.sha1, err = fileSHA1(path)
-			if err != nil {
-				return err
-			}
-		}
-		local[rel] = inf
-		return nil
-	}); err != nil {
-		return fmt.Errorf("error enumerating local GOROOT files: %w", err)
-	}
-
-	var toDel []string
-	for rel := range remote {
-		if rel == "VERSION" {
-			// Don't delete this. It's harmless, and
-			// necessary. Clients can overwrite it if they
-			// want. But if there's no VERSION file there,
-			// make.bash/bat assumes there's a git repo in
-			// place, but there's not only not a git repo
-			// there with gomote, but there's no git tool
-			// available either.
-			continue
-		}
-		// Also don't delete the auto-generated files from cmd/dist.
-		// Otherwise gomote users can't gomote push + gomote run make.bash
-		// and then iteratively:
-		// -- hack locally
-		// -- gomote push
-		// -- gomote run go test -v ...
-		// Because the go test would fail remotely without
-		// these files if they were deleted by gomote push.
-		if isGoToolDistGenerated(rel) {
-			continue
-		}
-		if isGitIgnored(rel) {
-			// Don't delete remote gitignored files; this breaks built toolchains.
-			continue
-		}
-		rel = strings.TrimRight(rel, "/")
-		if rel == "" {
-			continue
-		}
-		if _, ok := local[rel]; !ok {
-			toDel = append(toDel, rel)
-		}
-	}
-	if len(toDel) > 0 {
-		withGo := make([]string, len(toDel)) // with the "go/" prefix
-		for i, v := range toDel {
-			withGo[i] = "go/" + v
-		}
-		sort.Strings(withGo)
-		if dryRun {
-			log.Printf("(Dry-run) Would have deleted remote files: %q", withGo)
-		} else {
-			log.Printf("Deleting remote files: %q", withGo)
-			if err := bc.RemoveAll(ctx, withGo...); err != nil {
-				return fmt.Errorf("Deleting remote unwanted files: %w", err)
-			}
-		}
-	}
-
-	var toSend []string
-	notHave := 0
-	const maxNotHavePrint = 5
-	for rel, inf := range local {
-		if isGoToolDistGenerated(rel) || rel == "VERSION.cache" {
-			continue
-		}
-		if !inf.fi.Mode().IsRegular() {
-			// TODO(bradfitz): this is only doing regular files
-			// for now, so empty directories, symlinks, etc aren't
-			// supported. revisit if that's a problem.
-			if !inf.fi.IsDir() {
-				log.Printf("Ignoring local non-regular, non-directory file %s: %v", rel, inf.fi.Mode())
-			}
-			continue
-		}
-		rem, ok := remote[rel]
-		if !ok {
-			if notHave++; notHave <= maxNotHavePrint {
-				log.Printf("Remote doesn't have %q", rel)
-			}
-			toSend = append(toSend, rel)
-			continue
-		}
-		if rem.Digest() != inf.sha1 {
-			log.Printf("Remote's %s digest is %q; want %q", rel, rem.Digest(), inf.sha1)
-			toSend = append(toSend, rel)
-		}
-	}
-	if notHave > maxNotHavePrint {
-		log.Printf("Remote doesn't have %d files (only showed %d).", notHave, maxNotHavePrint)
-	}
-	if _, hasVersion := remote["VERSION"]; !hasVersion {
-		log.Printf("Remote lacks a VERSION file; sending a fake one")
-		toSend = append(toSend, "VERSION")
-	}
-	if len(toSend) > 0 {
-		sort.Strings(toSend)
-		tgz, err := generateDeltaTgz(goroot, toSend)
-		if err != nil {
-			return err
-		}
-		log.Printf("Uploading %d new/changed files; %d byte .tar.gz", len(toSend), tgz.Len())
-		if dryRun {
-			log.Printf("(Dry-run mode; not doing anything.")
-			return nil
-		}
-		if err := bc.PutTar(ctx, tgz, "go"); err != nil {
-			return fmt.Errorf("writing tarball to buildlet: %w", err)
-		}
-	}
-	return nil
-}
-
 func push(args []string) error {
 	fs := flag.NewFlagSet("push", flag.ContinueOnError)
 	var dryRun bool
diff --git a/cmd/gomote/put.go b/cmd/gomote/put.go
index bb8e8f1..c2a93f6 100644
--- a/cmd/gomote/put.go
+++ b/cmd/gomote/put.go
@@ -26,80 +26,6 @@
 	"golang.org/x/sync/errgroup"
 )
 
-// legacyPutTar a .tar.gz
-func legacyPutTar(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("put", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "puttar usage: gomote puttar [put-opts] <buildlet-name> [tar.gz file or '-' for stdin]")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	var rev string
-	fs.StringVar(&rev, "gorev", "", "If non-empty, git hash to download from gerrit and put to the buildlet. e.g. 886b02d705ff for Go 1.4.1. This just maps to the --URL flag, so the two options are mutually exclusive.")
-	var dir string
-	fs.StringVar(&dir, "dir", "", "relative directory from buildlet's work dir to extra tarball into")
-	var tarURL string
-	fs.StringVar(&tarURL, "url", "", "URL of tarball, instead of provided file.")
-
-	fs.Parse(args)
-	if fs.NArg() < 1 || fs.NArg() > 2 {
-		fs.Usage()
-	}
-	if rev != "" {
-		if tarURL != "" {
-			fmt.Fprintln(os.Stderr, "--gorev and --url are mutually exclusive")
-			fs.Usage()
-		}
-		tarURL = "https://go.googlesource.com/go/+archive/" + rev + ".tar.gz"
-	}
-
-	name := fs.Arg(0)
-	bc, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-
-	ctx := context.Background()
-
-	if tarURL != "" {
-		if fs.NArg() != 1 {
-			fs.Usage()
-		}
-		if err := bc.PutTarFromURL(ctx, tarURL, dir); err != nil {
-			return err
-		}
-		if rev != "" {
-			// Put a VERSION file there too, to avoid git usage.
-			version := strings.NewReader("devel " + rev)
-			var vtar tarutil.FileList
-			vtar.AddRegular(&tar.Header{
-				Name: "VERSION",
-				Mode: 0644,
-				Size: int64(version.Len()),
-			}, int64(version.Len()), version)
-			tgz := vtar.TarGz()
-			defer tgz.Close()
-			return bc.PutTar(ctx, tgz, dir)
-		}
-		return nil
-	}
-
-	var tgz io.Reader = os.Stdin
-	if fs.NArg() == 2 && fs.Arg(1) != "-" {
-		f, err := os.Open(fs.Arg(1))
-		if err != nil {
-			return err
-		}
-		defer f.Close()
-		tgz = f
-	}
-	return bc.PutTar(ctx, tgz, dir)
-}
-
 // putTar a .tar.gz
 func putTar(args []string) error {
 	fs := flag.NewFlagSet("put", flag.ContinueOnError)
@@ -276,36 +202,6 @@
 	return nil
 }
 
-// put go1.4 in the workdir
-func put14(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("put14", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "put14 usage: gomote put14 <buildlet-name>")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	fs.Parse(args)
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-	name := fs.Arg(0)
-	bc, conf, err := clientAndConf(name)
-	if err != nil {
-		return err
-	}
-	u := conf.GoBootstrapURL(buildEnv)
-	if u == "" {
-		fmt.Printf("No GoBootstrapURL defined for %q; ignoring. (may be baked into image)\n", name)
-		return nil
-	}
-	ctx := context.Background()
-	return bc.PutTarFromURL(ctx, u, "go1.4")
-}
-
 // putBootstrap places the bootstrap version of go in the workdir
 func putBootstrap(args []string) error {
 	fs := flag.NewFlagSet("putbootstrap", flag.ContinueOnError)
@@ -355,72 +251,6 @@
 	return eg.Wait()
 }
 
-// legacyPut single file
-func legacyPut(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("put", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "put usage: gomote put [put-opts] <buildlet-name> <source or '-' for stdin> [destination]")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	modeStr := fs.String("mode", "", "Unix file mode (octal); default to source file mode")
-	fs.Parse(args)
-	if n := fs.NArg(); n < 2 || n > 3 {
-		fs.Usage()
-	}
-
-	bc, err := remoteClient(fs.Arg(0))
-	if err != nil {
-		return err
-	}
-
-	var r io.Reader = os.Stdin
-	var mode os.FileMode = 0666
-
-	src := fs.Arg(1)
-	if src != "-" {
-		f, err := os.Open(src)
-		if err != nil {
-			return err
-		}
-		defer f.Close()
-		r = f
-
-		if *modeStr == "" {
-			fi, err := f.Stat()
-			if err != nil {
-				return err
-			}
-			mode = fi.Mode()
-		}
-	}
-	if *modeStr != "" {
-		modeInt, err := strconv.ParseInt(*modeStr, 8, 64)
-		if err != nil {
-			return err
-		}
-		mode = os.FileMode(modeInt)
-		if !mode.IsRegular() {
-			return fmt.Errorf("bad mode: %v", mode)
-		}
-	}
-
-	dest := fs.Arg(2)
-	if dest == "" {
-		if src == "-" {
-			return errors.New("must specify destination file name when source is standard input")
-		}
-		dest = filepath.Base(src)
-	}
-
-	ctx := context.Background()
-	return bc.Put(ctx, r, dest, mode)
-}
-
 // put single file
 func put(args []string) error {
 	fs := flag.NewFlagSet("put", flag.ContinueOnError)
diff --git a/cmd/gomote/rdp.go b/cmd/gomote/rdp.go
index 65145f5..c977f1a 100644
--- a/cmd/gomote/rdp.go
+++ b/cmd/gomote/rdp.go
@@ -5,88 +5,9 @@
 package main
 
 import (
-	"context"
-	"errors"
-	"flag"
 	"fmt"
-	"io"
-	"log"
-	"net"
-	"os"
-
-	"golang.org/x/build/buildlet"
-	"golang.org/x/sync/errgroup"
 )
 
-const rdpPort = 3389
-
 func rdp(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("rdp", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "rdp usage: gomote rdp [--listen=...] <instance>")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	var listen string
-	fs.StringVar(&listen, "listen", "localhost:"+fmt.Sprint(rdpPort), "local address to listen on")
-	fs.Parse(args)
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-	name := fs.Arg(0)
-	bc, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-
-	ln, err := net.Listen("tcp", listen)
-	if err != nil {
-		return err
-	}
-	log.Printf("Listening on %v to proxy RDP.", ln.Addr())
-	for {
-		c, err := ln.Accept()
-		if err != nil {
-			return err
-		}
-		go handleRDPConn(bc, c)
-	}
-}
-
-func handleRDPConn(bc buildlet.RemoteClient, c net.Conn) {
-	const Lmsgprefix = 64 // new in Go 1.14, harmless before
-	log := log.New(os.Stderr, c.RemoteAddr().String()+": ", log.LstdFlags|Lmsgprefix)
-	log.Printf("accepted connection, dialing buildlet via coordinator proxy...")
-	rwc, err := bc.ProxyTCP(rdpPort)
-	if err != nil {
-		c.Close()
-		log.Printf("failed to connect to buildlet via coordinator: %v", err)
-		return
-	}
-
-	log.Printf("connected to buildlet; proxying data.")
-
-	grp, ctx := errgroup.WithContext(context.Background())
-	grp.Go(func() error {
-		_, err := io.Copy(rwc, c)
-		if err == nil {
-			return errors.New("local client closed")
-		}
-		return fmt.Errorf("error copying from local to remote: %w", err)
-	})
-	grp.Go(func() error {
-		_, err := io.Copy(c, rwc)
-		if err == nil {
-			return errors.New("remote server closed")
-		}
-		return fmt.Errorf("error copying from remote to local: %w", err)
-	})
-	<-ctx.Done()
-	rwc.Close()
-	c.Close()
-	log.Printf("closing RDP connection: %v", grp.Wait())
+	return fmt.Errorf("unimplemented. See go.dev/issue/53272")
 }
diff --git a/cmd/gomote/rm.go b/cmd/gomote/rm.go
index 96aa87f..51026db 100644
--- a/cmd/gomote/rm.go
+++ b/cmd/gomote/rm.go
@@ -14,33 +14,6 @@
 	"golang.org/x/sync/errgroup"
 )
 
-func legacyRm(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("rm", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "rm usage: gomote rm <instance> <file-or-dir>+")
-		fmt.Fprintln(os.Stderr, "          gomote rm <instance> .  (to delete everything)")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	fs.Parse(args)
-
-	if fs.NArg() < 2 {
-		fs.Usage()
-	}
-	name := fs.Arg(0)
-	args = fs.Args()[1:]
-	bc, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-	ctx := context.Background()
-	return bc.RemoveAll(ctx, args...)
-}
-
 func rm(args []string) error {
 	fs := flag.NewFlagSet("rm", flag.ContinueOnError)
 	fs.Usage = func() {
diff --git a/cmd/gomote/run.go b/cmd/gomote/run.go
index 6beb837..766f286 100644
--- a/cmd/gomote/run.go
+++ b/cmd/gomote/run.go
@@ -17,90 +17,12 @@
 	"strings"
 	"sync"
 
-	"golang.org/x/build/buildlet"
-	"golang.org/x/build/dashboard"
-	"golang.org/x/build/internal/envutil"
 	"golang.org/x/build/internal/gomote/protos"
 	"golang.org/x/sync/errgroup"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
 
-func legacyRun(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("run", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "run usage: gomote run [run-opts] <instance> <cmd> [args...]")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	var sys bool
-	fs.BoolVar(&sys, "system", false, "run inside the system, and not inside the workdir; this is implicit if cmd starts with '/'")
-	var debug bool
-	fs.BoolVar(&debug, "debug", false, "write debug info about the command's execution before it begins")
-	var env stringSlice
-	fs.Var(&env, "e", "Environment variable KEY=value. The -e flag may be repeated multiple times to add multiple things to the environment.")
-	var firewall bool
-	fs.BoolVar(&firewall, "firewall", false, "Enable outbound firewall on machine. This is on by default on many builders (where supported) but disabled by default on gomote for ease of debugging. Once any command has been run with the -firewall flag on, it's on for the lifetime of that gomote instance.")
-	var path string
-	fs.StringVar(&path, "path", "", "Comma-separated list of ExecOpts.Path elements. The special string 'EMPTY' means to run without any $PATH. The empty string (default) does not modify the $PATH. Otherwise, the following expansions apply: the string '$PATH' expands to the current PATH element(s), the substring '$WORKDIR' expands to the buildlet's temp workdir.")
-
-	var dir string
-	fs.StringVar(&dir, "dir", "", "Directory to run from. Defaults to the directory of the command, or the work directory if -system is true.")
-	var builderEnv string
-	fs.StringVar(&builderEnv, "builderenv", "", "Optional alternate builder to act like. Must share the same underlying buildlet host type, or it's an error. For instance, linux-amd64-race or linux-386-387 are compatible with linux-amd64, but openbsd-amd64 and openbsd-386 are different hosts.")
-
-	fs.Parse(args)
-	if fs.NArg() < 2 {
-		fs.Usage()
-	}
-	name, cmd := fs.Arg(0), fs.Arg(1)
-
-	var conf *dashboard.BuildConfig
-
-	bc, conf, err := clientAndConf(name)
-	if err != nil {
-		return err
-	}
-
-	if builderEnv != "" {
-		altConf, ok := dashboard.Builders[builderEnv]
-		if !ok {
-			return fmt.Errorf("unknown --builderenv=%q builder value", builderEnv)
-		}
-		if altConf.HostType != conf.HostType {
-			return fmt.Errorf("--builderEnv=%q has host type %q, which is not compatible with the named buildlet's host type %q",
-				builderEnv, altConf.HostType, conf.HostType)
-		}
-		conf = altConf
-	}
-
-	var pathOpt []string
-	if path == "EMPTY" {
-		pathOpt = []string{} // non-nil
-	} else if path != "" {
-		pathOpt = strings.Split(path, ",")
-	}
-	env = append(env, "GO_DISABLE_OUTBOUND_NETWORK="+fmt.Sprint(firewall))
-
-	remoteErr, execErr := bc.Exec(context.Background(), cmd, buildlet.ExecOpts{
-		Dir:         dir,
-		SystemLevel: sys || strings.HasPrefix(cmd, "/"),
-		Output:      os.Stdout,
-		Args:        fs.Args()[2:],
-		ExtraEnv:    envutil.Dedup(conf.GOOS(), append(conf.Env(), []string(env)...)),
-		Debug:       debug,
-		Path:        pathOpt,
-	})
-	if execErr != nil {
-		return fmt.Errorf("Error trying to execute %s: %w", cmd, execErr)
-	}
-	return remoteErr
-}
-
 // stringSlice implements flag.Value, specifically for storing environment
 // variable key=value pairs.
 type stringSlice []string
diff --git a/cmd/gomote/ssh.go b/cmd/gomote/ssh.go
index ba55588..85487f8 100644
--- a/cmd/gomote/ssh.go
+++ b/cmd/gomote/ssh.go
@@ -15,54 +15,10 @@
 	"os/exec"
 	"path/filepath"
 	"strings"
-	"syscall"
 
 	"golang.org/x/build/internal/gomote/protos"
-	"golang.org/x/build/internal/gophers"
 )
 
-func legacySSH(args []string) error {
-	if activeGroup != nil {
-		return fmt.Errorf("command does not support groups")
-	}
-
-	fs := flag.NewFlagSet("ssh", flag.ContinueOnError)
-	fs.Usage = func() {
-		fmt.Fprintln(os.Stderr, "ssh usage: gomote ssh <instance>")
-		fs.PrintDefaults()
-		os.Exit(1)
-	}
-	var mutable bool
-	fs.BoolVar(&mutable, "i-will-not-break-the-host", false, "required for older host configs with reused filesystems; using this says that you are aware that your changes to the machine's root filesystem affect future builds. This is a no-op for the newer, safe host configs.")
-	fs.Parse(args)
-	if fs.NArg() != 1 {
-		fs.Usage()
-	}
-	name := fs.Arg(0)
-	_, err := remoteClient(name)
-	if err != nil {
-		return err
-	}
-	// gomoteUser extracts "gopher" from "user-gopher-linux-amd64-0".
-	gomoteUser := strings.Split(name, "-")[1]
-	githubUser := gophers.GitHubOfGomoteUser(gomoteUser)
-
-	sshUser := name
-	if mutable {
-		sshUser = "mutable-" + sshUser
-	}
-
-	ssh, err := exec.LookPath("ssh")
-	if err != nil {
-		log.Printf("No 'ssh' binary found in path so can't run:")
-	}
-	fmt.Printf("$ ssh -p 2222 %s@farmer.golang.org # auth using https://github.com/%s.keys\n", sshUser, githubUser)
-
-	// Best effort, where supported:
-	syscall.Exec(ssh, []string{"ssh", "-p", "2222", sshUser + "@farmer.golang.org"}, os.Environ())
-	return nil
-}
-
 func ssh(args []string) error {
 	if activeGroup != nil {
 		return fmt.Errorf("command does not support groups")