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  }