cmd/racebuild: add -copyonfail debugging flag

When debugging new versions of the race detector runtime, it can be
useful to copy the newly built syso back to the local machine's Go
repo (from the gomote) even if race.bat/race.bash fails, so as to
analyze the syso or run other tests with it. Add a command line option
"-copyonfail" that attempts to perform the copy even if the script run
fails.

Updates golang/go#35006.
Updates golang/go#53539.

Change-Id: I688b8673b444d1b6d948f10ca2fa4ab109eade44
Reviewed-on: https://go-review.googlesource.com/c/build/+/415675
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/racebuild/racebuild.go b/cmd/racebuild/racebuild.go
index 95fb9a4..1004fe8 100644
--- a/cmd/racebuild/racebuild.go
+++ b/cmd/racebuild/racebuild.go
@@ -35,6 +35,7 @@
 	flagRev        = flag.String("rev", "", "llvm-project git revision from https://github.com/llvm/llvm-project (required)")
 	flagCherryPick = flag.String("cherrypick", "", "go.googlesource.com CL reference to cherry-pick on top of Go repo (takes form 'refs/changes/NNN/<CL number>/<patchset number>') (optional)")
 	flagCheckout   = flag.String("checkout", "", "go.googlesource.com CL reference to check out on top of Go repo (takes form 'refs/changes/NNN/<CL number>/<patchset number>') (optional)")
+	flagCopyOnFail = flag.Bool("copyonfail", false, "Attempt to copy newly built race syso into Go repo even if script fails.")
 	flagGoRev      = flag.String("gorev", "HEAD", "Go repository revision to use; HEAD is relative to --goroot")
 	flagPlatforms  = flag.String("platforms", "all", `comma-separated platforms (such as "linux/amd64") to rebuild, or "all"`)
 )
@@ -509,11 +510,16 @@
 	if _, err := p.Gomote(ctx, "put", "-mode=0700", p.Inst, script.Name(), targetName); err != nil {
 		return err
 	}
+	var scriptRunErr error
 	gogitop, gosrcref := setupForGoRepoGitOp()
 	if _, err := p.Gomote(ctx, "run", "-e=REV="+*flagRev, "-e=GOREV="+goRev,
 		"-e=GOGITOP="+gogitop, "-e=GOSRCREF="+gosrcref,
 		p.Inst, targetName); err != nil {
-		return err
+		if !*flagCopyOnFail {
+			return err
+		}
+		log.Printf("%v: gomote script run failed, continuing...\n", p.Name())
+		scriptRunErr = err
 	}
 
 	// The script is supposed to leave updated runtime at that path. Copy it out.
@@ -527,6 +533,9 @@
 	if err := p.WriteSyso(filepath.Join(*flagGoroot, "src", "runtime", "race", syso), targz); err != nil {
 		return fmt.Errorf("%v", err)
 	}
+	if scriptRunErr != nil {
+		return err
+	}
 
 	log.Printf("%v: build completed", p.Name())
 	return nil