github.com/gamechanger/errcheck@v0.0.0-20190204213044-2847c07a5541/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "go/build" 7 "os" 8 "path/filepath" 9 "regexp" 10 "runtime" 11 "strings" 12 13 "github.com/gamechanger/errcheck/internal/errcheck" 14 "github.com/kisielk/gotool" 15 ) 16 17 const ( 18 exitCodeOk int = iota 19 exitUncheckedError 20 exitFatalError 21 ) 22 23 var abspath bool 24 25 type ignoreFlag map[string]*regexp.Regexp 26 27 func (f ignoreFlag) String() string { 28 pairs := make([]string, 0, len(f)) 29 for pkg, re := range f { 30 prefix := "" 31 if pkg != "" { 32 prefix = pkg + ":" 33 } 34 pairs = append(pairs, prefix+re.String()) 35 } 36 return fmt.Sprintf("%q", strings.Join(pairs, ",")) 37 } 38 39 func (f ignoreFlag) Set(s string) error { 40 if s == "" { 41 return nil 42 } 43 for _, pair := range strings.Split(s, ",") { 44 colonIndex := strings.Index(pair, ":") 45 var pkg, re string 46 if colonIndex == -1 { 47 pkg = "" 48 re = pair 49 } else { 50 pkg = pair[:colonIndex] 51 re = pair[colonIndex+1:] 52 } 53 regex, err := regexp.Compile(re) 54 if err != nil { 55 return err 56 } 57 f[pkg] = regex 58 } 59 return nil 60 } 61 62 type tagsFlag []string 63 64 func (f *tagsFlag) String() string { 65 return fmt.Sprintf("%q", strings.Join(*f, " ")) 66 } 67 68 func (f *tagsFlag) Set(s string) error { 69 if s == "" { 70 return nil 71 } 72 tags := strings.Split(s, " ") 73 if tags == nil { 74 return nil 75 } 76 for _, tag := range tags { 77 if tag != "" { 78 *f = append(*f, tag) 79 } 80 } 81 return nil 82 } 83 84 var dotStar = regexp.MustCompile(".*") 85 86 func reportUncheckedErrors(e *errcheck.UncheckedErrors) { 87 wd, err := os.Getwd() 88 if err != nil { 89 wd = "" 90 } 91 for _, uncheckedError := range e.Errors { 92 pos := uncheckedError.Pos.String() 93 if !abspath { 94 newPos, err := filepath.Rel(wd, pos) 95 if err == nil { 96 pos = newPos 97 } 98 } 99 fmt.Printf("%s\t%s\n", pos, uncheckedError.Line) 100 } 101 } 102 103 func mainCmd(args []string) int { 104 runtime.GOMAXPROCS(runtime.NumCPU()) 105 106 checker := &errcheck.Checker{} 107 paths, err := parseFlags(checker, args) 108 if err != exitCodeOk { 109 return err 110 } 111 112 if err := checker.CheckPackages(paths...); err != nil { 113 if e, ok := err.(*errcheck.UncheckedErrors); ok { 114 reportUncheckedErrors(e) 115 return exitUncheckedError 116 } else if err == errcheck.ErrNoGoFiles { 117 fmt.Fprintln(os.Stderr, err) 118 return exitCodeOk 119 } 120 fmt.Fprintf(os.Stderr, "error: failed to check packages: %s\n", err) 121 return exitFatalError 122 } 123 return exitCodeOk 124 } 125 126 func parseFlags(checker *errcheck.Checker, args []string) ([]string, int) { 127 flags := flag.NewFlagSet(args[0], flag.ContinueOnError) 128 flags.BoolVar(&checker.Blank, "blank", false, "if true, check for errors assigned to blank identifier") 129 flags.BoolVar(&checker.Asserts, "asserts", false, "if true, check for ignored type assertion results") 130 flags.BoolVar(&checker.WithoutTests, "ignoretests", false, "if true, checking of _test.go files is disabled") 131 flags.BoolVar(&checker.Verbose, "verbose", false, "produce more verbose logging") 132 133 flags.BoolVar(&abspath, "abspath", false, "print absolute paths to files") 134 135 tags := tagsFlag{} 136 flags.Var(&tags, "tags", "space-separated list of build tags to include") 137 ignorePkg := flags.String("ignorepkg", "", "comma-separated list of package paths to ignore") 138 ignore := ignoreFlag(map[string]*regexp.Regexp{ 139 "fmt": dotStar, 140 }) 141 flags.Var(ignore, "ignore", "comma-separated list of pairs of the form pkg:regex\n"+ 142 " the regex is used to ignore names within pkg") 143 144 if err := flags.Parse(args[1:]); err != nil { 145 return nil, exitFatalError 146 } 147 148 checker.Tags = tags 149 for _, pkg := range strings.Split(*ignorePkg, ",") { 150 if pkg != "" { 151 ignore[pkg] = dotStar 152 } 153 } 154 checker.Ignore = ignore 155 156 ctx := gotool.Context{ 157 BuildContext: build.Default, 158 } 159 ctx.BuildContext.BuildTags = tags 160 161 // ImportPaths normalizes paths and expands '...' 162 return gotool.ImportPaths(flags.Args()), exitCodeOk 163 } 164 165 func main() { 166 os.Exit(mainCmd(os.Args)) 167 }