gitee.com/wgliang/goreporter@v0.0.0-20180902115603-df1b20f7c5d0/linters/golint/linter.go (about)

     1  // Copyright (c) 2013 The Go Authors. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file or at
     5  // https://developers.google.com/open-source/licenses/bsd.
     6  
     7  // golint lints the Go source files named on its command line.
     8  package golint
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  	"go/build"
    14  	"io/ioutil"
    15  	"os"
    16  	"path/filepath"
    17  	"strings"
    18  )
    19  
    20  var (
    21  	minConfidence = flag.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")
    22  	setExitStatus = flag.Bool("set_exit_status", false, "set exit status to 1 if any issues are found")
    23  	suggestions   int
    24  )
    25  
    26  func usage() {
    27  	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
    28  	fmt.Fprintf(os.Stderr, "\tgolint [flags] # runs on package in current directory\n")
    29  	fmt.Fprintf(os.Stderr, "\tgolint [flags] [packages]\n")
    30  	fmt.Fprintf(os.Stderr, "\tgolint [flags] [directories] # where a '/...' suffix includes all sub-directories\n")
    31  	fmt.Fprintf(os.Stderr, "\tgolint [flags] [files] # all must belong to a single package\n")
    32  	fmt.Fprintf(os.Stderr, "Flags:\n")
    33  	flag.PrintDefaults()
    34  }
    35  
    36  func GoLinter(projectPath []string) (results []string) {
    37  	flag.Usage = usage
    38  	flag.Parse()
    39  
    40  	// dirsRun, filesRun, and pkgsRun indicate whether golint is applied to
    41  	// directory, file or package targets. The distinction affects which
    42  	// checks are run. It is no valid to mix target types.
    43  	var dirsRun, filesRun, pkgsRun int
    44  	var args []string
    45  	for _, arg := range projectPath {
    46  		if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-len("/...")]) {
    47  			dirsRun = 1
    48  			args = append(args, allPackagesInFS(arg)...)
    49  		} else if isDir(arg) {
    50  			dirsRun = 1
    51  			args = append(args, arg)
    52  		} else if exists(arg) {
    53  			filesRun = 1
    54  			args = append(args, arg)
    55  		} else {
    56  			pkgsRun = 1
    57  			args = append(args, arg)
    58  		}
    59  	}
    60  
    61  	if dirsRun+filesRun+pkgsRun != 1 {
    62  		usage()
    63  		os.Exit(2)
    64  	}
    65  	switch {
    66  	case dirsRun == 1:
    67  		for _, dir := range args {
    68  			results = append(results, lintDir(dir)...)
    69  		}
    70  	case filesRun == 1:
    71  		return lintFiles(args...)
    72  	case pkgsRun == 1:
    73  		for _, pkg := range importPaths(args) {
    74  			results = append(results, lintPackage(pkg)...)
    75  		}
    76  	}
    77  
    78  	return
    79  }
    80  
    81  func isDir(filename string) bool {
    82  	fi, err := os.Stat(filename)
    83  	return err == nil && fi.IsDir()
    84  }
    85  
    86  func exists(filename string) bool {
    87  	_, err := os.Stat(filename)
    88  	return err == nil
    89  }
    90  
    91  func lintFiles(filenames ...string) (results []string) {
    92  	files := make(map[string][]byte)
    93  	for _, filename := range filenames {
    94  		src, err := ioutil.ReadFile(filename)
    95  		if err != nil {
    96  			fmt.Fprintln(os.Stderr, err)
    97  			continue
    98  		}
    99  		files[filename] = src
   100  	}
   101  
   102  	l := new(Linter)
   103  	ps, err := l.LintFiles(files)
   104  	if err != nil {
   105  		fmt.Fprintf(os.Stderr, "%v\n", err)
   106  		return
   107  	}
   108  
   109  	for _, p := range ps {
   110  		if p.Confidence >= *minConfidence {
   111  			results = append(results, fmt.Sprintf("%v: %s", p.Position, p.Text))
   112  			// suggestions++
   113  		}
   114  	}
   115  	return results
   116  }
   117  
   118  func lintDir(dirname string) []string {
   119  	pkg, err := build.ImportDir(dirname, 0)
   120  	return lintImportedPackage(pkg, err)
   121  }
   122  
   123  func lintPackage(pkgname string) []string {
   124  	pkg, err := build.Import(pkgname, ".", 0)
   125  	return lintImportedPackage(pkg, err)
   126  }
   127  
   128  func lintImportedPackage(pkg *build.Package, err error) (results []string) {
   129  	if err != nil {
   130  		if _, nogo := err.(*build.NoGoError); nogo {
   131  			// Don't complain if the failure is due to no Go source files.
   132  			return
   133  		}
   134  		fmt.Fprintln(os.Stderr, err)
   135  		return
   136  	}
   137  
   138  	var files []string
   139  	files = append(files, pkg.GoFiles...)
   140  	files = append(files, pkg.CgoFiles...)
   141  	files = append(files, pkg.TestGoFiles...)
   142  	if pkg.Dir != "." {
   143  		for i, f := range files {
   144  			files[i] = filepath.Join(pkg.Dir, f)
   145  		}
   146  	}
   147  	// TODO(dsymonds): Do foo_test too (pkg.XTestGoFiles)
   148  
   149  	return lintFiles(files...)
   150  }