|
|
- // Copyright 2020 The Gitea Authors. All rights reserved.
- // Copyright (c) 2018 Minko Gechev. All rights reserved.
- // Use of this source code is governed by a MIT-style
- // license that can be found in the LICENSE file.
-
- // +build ignore
-
- package main
-
- import (
- "flag"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/BurntSushi/toml"
- "github.com/mgechev/dots"
- "github.com/mgechev/revive/formatter"
- "github.com/mgechev/revive/lint"
- "github.com/mgechev/revive/rule"
- "github.com/mitchellh/go-homedir"
- )
-
- func fail(err string) {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
- }
-
- var defaultRules = []lint.Rule{
- &rule.VarDeclarationsRule{},
- &rule.PackageCommentsRule{},
- &rule.DotImportsRule{},
- &rule.BlankImportsRule{},
- &rule.ExportedRule{},
- &rule.VarNamingRule{},
- &rule.IndentErrorFlowRule{},
- &rule.IfReturnRule{},
- &rule.RangeRule{},
- &rule.ErrorfRule{},
- &rule.ErrorNamingRule{},
- &rule.ErrorStringsRule{},
- &rule.ReceiverNamingRule{},
- &rule.IncrementDecrementRule{},
- &rule.ErrorReturnRule{},
- &rule.UnexportedReturnRule{},
- &rule.TimeNamingRule{},
- &rule.ContextKeysType{},
- &rule.ContextAsArgumentRule{},
- }
-
- var allRules = append([]lint.Rule{
- &rule.ArgumentsLimitRule{},
- &rule.CyclomaticRule{},
- &rule.FileHeaderRule{},
- &rule.EmptyBlockRule{},
- &rule.SuperfluousElseRule{},
- &rule.ConfusingNamingRule{},
- &rule.GetReturnRule{},
- &rule.ModifiesParamRule{},
- &rule.ConfusingResultsRule{},
- &rule.DeepExitRule{},
- &rule.UnusedParamRule{},
- &rule.UnreachableCodeRule{},
- &rule.AddConstantRule{},
- &rule.FlagParamRule{},
- &rule.UnnecessaryStmtRule{},
- &rule.StructTagRule{},
- &rule.ModifiesValRecRule{},
- &rule.ConstantLogicalExprRule{},
- &rule.BoolLiteralRule{},
- &rule.RedefinesBuiltinIDRule{},
- &rule.ImportsBlacklistRule{},
- &rule.FunctionResultsLimitRule{},
- &rule.MaxPublicStructsRule{},
- &rule.RangeValInClosureRule{},
- &rule.RangeValAddress{},
- &rule.WaitGroupByValueRule{},
- &rule.AtomicRule{},
- &rule.EmptyLinesRule{},
- &rule.LineLengthLimitRule{},
- &rule.CallToGCRule{},
- &rule.DuplicatedImportsRule{},
- &rule.ImportShadowingRule{},
- &rule.BareReturnRule{},
- &rule.UnusedReceiverRule{},
- &rule.UnhandledErrorRule{},
- &rule.CognitiveComplexityRule{},
- &rule.StringOfIntRule{},
- }, defaultRules...)
-
- var allFormatters = []lint.Formatter{
- &formatter.Stylish{},
- &formatter.Friendly{},
- &formatter.JSON{},
- &formatter.NDJSON{},
- &formatter.Default{},
- &formatter.Unix{},
- &formatter.Checkstyle{},
- &formatter.Plain{},
- }
-
- func getFormatters() map[string]lint.Formatter {
- result := map[string]lint.Formatter{}
- for _, f := range allFormatters {
- result[f.Name()] = f
- }
- return result
- }
-
- func getLintingRules(config *lint.Config) []lint.Rule {
- rulesMap := map[string]lint.Rule{}
- for _, r := range allRules {
- rulesMap[r.Name()] = r
- }
-
- lintingRules := []lint.Rule{}
- for name := range config.Rules {
- rule, ok := rulesMap[name]
- if !ok {
- fail("cannot find rule: " + name)
- }
- lintingRules = append(lintingRules, rule)
- }
-
- return lintingRules
- }
-
- func parseConfig(path string) *lint.Config {
- config := &lint.Config{}
- file, err := ioutil.ReadFile(path)
- if err != nil {
- fail("cannot read the config file")
- }
- _, err = toml.Decode(string(file), config)
- if err != nil {
- fail("cannot parse the config file: " + err.Error())
- }
- return config
- }
-
- func normalizeConfig(config *lint.Config) {
- if config.Confidence == 0 {
- config.Confidence = 0.8
- }
- severity := config.Severity
- if severity != "" {
- for k, v := range config.Rules {
- if v.Severity == "" {
- v.Severity = severity
- }
- config.Rules[k] = v
- }
- for k, v := range config.Directives {
- if v.Severity == "" {
- v.Severity = severity
- }
- config.Directives[k] = v
- }
- }
- }
-
- func getConfig() *lint.Config {
- config := defaultConfig()
- if configPath != "" {
- config = parseConfig(configPath)
- }
- normalizeConfig(config)
- return config
- }
-
- func getFormatter() lint.Formatter {
- formatters := getFormatters()
- formatter := formatters["default"]
- if formatterName != "" {
- f, ok := formatters[formatterName]
- if !ok {
- fail("unknown formatter " + formatterName)
- }
- formatter = f
- }
- return formatter
- }
-
- func buildDefaultConfigPath() string {
- var result string
- if homeDir, err := homedir.Dir(); err == nil {
- result = filepath.Join(homeDir, "revive.toml")
- if _, err := os.Stat(result); err != nil {
- result = ""
- }
- }
-
- return result
- }
-
- func defaultConfig() *lint.Config {
- defaultConfig := lint.Config{
- Confidence: 0.0,
- Severity: lint.SeverityWarning,
- Rules: map[string]lint.RuleConfig{},
- }
- for _, r := range defaultRules {
- defaultConfig.Rules[r.Name()] = lint.RuleConfig{}
- }
- return &defaultConfig
- }
-
- func normalizeSplit(strs []string) []string {
- res := []string{}
- for _, s := range strs {
- t := strings.Trim(s, " \t")
- if len(t) > 0 {
- res = append(res, t)
- }
- }
- return res
- }
-
- func getPackages() [][]string {
- globs := normalizeSplit(flag.Args())
- if len(globs) == 0 {
- globs = append(globs, ".")
- }
-
- packages, err := dots.ResolvePackages(globs, normalizeSplit(excludePaths))
- if err != nil {
- fail(err.Error())
- }
-
- return packages
- }
-
- type arrayFlags []string
-
- func (i *arrayFlags) String() string {
- return strings.Join([]string(*i), " ")
- }
-
- func (i *arrayFlags) Set(value string) error {
- *i = append(*i, value)
- return nil
- }
-
- var configPath string
- var excludePaths arrayFlags
- var formatterName string
- var help bool
-
- var originalUsage = flag.Usage
-
- func init() {
- flag.Usage = func() {
- originalUsage()
- }
- // command line help strings
- const (
- configUsage = "path to the configuration TOML file, defaults to $HOME/revive.toml, if present (i.e. -config myconf.toml)"
- excludeUsage = "list of globs which specify files to be excluded (i.e. -exclude foo/...)"
- formatterUsage = "formatter to be used for the output (i.e. -formatter stylish)"
- )
-
- defaultConfigPath := buildDefaultConfigPath()
-
- flag.StringVar(&configPath, "config", defaultConfigPath, configUsage)
- flag.Var(&excludePaths, "exclude", excludeUsage)
- flag.StringVar(&formatterName, "formatter", "", formatterUsage)
- flag.Parse()
- }
-
- func main() {
- config := getConfig()
- formatter := getFormatter()
- packages := getPackages()
-
- revive := lint.New(func(file string) ([]byte, error) {
- return ioutil.ReadFile(file)
- })
-
- lintingRules := getLintingRules(config)
-
- failures, err := revive.Lint(packages, lintingRules, *config)
- if err != nil {
- fail(err.Error())
- }
-
- formatChan := make(chan lint.Failure)
- exitChan := make(chan bool)
-
- var output string
- go (func() {
- output, err = formatter.Format(formatChan, *config)
- if err != nil {
- fail(err.Error())
- }
- exitChan <- true
- })()
-
- exitCode := 0
- for f := range failures {
- if f.Confidence < config.Confidence {
- continue
- }
- if exitCode == 0 {
- exitCode = config.WarningCode
- }
- if c, ok := config.Rules[f.RuleName]; ok && c.Severity == lint.SeverityError {
- exitCode = config.ErrorCode
- }
- if c, ok := config.Directives[f.RuleName]; ok && c.Severity == lint.SeverityError {
- exitCode = config.ErrorCode
- }
-
- formatChan <- f
- }
-
- close(formatChan)
- <-exitChan
- if output != "" {
- fmt.Println(output)
- }
-
- os.Exit(exitCode)
- }
|