golint.go 3.7 KB

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