github.com/serversong/goreporter@v0.0.0-20200325104552-3cfaf44fd178/linters/simplecode/lint/lintutil/util.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  // Package lintutil provides helpers for writing linter command lines.
     8  package lintutil // import "github.com/360EntSecGroup-Skylar/goreporter/linters/simplecode/lint/lintutil"
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  	"go/build"
    14  	"io/ioutil"
    15  	"os"
    16  	"path/filepath"
    17  	"strings"
    18  
    19  	"github.com/360EntSecGroup-Skylar/goreporter/linters/simplecode/lint"
    20  
    21  	"github.com/360EntSecGroup-Skylar/goreporter/linters/simplecode/gotool"
    22  )
    23  
    24  var (
    25  	excepts = []string{"vendor"}
    26  )
    27  
    28  func usage(name string, flags *flag.FlagSet) func() {
    29  	return func() {
    30  		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
    31  		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
    32  		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
    33  		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
    34  		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
    35  		fmt.Fprintf(os.Stderr, "Flags:\n")
    36  		flags.PrintDefaults()
    37  	}
    38  }
    39  
    40  type runner struct {
    41  	funcs         []lint.Func
    42  	minConfidence float64
    43  	tags          []string
    44  	SimpleResult  []string
    45  
    46  	unclean bool
    47  }
    48  
    49  func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) {
    50  	if len(importPaths) == 0 {
    51  		return false, nil
    52  	}
    53  	if strings.HasSuffix(importPaths[0], ".go") {
    54  		// User is specifying a package in terms of .go files, don't resolve
    55  		return true, nil
    56  	}
    57  	wd, err := os.Getwd()
    58  	if err != nil {
    59  		return false, err
    60  	}
    61  	ctx := build.Default
    62  	ctx.BuildTags = runner.tags
    63  	for i, path := range importPaths {
    64  		githubIndex := strings.LastIndex(path, "github.com")
    65  		if githubIndex < len(path) && githubIndex >= 0 {
    66  			path = path[githubIndex:]
    67  		}
    68  		bpkg, err := ctx.Import(path, wd, build.FindOnly)
    69  		if err != nil {
    70  			return false, fmt.Errorf("can't load package %q: %v", path, err)
    71  		}
    72  		importPaths[i] = bpkg.ImportPath
    73  	}
    74  	return false, nil
    75  }
    76  
    77  func ProcessArgs(except, name string, funcs []lint.Func, args []string) []string {
    78  	excepts = append(excepts, strings.Split(except, ",")...)
    79  	flags := &flag.FlagSet{}
    80  	flags.Usage = usage(name, flags)
    81  	var minConfidence = flags.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")
    82  	var tags = flags.String("tags", "", "List of `build tags`")
    83  	flags.Parse(args)
    84  
    85  	runner := &runner{
    86  		funcs:         funcs,
    87  		minConfidence: *minConfidence,
    88  		tags:          strings.Fields(*tags),
    89  	}
    90  	paths := gotool.ImportPaths(flags.Args())
    91  	goFiles, err := runner.resolveRelative(paths)
    92  	if err != nil {
    93  		fmt.Fprintln(os.Stderr, err)
    94  		runner.unclean = true
    95  	}
    96  	if goFiles {
    97  		runner.lintFiles(paths...)
    98  	} else {
    99  		for _, path := range paths {
   100  			runner.lintPackage(path)
   101  		}
   102  	}
   103  	return runner.SimpleResult
   104  }
   105  
   106  func (runner *runner) lintFiles(filenames ...string) {
   107  	files := make(map[string][]byte)
   108  	for _, filename := range filenames {
   109  		src, err := ioutil.ReadFile(filename)
   110  		if err != nil {
   111  			fmt.Fprintln(os.Stderr, err)
   112  			runner.unclean = true
   113  			continue
   114  		}
   115  		files[filename] = src
   116  	}
   117  
   118  	l := &lint.Linter{
   119  		Funcs: runner.funcs,
   120  	}
   121  	ps, err := l.LintFiles(files)
   122  	if err != nil {
   123  		fmt.Fprintf(os.Stderr, "%v\n", err)
   124  		runner.unclean = true
   125  		return
   126  	}
   127  	if len(ps) > 0 {
   128  		runner.unclean = true
   129  	}
   130  	for _, p := range ps {
   131  		if p.Confidence >= runner.minConfidence {
   132  			runner.SimpleResult = append(runner.SimpleResult, fmt.Sprintf("%v: %s", p.Position, p.Text))
   133  		}
   134  	}
   135  }
   136  
   137  func (runner *runner) lintPackage(pkgname string) {
   138  	ctx := build.Default
   139  	ctx.BuildTags = runner.tags
   140  	pkg, err := ctx.Import(pkgname, ".", 0)
   141  	runner.lintImportedPackage(pkg, err)
   142  }
   143  
   144  func (runner *runner) lintImportedPackage(pkg *build.Package, err error) {
   145  	if err != nil {
   146  		if _, nogo := err.(*build.NoGoError); nogo {
   147  			// Don't complain if the failure is due to no Go source files.
   148  			return
   149  		}
   150  		fmt.Fprintln(os.Stderr, err)
   151  		runner.unclean = true
   152  		return
   153  	}
   154  
   155  	var files []string
   156  	xtest := pkg.XTestGoFiles
   157  	files = append(files, filterFiles(pkg.GoFiles, pkg.Dir)...)
   158  	files = append(files, filterFiles(pkg.CgoFiles, pkg.Dir)...)
   159  	files = append(files, filterFiles(pkg.TestGoFiles, pkg.Dir)...)
   160  	if pkg.Dir != "." {
   161  		for i, f := range xtest {
   162  			xtest[i] = filepath.Join(pkg.Dir, f)
   163  		}
   164  	}
   165  	runner.lintFiles(xtest...)
   166  	runner.lintFiles(files...)
   167  }
   168  
   169  func filterFiles(files []string, pkgDir string) (filtedFiles []string) {
   170  	if pkgDir != "." {
   171  		for i, f := range files {
   172  			files[i] = filepath.Join(pkgDir, f)
   173  			if !exceptPkg(files[i]) {
   174  				filtedFiles = append(filtedFiles, files[i])
   175  			}
   176  		}
   177  	} else {
   178  		return files
   179  	}
   180  	return filtedFiles
   181  }
   182  
   183  // exceptPkg is a function that will determine whether the package is an exception.
   184  func exceptPkg(pkg string) bool {
   185  	if len(excepts) == 0 {
   186  		return false
   187  	}
   188  	for _, va := range excepts {
   189  		if strings.Contains(pkg, va) {
   190  			return true
   191  		}
   192  	}
   193  	return false
   194  }