From 7810844dd42c1620e741849f744103408f5edb00 Mon Sep 17 00:00:00 2001 From: chavacava Date: Fri, 18 Mar 2022 15:00:41 +0100 Subject: [PATCH] removes duplicated utility function (#652) Signed-off-by: subham sarkar --- cli/main.go | 281 +++++++++++++++++++++++++++++++++++++++ config/config.go | 8 +- config/config_test.go | 4 +- main.go | 251 +--------------------------------- rule/exported.go | 2 +- rule/package-comments.go | 2 +- rule/utils.go | 4 - 7 files changed, 294 insertions(+), 258 deletions(-) create mode 100644 cli/main.go diff --git a/cli/main.go b/cli/main.go new file mode 100644 index 000000000..c1d8cba6c --- /dev/null +++ b/cli/main.go @@ -0,0 +1,281 @@ +package cli + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "runtime/debug" + "strings" + + "github.com/fatih/color" + "github.com/mgechev/dots" + "github.com/mgechev/revive/config" + "github.com/mgechev/revive/lint" + "github.com/mgechev/revive/logging" + "github.com/mitchellh/go-homedir" +) + +var ( + version = "dev" + commit = "none" + date = "unknown" + builtBy = "unknown" +) + +func fail(err string) { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) +} + +// ExtraRule configures a new rule to be used with revive. +type ExtraRule struct { + Rule lint.Rule + DefaultConfig lint.RuleConfig +} + +// NewExtraRule returns a configured extra rule +func NewExtraRule(rule lint.Rule, defaultConfig lint.RuleConfig) ExtraRule { + return ExtraRule{ + Rule: rule, + DefaultConfig: defaultConfig, + } +} + +// RunRevive runs the CLI for revive. +func RunRevive(extraRules ...ExtraRule) { + log, err := logging.GetLogger() + if err != nil { + fail(err.Error()) + } + + formatter, err := config.GetFormatter(formatterName) + if err != nil { + fail(err.Error()) + } + + conf, err := config.GetConfig(configPath) + if err != nil { + fail(err.Error()) + } + + if setExitStatus { + conf.ErrorCode = 1 + conf.WarningCode = 1 + } + + extraRuleInstances := make([]lint.Rule, len(extraRules)) + for i, extraRule := range extraRules { + extraRuleInstances[i] = extraRule.Rule + + ruleName := extraRule.Rule.Name() + _, isRuleAlreadyConfigured := conf.Rules[ruleName] + if !isRuleAlreadyConfigured { + conf.Rules[ruleName] = extraRule.DefaultConfig + } + } + + lintingRules, err := config.GetLintingRules(conf, extraRuleInstances) + if err != nil { + fail(err.Error()) + } + + log.Println("Config loaded") + + if len(excludePaths) == 0 { // if no excludes were set in the command line + excludePaths = conf.Exclude // use those from the configuration + } + + packages, err := getPackages(excludePaths) + if err != nil { + fail(err.Error()) + } + revive := lint.New(func(file string) ([]byte, error) { + return ioutil.ReadFile(file) + }, maxOpenFiles) + + failures, err := revive.Lint(packages, lintingRules, *conf) + 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, *conf) + if err != nil { + fail(err.Error()) + } + exitChan <- true + })() + + exitCode := 0 + for f := range failures { + if f.Confidence < conf.Confidence { + continue + } + if exitCode == 0 { + exitCode = conf.WarningCode + } + if c, ok := conf.Rules[f.RuleName]; ok && c.Severity == lint.SeverityError { + exitCode = conf.ErrorCode + } + if c, ok := conf.Directives[f.RuleName]; ok && c.Severity == lint.SeverityError { + exitCode = conf.ErrorCode + } + + formatChan <- f + } + + close(formatChan) + <-exitChan + if output != "" { + fmt.Println(output) + } + + os.Exit(exitCode) +} + +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(excludePaths arrayFlags) ([][]string, error) { + globs := normalizeSplit(flag.Args()) + if len(globs) == 0 { + globs = append(globs, ".") + } + + packages, err := dots.ResolvePackages(globs, normalizeSplit(excludePaths)) + if err != nil { + return nil, err + } + + return packages, nil +} + +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 + excludePaths arrayFlags + formatterName string + help bool + versionFlag bool + setExitStatus bool + maxOpenFiles int +) + +var originalUsage = flag.Usage + +func getLogo() string { + return color.YellowString(` _ __ _____ _(_)__ _____ +| '__/ _ \ \ / / \ \ / / _ \ +| | | __/\ V /| |\ V / __/ +|_| \___| \_/ |_| \_/ \___|`) +} + +func getCall() string { + return color.MagentaString("revive -config c.toml -formatter friendly -exclude a.go -exclude b.go ./...") +} + +func getBanner() string { + return fmt.Sprintf(` +%s + +Example: + %s +`, getLogo(), getCall()) +} + +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 init() { + // Force colorizing for no TTY environments + if os.Getenv("REVIVE_FORCE_COLOR") == "1" { + color.NoColor = false + } + + flag.Usage = func() { + fmt.Println(getBanner()) + 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)" + versionUsage = "get revive version" + exitStatusUsage = "set exit status to 1 if any issues are found, overwrites errorCode and warningCode in config" + maxOpenFilesUsage = "maximum number of open files at the same time" + ) + + defaultConfigPath := buildDefaultConfigPath() + + flag.StringVar(&configPath, "config", defaultConfigPath, configUsage) + flag.Var(&excludePaths, "exclude", excludeUsage) + flag.StringVar(&formatterName, "formatter", "", formatterUsage) + flag.BoolVar(&versionFlag, "version", false, versionUsage) + flag.BoolVar(&setExitStatus, "set_exit_status", false, exitStatusUsage) + flag.IntVar(&maxOpenFiles, "max_open_files", 0, maxOpenFilesUsage) + flag.Parse() + + // Output build info (version, commit, date and builtBy) + if versionFlag { + var buildInfo string + if date != "unknown" && builtBy != "unknown" { + buildInfo = fmt.Sprintf("Built\t\t%s by %s\n", date, builtBy) + } + + if commit != "none" { + buildInfo = fmt.Sprintf("Commit:\t\t%s\n%s", commit, buildInfo) + } + + if version == "dev" { + bi, ok := debug.ReadBuildInfo() + if ok { + version = bi.Main.Version + if strings.HasPrefix(version, "v") { + version = bi.Main.Version[1:] + } + if len(buildInfo) == 0 { + fmt.Printf("version %s\n", version) + os.Exit(0) + } + } + } + + fmt.Printf("Version:\t%s\n%s", version, buildInfo) + os.Exit(0) + } +} diff --git a/config/config.go b/config/config.go index a86a9a143..c4fa960a3 100644 --- a/config/config.go +++ b/config/config.go @@ -107,11 +107,17 @@ func getFormatters() map[string]lint.Formatter { } // GetLintingRules yields the linting rules that must be applied by the linter -func GetLintingRules(config *lint.Config) ([]lint.Rule, error) { +func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, error) { rulesMap := map[string]lint.Rule{} for _, r := range allRules { rulesMap[r.Name()] = r } + for _, r := range extraRules { + if _, ok := rulesMap[r.Name()]; ok { + continue + } + rulesMap[r.Name()] = r + } var lintingRules []lint.Rule for name, ruleConfig := range config.Rules { diff --git a/config/config_test.go b/config/config_test.go index e1e59cae8..cc15f2af6 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -92,7 +92,7 @@ func TestGetLintingRules(t *testing.T) { if err != nil { t.Fatalf("Unexpected error while loading conf: %v", err) } - rules, err := GetLintingRules(cfg) + rules, err := GetLintingRules(cfg, []lint.Rule{}) switch { case err != nil: t.Fatalf("Unexpected error\n\t%v", err) @@ -130,7 +130,7 @@ func TestGetGlobalSeverity(t *testing.T) { if err != nil { t.Fatalf("Unexpected error while loading conf: %v", err) } - rules, err := GetLintingRules(cfg) + rules, err := GetLintingRules(cfg, []lint.Rule{}) if err != nil { t.Fatalf("Unexpected error while loading conf: %v", err) } diff --git a/main.go b/main.go index c8ba4dcdd..1196908b1 100644 --- a/main.go +++ b/main.go @@ -1,254 +1,7 @@ package main -import ( - "flag" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "runtime/debug" - "strings" - - "github.com/deepsourcelabs/revive/config" - "github.com/deepsourcelabs/revive/lint" - "github.com/deepsourcelabs/revive/logging" - "github.com/fatih/color" - "github.com/mgechev/dots" - "github.com/mitchellh/go-homedir" -) - -var ( - version = "dev" - commit = "none" - date = "unknown" - builtBy = "unknown" -) - -func fail(err string) { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) -} +import "github.com/deepsourcelabs/revive/cli" func main() { - log, err := logging.GetLogger() - if err != nil { - fail(err.Error()) - } - - conf, err := config.GetConfig(configPath) - if err != nil { - fail(err.Error()) - } - formatter, err := config.GetFormatter(formatterName) - if err != nil { - fail(err.Error()) - } - if setExitStatus { - conf.ErrorCode = 1 - conf.WarningCode = 1 - } - - if len(excludePaths) == 0 { // if no excludes were set in the command line - excludePaths = conf.Exclude // use those from the configuration - } - - packages, err := getPackages(excludePaths) - if err != nil { - fail(err.Error()) - } - - revive := lint.New(func(file string) ([]byte, error) { - return ioutil.ReadFile(file) - }, maxOpenFiles) - - lintingRules, err := config.GetLintingRules(conf) - if err != nil { - fail(err.Error()) - } - - log.Println("Config loaded") - - failures, err := revive.Lint(packages, lintingRules, *conf) - 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, *conf) - if err != nil { - fail(err.Error()) - } - exitChan <- true - })() - - exitCode := 0 - for f := range failures { - if f.Confidence < conf.Confidence { - continue - } - if exitCode == 0 { - exitCode = conf.WarningCode - } - if c, ok := conf.Rules[f.RuleName]; ok && c.Severity == lint.SeverityError { - exitCode = conf.ErrorCode - } - if c, ok := conf.Directives[f.RuleName]; ok && c.Severity == lint.SeverityError { - exitCode = conf.ErrorCode - } - - formatChan <- f - } - - close(formatChan) - <-exitChan - if output != "" { - fmt.Println(output) - } - - os.Exit(exitCode) -} - -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(excludePaths arrayFlags) ([][]string, error) { - globs := normalizeSplit(flag.Args()) - if len(globs) == 0 { - globs = append(globs, ".") - } - - packages, err := dots.ResolvePackages(globs, normalizeSplit(excludePaths)) - if err != nil { - return nil, err - } - - return packages, nil -} - -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 - excludePaths arrayFlags - formatterName string - help bool - versionFlag bool - setExitStatus bool - maxOpenFiles int -) - -var originalUsage = flag.Usage - -func getLogo() string { - return color.YellowString(` _ __ _____ _(_)__ _____ -| '__/ _ \ \ / / \ \ / / _ \ -| | | __/\ V /| |\ V / __/ -|_| \___| \_/ |_| \_/ \___|`) -} - -func getCall() string { - return color.MagentaString("revive -config c.toml -formatter friendly -exclude a.go -exclude b.go ./...") -} - -func getBanner() string { - return fmt.Sprintf(` -%s - -Example: - %s -`, getLogo(), getCall()) -} - -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 init() { - // Force colorizing for no TTY environments - if os.Getenv("REVIVE_FORCE_COLOR") == "1" { - color.NoColor = false - } - - flag.Usage = func() { - fmt.Println(getBanner()) - 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)" - versionUsage = "get revive version" - exitStatusUsage = "set exit status to 1 if any issues are found, overwrites errorCode and warningCode in config" - maxOpenFilesUsage = "maximum number of open files at the same time" - ) - - defaultConfigPath := buildDefaultConfigPath() - - flag.StringVar(&configPath, "config", defaultConfigPath, configUsage) - flag.Var(&excludePaths, "exclude", excludeUsage) - flag.StringVar(&formatterName, "formatter", "", formatterUsage) - flag.BoolVar(&versionFlag, "version", false, versionUsage) - flag.BoolVar(&setExitStatus, "set_exit_status", false, exitStatusUsage) - flag.IntVar(&maxOpenFiles, "max_open_files", 0, maxOpenFilesUsage) - flag.Parse() - - // Output build info (version, commit, date and builtBy) - if versionFlag { - var buildInfo string - if date != "unknown" && builtBy != "unknown" { - buildInfo = fmt.Sprintf("Built\t\t%s by %s\n", date, builtBy) - } - - if commit != "none" { - buildInfo = fmt.Sprintf("Commit:\t\t%s\n%s", commit, buildInfo) - } - - if version == "dev" { - bi, ok := debug.ReadBuildInfo() - if ok { - version = bi.Main.Version - if strings.HasPrefix(version, "v") { - version = bi.Main.Version[1:] - } - if len(buildInfo) == 0 { - fmt.Printf("version %s\n", version) - os.Exit(0) - } - } - } - - fmt.Printf("Version:\t%s\n%s", version, buildInfo) - os.Exit(0) - } + cli.RunRevive() } diff --git a/rule/exported.go b/rule/exported.go index f4dc465fb..11c4b0316 100644 --- a/rule/exported.go +++ b/rule/exported.go @@ -23,7 +23,7 @@ type ExportedRule struct { func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { var failures []lint.Failure - if isTest(file) { + if file.IsTest() { return failures } diff --git a/rule/package-comments.go b/rule/package-comments.go index 3bb96c221..1da633399 100644 --- a/rule/package-comments.go +++ b/rule/package-comments.go @@ -20,7 +20,7 @@ type PackageCommentsRule struct{} func (r *PackageCommentsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - if isTest(file) { + if file.IsTest() { return failures } diff --git a/rule/utils.go b/rule/utils.go index ec253e041..9f2962237 100644 --- a/rule/utils.go +++ b/rule/utils.go @@ -19,10 +19,6 @@ const styleGuideBase = "https://golang.org/wiki/CodeReviewComments" // If id == nil, the answer is false. func isBlank(id *ast.Ident) bool { return id != nil && id.Name == "_" } -func isTest(f *lint.File) bool { - return strings.HasSuffix(f.Name, "_test.go") -} - var commonMethods = map[string]bool{ "Error": true, "Read": true,