github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/tools/runner/serial.go (about)

     1  // Copyright 2016 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package runner
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"runtime"
    14  
    15  	"github.com/attic-labs/noms/go/d"
    16  )
    17  
    18  // Env is a map of env vars, mapping key string to value string.
    19  type Env map[string]string
    20  
    21  func (e Env) toStrings() (out []string) {
    22  	out = os.Environ()
    23  	// Sadly, it seems like we need to force-set GOROOT in the environment to handle some funky runtime environments (e.g. on our Travis setup)
    24  	if e == nil {
    25  		e = Env{}
    26  	}
    27  
    28  	if _, overridden := e["GOROOT"]; !overridden {
    29  		e["GOROOT"] = runtime.GOROOT()
    30  	}
    31  	for n, v := range e {
    32  		out = append(out, fmt.Sprintf("%s=%s", n, v))
    33  	}
    34  	return
    35  }
    36  
    37  // ForceRun runs 'exe [args...]' in current working directory, and d.Chk()s on failure. Inherits the environment of the current process.
    38  func ForceRun(exe string, args ...string) {
    39  	err := runEnvDir(os.Stdout, os.Stderr, Env{}, "", exe, args...)
    40  	d.Chk.NoError(err)
    41  }
    42  
    43  // ForceRunInDir runs 'exe [args...]' in the given directory, and d.Chk()s on failure. Inherits the environment of the current process.
    44  func ForceRunInDir(dir string, env Env, exe string, args ...string) {
    45  	info, err := os.Stat(dir)
    46  	if err != nil {
    47  		d.Panic("Can't stat %s", dir)
    48  	}
    49  	if !info.IsDir() {
    50  		d.Panic("%s must be a path to a directory.", dir)
    51  	}
    52  	d.Chk.NoError(runEnvDir(os.Stdout, os.Stderr, env, dir, exe, args...))
    53  }
    54  
    55  // RunInDir runs 'exe [args...]' in the given directory, returning any failure. The child's stdout and stderr are mapped to out and err respectively. Inherits the environment of the current process.
    56  func RunInDir(out, err io.Writer, dir, exe string, args ...string) error {
    57  	return runEnvDir(out, err, Env{}, dir, exe, args...)
    58  }
    59  
    60  // runEnvDir 'exe [args...]' in dir with the environment env overlaid on that of the current process. If dir == "", use the current working directory.
    61  func runEnvDir(out, err io.Writer, env Env, dir, exe string, args ...string) error {
    62  	cmd := exec.Command(exe, args...)
    63  	cmd.Dir = dir
    64  	cmd.Env = env.toStrings()
    65  	cmd.Stdout = out
    66  	cmd.Stderr = err
    67  	return cmd.Run()
    68  }
    69  
    70  // Serial serially runs all instances of filename found under dir, mapping stdout and stderr to each subprocess in the obvious way. env is overlaid on the environment of the current process. If args are provided, they're passed en masse to each subprocess.
    71  func Serial(stdout, stderr io.Writer, env Env, dir, filename string, args ...string) bool {
    72  	success := true
    73  	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
    74  		if os.IsNotExist(err) {
    75  			// Some programs like npm create temporary log files which confuse filepath.Walk.
    76  			return nil
    77  		}
    78  		if err != nil {
    79  			d.Panic("Failed directory traversal at %s", path)
    80  		}
    81  		if !info.IsDir() && filepath.Base(path) == filename {
    82  			scriptAndArgs := append([]string{filepath.Base(path)}, args...)
    83  			runErr := runEnvDir(stdout, stderr, env, filepath.Dir(path), "python", scriptAndArgs...)
    84  			if runErr != nil {
    85  				success = false
    86  				fmt.Fprintf(stderr, "Running %s failed with %v\n", path, runErr)
    87  			}
    88  		}
    89  		return nil
    90  	})
    91  	d.PanicIfError(err)
    92  	return success
    93  }