github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/scripts/run-linter.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"flag"
     6  	"fmt"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  	"time"
    13  )
    14  
    15  type result struct {
    16  	name     string
    17  	cmd      string
    18  	passed   bool
    19  	duration time.Duration
    20  	output   []string
    21  }
    22  
    23  // String prints the results of a linter run in gotest format.
    24  func (r *result) String() string {
    25  	buf := &bytes.Buffer{}
    26  
    27  	fmt.Fprintln(buf, "=== RUN", r.name)
    28  	if r.passed {
    29  		fmt.Fprintf(buf, "--- PASS: %s (%s)", r.name, r.duration)
    30  	} else {
    31  		// fmt.Fprintln(buf, "    CMD:", r.cmd)
    32  		fmt.Fprintf(buf, strings.Join(r.output, "\n"))
    33  		fmt.Fprintf(buf, "--- FAIL: %s (%s)", r.name, r.duration)
    34  	}
    35  
    36  	return buf.String()
    37  }
    38  
    39  // fixup goes through the output and improves the output generated by
    40  // specific linters so that all output includes the relative path to the
    41  // error, instead of mixing relative and absolute paths.
    42  func (r *result) fixup(dirname string) {
    43  	for idx, ln := range r.output {
    44  		if strings.HasPrefix(ln, dirname) {
    45  			r.output[idx] = ln[len(dirname)+1:]
    46  		}
    47  	}
    48  }
    49  
    50  // runs the gometalinter on a list of packages; integrating with the "make lint" target.
    51  func main() {
    52  	var (
    53  		lintArgs       string
    54  		lintBin        string
    55  		packageList    string
    56  		output         string
    57  		packages       []string
    58  		results        []*result
    59  		hasFailingTest bool
    60  
    61  		gopath = os.Getenv("GOPATH")
    62  	)
    63  
    64  	flag.StringVar(&lintArgs, "lintArgs", "", "args to pass to gometalinter")
    65  	flag.StringVar(&lintBin, "lintBin", filepath.Join(gopath, "bin", "gometalinter"), "path to go metalinter")
    66  	flag.StringVar(&packageList, "packages", "", "list of space separated packages")
    67  	flag.StringVar(&output, "output", "", "output file for to write results.")
    68  	flag.Parse()
    69  
    70  	packages = strings.Split(strings.Replace(packageList, "-", "/", -1), " ")
    71  	dirname, _ := os.Getwd()
    72  	cwd := filepath.Base(dirname)
    73  	gopath, _ = filepath.Abs(gopath)
    74  	lintArgs += fmt.Sprintf(" --concurrency=%d", runtime.NumCPU()/2)
    75  
    76  	for _, pkg := range packages {
    77  		args := []string{lintBin, lintArgs}
    78  		if cwd == pkg {
    79  			args = append(args, ".")
    80  		} else {
    81  			args = append(args, "./"+pkg)
    82  		}
    83  
    84  		startAt := time.Now()
    85  		cmd := strings.Join(args, " ")
    86  		out, err := exec.Command("sh", "-c", cmd).CombinedOutput()
    87  
    88  		r := &result{
    89  			cmd:      strings.Join(args, " "),
    90  			name:     "lint-" + strings.Replace(pkg, "/", "-", -1),
    91  			passed:   err == nil,
    92  			duration: time.Since(startAt),
    93  			output:   strings.Split(string(out), "\n"),
    94  		}
    95  		r.fixup(dirname)
    96  
    97  		if !r.passed {
    98  			hasFailingTest = true
    99  		}
   100  
   101  		results = append(results, r)
   102  		fmt.Println(r)
   103  	}
   104  
   105  	if output != "" {
   106  		f, err := os.Create(output)
   107  		if err != nil {
   108  			os.Exit(1)
   109  		}
   110  		defer func() {
   111  			if err != f.Close() {
   112  				panic(err)
   113  			}
   114  		}()
   115  
   116  		for _, r := range results {
   117  			f.WriteString(r.String() + "\n")
   118  		}
   119  	}
   120  
   121  	if hasFailingTest {
   122  		os.Exit(1)
   123  	}
   124  }