2018-10-24 21:18:19 +00:00
|
|
|
// Copyright (c) 2013 The Go Authors. All rights reserved.
|
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd.
|
|
|
|
|
|
|
|
// golint lints the Go source files named on its command line.
|
2018-11-28 17:11:16 +00:00
|
|
|
package main
|
2018-10-24 21:18:19 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"go/build"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"golang.org/x/lint"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
minConfidence = flag.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")
|
|
|
|
setExitStatus = flag.Bool("set_exit_status", false, "set exit status to 1 if any issues are found")
|
|
|
|
suggestions int
|
|
|
|
)
|
|
|
|
|
|
|
|
func usage() {
|
|
|
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
|
|
|
fmt.Fprintf(os.Stderr, "\tgolint [flags] # runs on package in current directory\n")
|
|
|
|
fmt.Fprintf(os.Stderr, "\tgolint [flags] [packages]\n")
|
|
|
|
fmt.Fprintf(os.Stderr, "\tgolint [flags] [directories] # where a '/...' suffix includes all sub-directories\n")
|
|
|
|
fmt.Fprintf(os.Stderr, "\tgolint [flags] [files] # all must belong to a single package\n")
|
|
|
|
fmt.Fprintf(os.Stderr, "Flags:\n")
|
|
|
|
flag.PrintDefaults()
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
flag.Usage = usage
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
if flag.NArg() == 0 {
|
|
|
|
lintDir(".")
|
|
|
|
} else {
|
|
|
|
// dirsRun, filesRun, and pkgsRun indicate whether golint is applied to
|
|
|
|
// directory, file or package targets. The distinction affects which
|
|
|
|
// checks are run. It is no valid to mix target types.
|
|
|
|
var dirsRun, filesRun, pkgsRun int
|
|
|
|
var args []string
|
|
|
|
for _, arg := range flag.Args() {
|
|
|
|
if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-len("/...")]) {
|
|
|
|
dirsRun = 1
|
|
|
|
for _, dirname := range allPackagesInFS(arg) {
|
|
|
|
args = append(args, dirname)
|
|
|
|
}
|
|
|
|
} else if isDir(arg) {
|
|
|
|
dirsRun = 1
|
|
|
|
args = append(args, arg)
|
|
|
|
} else if exists(arg) {
|
|
|
|
filesRun = 1
|
|
|
|
args = append(args, arg)
|
|
|
|
} else {
|
|
|
|
pkgsRun = 1
|
|
|
|
args = append(args, arg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if dirsRun+filesRun+pkgsRun != 1 {
|
|
|
|
usage()
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
switch {
|
|
|
|
case dirsRun == 1:
|
|
|
|
for _, dir := range args {
|
|
|
|
lintDir(dir)
|
|
|
|
}
|
|
|
|
case filesRun == 1:
|
|
|
|
lintFiles(args...)
|
|
|
|
case pkgsRun == 1:
|
|
|
|
for _, pkg := range importPaths(args) {
|
|
|
|
lintPackage(pkg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if *setExitStatus && suggestions > 0 {
|
|
|
|
fmt.Fprintf(os.Stderr, "Found %d lint suggestions; failing.\n", suggestions)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func isDir(filename string) bool {
|
|
|
|
fi, err := os.Stat(filename)
|
|
|
|
return err == nil && fi.IsDir()
|
|
|
|
}
|
|
|
|
|
|
|
|
func exists(filename string) bool {
|
|
|
|
_, err := os.Stat(filename)
|
|
|
|
return err == nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func lintFiles(filenames ...string) {
|
|
|
|
files := make(map[string][]byte)
|
|
|
|
for _, filename := range filenames {
|
|
|
|
src, err := ioutil.ReadFile(filename)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
files[filename] = src
|
|
|
|
}
|
|
|
|
|
|
|
|
l := new(lint.Linter)
|
|
|
|
ps, err := l.LintFiles(files)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, p := range ps {
|
|
|
|
if p.Confidence >= *minConfidence {
|
|
|
|
fmt.Printf("%v: %s\n", p.Position, p.Text)
|
|
|
|
suggestions++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func lintDir(dirname string) {
|
|
|
|
pkg, err := build.ImportDir(dirname, 0)
|
|
|
|
lintImportedPackage(pkg, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func lintPackage(pkgname string) {
|
|
|
|
pkg, err := build.Import(pkgname, ".", 0)
|
|
|
|
lintImportedPackage(pkg, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func lintImportedPackage(pkg *build.Package, err error) {
|
|
|
|
if err != nil {
|
|
|
|
if _, nogo := err.(*build.NoGoError); nogo {
|
|
|
|
// Don't complain if the failure is due to no Go source files.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var files []string
|
|
|
|
files = append(files, pkg.GoFiles...)
|
|
|
|
files = append(files, pkg.CgoFiles...)
|
|
|
|
files = append(files, pkg.TestGoFiles...)
|
|
|
|
if pkg.Dir != "." {
|
|
|
|
for i, f := range files {
|
|
|
|
files[i] = filepath.Join(pkg.Dir, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO(dsymonds): Do foo_test too (pkg.XTestGoFiles)
|
|
|
|
|
|
|
|
lintFiles(files...)
|
|
|
|
}
|