github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 11 "github.com/fatih/color" 12 "github.com/mgechev/dots" 13 "github.com/mgechev/revive/config" 14 "github.com/mgechev/revive/lint" 15 "github.com/mitchellh/go-homedir" 16 ) 17 18 var ( 19 version = "dev" 20 commit = "none" 21 date = "unknown" 22 builtBy = "unknown" 23 ) 24 25 func fail(err string) { 26 fmt.Fprintln(os.Stderr, err) 27 os.Exit(1) 28 } 29 30 func main() { 31 conf, err := config.GetConfig(configPath) 32 if err != nil { 33 fail(err.Error()) 34 } 35 formatter, err := config.GetFormatter(formatterName) 36 if err != nil { 37 fail(err.Error()) 38 } 39 40 if len(excludePaths) == 0 { // if no excludes were set in the command line 41 excludePaths = conf.Exclude // use those from the configuration 42 } 43 44 packages, err := getPackages(excludePaths) 45 if err != nil { 46 fail(err.Error()) 47 } 48 49 revive := lint.New(func(file string) ([]byte, error) { 50 return ioutil.ReadFile(file) 51 }) 52 53 lintingRules, err := config.GetLintingRules(conf) 54 if err != nil { 55 fail(err.Error()) 56 } 57 58 failures, err := revive.Lint(packages, lintingRules, *conf) 59 if err != nil { 60 fail(err.Error()) 61 } 62 63 formatChan := make(chan lint.Failure) 64 exitChan := make(chan bool) 65 66 var output string 67 go (func() { 68 output, err = formatter.Format(formatChan, *conf) 69 if err != nil { 70 fail(err.Error()) 71 } 72 exitChan <- true 73 })() 74 75 exitCode := 0 76 for f := range failures { 77 if f.Confidence < conf.Confidence { 78 continue 79 } 80 if exitCode == 0 { 81 exitCode = conf.WarningCode 82 } 83 if c, ok := conf.Rules[f.RuleName]; ok && c.Severity == lint.SeverityError { 84 exitCode = conf.ErrorCode 85 } 86 if c, ok := conf.Directives[f.RuleName]; ok && c.Severity == lint.SeverityError { 87 exitCode = conf.ErrorCode 88 } 89 90 formatChan <- f 91 } 92 93 close(formatChan) 94 <-exitChan 95 if output != "" { 96 fmt.Println(output) 97 } 98 99 os.Exit(exitCode) 100 } 101 102 func normalizeSplit(strs []string) []string { 103 res := []string{} 104 for _, s := range strs { 105 t := strings.Trim(s, " \t") 106 if len(t) > 0 { 107 res = append(res, t) 108 } 109 } 110 return res 111 } 112 113 func getPackages(excludePaths arrayFlags) ([][]string, error) { 114 globs := normalizeSplit(flag.Args()) 115 if len(globs) == 0 { 116 globs = append(globs, ".") 117 } 118 119 packages, err := dots.ResolvePackages(globs, normalizeSplit(excludePaths)) 120 if err != nil { 121 return nil, err 122 } 123 124 return packages, nil 125 } 126 127 type arrayFlags []string 128 129 func (i *arrayFlags) String() string { 130 return strings.Join([]string(*i), " ") 131 } 132 133 func (i *arrayFlags) Set(value string) error { 134 *i = append(*i, value) 135 return nil 136 } 137 138 var configPath string 139 var excludePaths arrayFlags 140 var formatterName string 141 var help bool 142 var versionFlag bool 143 144 var originalUsage = flag.Usage 145 146 func getLogo() string { 147 return color.YellowString(` _ __ _____ _(_)__ _____ 148 | '__/ _ \ \ / / \ \ / / _ \ 149 | | | __/\ V /| |\ V / __/ 150 |_| \___| \_/ |_| \_/ \___|`) 151 } 152 153 func getCall() string { 154 return color.MagentaString("revive -config c.toml -formatter friendly -exclude a.go -exclude b.go ./...") 155 } 156 157 func getBanner() string { 158 return fmt.Sprintf(` 159 %s 160 161 Example: 162 %s 163 `, getLogo(), getCall()) 164 } 165 166 func buildDefaultConfigPath() string { 167 var result string 168 if homeDir, err := homedir.Dir(); err == nil { 169 result = filepath.Join(homeDir, "revive.toml") 170 if _, err := os.Stat(result); err != nil { 171 result = "" 172 } 173 } 174 175 return result 176 } 177 178 func init() { 179 // Force colorizing for no TTY environments 180 if os.Getenv("REVIVE_FORCE_COLOR") == "1" { 181 color.NoColor = false 182 } 183 184 flag.Usage = func() { 185 fmt.Println(getBanner()) 186 originalUsage() 187 } 188 189 // command line help strings 190 const ( 191 configUsage = "path to the configuration TOML file, defaults to $HOME/revive.toml, if present (i.e. -config myconf.toml)" 192 excludeUsage = "list of globs which specify files to be excluded (i.e. -exclude foo/...)" 193 formatterUsage = "formatter to be used for the output (i.e. -formatter stylish)" 194 versionUsage = "get revive version" 195 ) 196 197 defaultConfigPath := buildDefaultConfigPath() 198 199 flag.StringVar(&configPath, "config", defaultConfigPath, configUsage) 200 flag.Var(&excludePaths, "exclude", excludeUsage) 201 flag.StringVar(&formatterName, "formatter", "", formatterUsage) 202 flag.BoolVar(&versionFlag, "version", false, versionUsage) 203 flag.Parse() 204 205 // Output build info (version, commit, date and builtBy) 206 if versionFlag { 207 fmt.Printf( 208 "Current revive version %v commit %v, built @%v by %v.\n", 209 version, 210 commit, 211 date, 212 builtBy, 213 ) 214 os.Exit(0) 215 } 216 }