|
1 | 1 | package cmd
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
4 | 5 | "context"
|
5 | 6 | "errors"
|
6 | 7 | "fmt"
|
@@ -70,6 +71,10 @@ func setupFlags(name string) (*pflag.FlagSet, *options) {
|
70 | 71 | "use different icons, see help for options")
|
71 | 72 | flags.BoolVar(&opts.rawCommand, "raw-command", false,
|
72 | 73 | "don't prepend 'go test -json' to the 'go test' command")
|
| 74 | + flags.BoolVar(&opts.readStdin, "stdin", false, |
| 75 | + "don't run any command, instead read go test stdout from stdin") |
| 76 | + flags.IntVar(&opts.readStderrFD, "stderr", 0, |
| 77 | + "read go test stderr from a certain `file descriptor` (only valid in combination with -stdin)") |
73 | 78 | flags.BoolVar(&opts.ignoreNonJSONOutputLines, "ignore-non-json-output-lines", false,
|
74 | 79 | "write non-JSON 'go test' output lines to stderr instead of failing")
|
75 | 80 | flags.Lookup("ignore-non-json-output-lines").Hidden = true
|
@@ -176,6 +181,8 @@ type options struct {
|
176 | 181 | formatOptions testjson.FormatOptions
|
177 | 182 | debug bool
|
178 | 183 | rawCommand bool
|
| 184 | + readStdin bool |
| 185 | + readStderrFD int |
179 | 186 | ignoreNonJSONOutputLines bool
|
180 | 187 | jsonFile string
|
181 | 188 | jsonFileTimingEvents string
|
@@ -212,6 +219,15 @@ func (o options) Validate() error {
|
212 | 219 | return fmt.Errorf("-failfast can not be used with --rerun-fails " +
|
213 | 220 | "because not all test cases will run")
|
214 | 221 | }
|
| 222 | + if o.rawCommand && o.readStdin { |
| 223 | + return errors.New("-stdin and -rawCommand are mutually exclusive") |
| 224 | + } |
| 225 | + if o.readStdin && len(o.args) > 0 { |
| 226 | + return fmt.Errorf("-stdin does not support additional arguments (%q)", o.args) |
| 227 | + } |
| 228 | + if o.readStderrFD > 0 && !o.readStdin { |
| 229 | + return errors.New("-stderr depends on -stdin") |
| 230 | + } |
215 | 231 | return nil
|
216 | 232 | }
|
217 | 233 |
|
@@ -264,29 +280,45 @@ func run(opts *options) error {
|
264 | 280 | return err
|
265 | 281 | }
|
266 | 282 |
|
267 |
| - goTestProc, err := startGoTestFn(ctx, "", goTestCmdArgs(opts, rerunOpts{})) |
268 |
| - if err != nil { |
269 |
| - return err |
270 |
| - } |
271 |
| - |
272 | 283 | handler, err := newEventHandler(opts)
|
273 | 284 | if err != nil {
|
274 | 285 | return err
|
275 | 286 | }
|
276 | 287 | defer handler.Close() // nolint: errcheck
|
277 | 288 | cfg := testjson.ScanConfig{
|
278 |
| - Stdout: goTestProc.stdout, |
279 |
| - Stderr: goTestProc.stderr, |
280 | 289 | Handler: handler,
|
281 | 290 | Stop: cancel,
|
282 | 291 | IgnoreNonJSONOutputLines: opts.ignoreNonJSONOutputLines,
|
283 | 292 | }
|
| 293 | + |
| 294 | + var goTestProc *proc |
| 295 | + if opts.readStdin { |
| 296 | + cfg.Stdout = os.Stdin |
| 297 | + if opts.readStderrFD > 0 { |
| 298 | + cfg.Stderr = os.NewFile(uintptr(opts.readStderrFD), fmt.Sprintf("go test stderr on fd %d", opts.stderr)) |
| 299 | + } else { |
| 300 | + cfg.Stderr = bytes.NewReader(nil) |
| 301 | + } |
| 302 | + } else { |
| 303 | + p, err := startGoTestFn(ctx, "", goTestCmdArgs(opts, rerunOpts{})) |
| 304 | + if err != nil { |
| 305 | + return err |
| 306 | + } |
| 307 | + goTestProc = p |
| 308 | + cfg.Stdout = p.stdout |
| 309 | + cfg.Stderr = p.stderr |
| 310 | + } |
| 311 | + |
284 | 312 | exec, err := testjson.ScanTestOutput(cfg)
|
285 | 313 | handler.Flush()
|
286 | 314 | if err != nil {
|
287 | 315 | return finishRun(opts, exec, err)
|
288 | 316 | }
|
289 | 317 |
|
| 318 | + if opts.readStdin { |
| 319 | + return finishRun(opts, exec, nil) |
| 320 | + } |
| 321 | + |
290 | 322 | exitErr := goTestProc.cmd.Wait()
|
291 | 323 | if signum := atomic.LoadInt32(&goTestProc.signal); signum != 0 {
|
292 | 324 | return finishRun(opts, exec, exitError{num: signalExitCode + int(signum)})
|
|
0 commit comments