github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/dashboard/builder/exec.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "io" 10 "log" 11 "os/exec" 12 "time" 13 ) 14 15 // run runs a command with optional arguments. 16 func run(cmd *exec.Cmd, opts ...runOpt) error { 17 a := runArgs{cmd, *cmdTimeout} 18 for _, opt := range opts { 19 opt.modArgs(&a) 20 } 21 if *verbose { 22 log.Printf("running %v in %v", a.cmd.Args, a.cmd.Dir) 23 } 24 if err := cmd.Start(); err != nil { 25 return err 26 } 27 err := timeout(a.timeout, cmd.Wait) 28 if _, ok := err.(timeoutError); ok { 29 cmd.Process.Kill() 30 } 31 return err 32 } 33 34 // Zero or more runOpts can be passed to run to modify the command 35 // before it's run. 36 type runOpt interface { 37 modArgs(*runArgs) 38 } 39 40 // allOutput sends both stdout and stderr to w. 41 func allOutput(w io.Writer) optFunc { 42 return func(a *runArgs) { 43 a.cmd.Stdout = w 44 a.cmd.Stderr = w 45 } 46 } 47 48 func runTimeout(timeout time.Duration) optFunc { 49 return func(a *runArgs) { 50 a.timeout = timeout 51 } 52 } 53 54 func runDir(dir string) optFunc { 55 return func(a *runArgs) { 56 a.cmd.Dir = dir 57 } 58 } 59 60 func runEnv(env []string) optFunc { 61 return func(a *runArgs) { 62 a.cmd.Env = env 63 } 64 } 65 66 // timeout runs f and returns its error value, or if the function does not 67 // complete before the provided duration it returns a timeout error. 68 func timeout(d time.Duration, f func() error) error { 69 errc := make(chan error, 1) 70 go func() { 71 errc <- f() 72 }() 73 t := time.NewTimer(d) 74 defer t.Stop() 75 select { 76 case <-t.C: 77 return timeoutError(d) 78 case err := <-errc: 79 return err 80 } 81 } 82 83 type timeoutError time.Duration 84 85 func (e timeoutError) Error() string { 86 return fmt.Sprintf("timed out after %v", time.Duration(e)) 87 } 88 89 // optFunc implements runOpt with a function, like http.HandlerFunc. 90 type optFunc func(*runArgs) 91 92 func (f optFunc) modArgs(a *runArgs) { f(a) } 93 94 // internal detail to exec.go: 95 type runArgs struct { 96 cmd *exec.Cmd 97 timeout time.Duration 98 }