Skip to content

Commit

Permalink
cmd/gomote: add -until flag to the run command
Browse files Browse the repository at this point in the history
For golang/go#53956.

Change-Id: If2ff0fc245948c72f992c930127d5d595ac2d868
Reviewed-on: https://go-review.googlesource.com/c/build/+/418894
Auto-Submit: Michael Knyszek <[email protected]>
Run-TryBot: Michael Knyszek <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Carlos Amedee <[email protected]>
  • Loading branch information
mknyszek authored and gopherbot committed Nov 18, 2022
1 parent c46b371 commit d261e68
Showing 1 changed file with 60 additions and 22 deletions.
82 changes: 60 additions & 22 deletions cmd/gomote/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
package main

import (
"bytes"
"context"
"errors"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"sync"

Expand Down Expand Up @@ -141,11 +143,23 @@ func run(args []string) error {
var collect bool
fs.BoolVar(&collect, "collect", false, "Collect artifacts (stdout, work dir .tar.gz) into $PWD once complete.")

var untilPattern string
fs.StringVar(&untilPattern, "until", "", "Run command repeatedly until the output matches the provided regexp.")

fs.Parse(args)
if fs.NArg() == 0 {
fs.Usage()
}

var until *regexp.Regexp
var err error
if untilPattern != "" {
until, err = regexp.Compile(untilPattern)
if err != nil {
return fmt.Errorf("bad regexp %q for 'until': %v", untilPattern, err)
}
}

var cmd string
var cmdArgs []string
var runSet []string
Expand Down Expand Up @@ -187,7 +201,6 @@ func run(args []string) error {
// This is useful even if we don't have multiple gomotes running, since
// it's easy to accidentally lose the output.
var outDir string
var err error
if collect {
outDir, err = os.Getwd()
if err != nil {
Expand Down Expand Up @@ -228,32 +241,57 @@ func run(args []string) error {
if len(runSet) == 1 {
outputs = append(outputs, os.Stdout)
}
err = doRun(
ctx,
inst,
cmd,
cmdArgs,
runDir(dir),
runBuilderEnv(builderEnv),
runEnv(env),
runPath(pathOpt),
runSystem(sys),
runDebug(debug),
runFirewall(firewall),
runWriters(outputs...),
)
// If it's just that the command failed, don't exit just yet, and don't return
// an error to the errgroup because we want the other commands to keep going.
if err != nil {
ce, ok := err.(*cmdFailedError)
if !ok {
return err
// Give ourselves the output too so that we can match against it.
var outBuf bytes.Buffer
if until != nil {
outputs = append(outputs, &outBuf)
}
var ce *cmdFailedError
for {
err := doRun(
ctx,
inst,
cmd,
cmdArgs,
runDir(dir),
runBuilderEnv(builderEnv),
runEnv(env),
runPath(pathOpt),
runSystem(sys),
runDebug(debug),
runFirewall(firewall),
runWriters(outputs...),
)
// If it's just that the command failed, don't exit just yet, and don't return
// an error to the errgroup because we want the other commands to keep going.
if err != nil {
var ok bool
ce, ok = err.(*cmdFailedError)
if !ok {
return err
}
}
if until == nil || until.Match(outBuf.Bytes()) {
break
}
// Reset the output file and our buffer for the next run.
outBuf.Reset()
if err := outf.Truncate(0); err != nil {
return fmt.Errorf("failed to truncate output file %q: %v", outf.Name(), err)
}

fmt.Fprintf(os.Stderr, "# No match found on %q, running again...\n", inst)
}
if until != nil {
fmt.Fprintf(os.Stderr, "# Match found on %q.\n", inst)
}
if ce != nil {
// N.B. If err this wasn't a cmdFailedError
cmdsFailedMu.Lock()
cmdsFailed = append(cmdsFailed, ce)
cmdsFailedMu.Unlock()
// Write out the error.
_, err := io.MultiWriter(outputs...).Write([]byte(err.Error() + "\n"))
_, err := io.MultiWriter(outputs...).Write([]byte(ce.Error() + "\n"))
if err != nil {
fmt.Fprintf(os.Stderr, "failed to write error to output: %v", err)
}
Expand Down

0 comments on commit d261e68

Please sign in to comment.