mirror of
https://github.com/mgechev/revive.git
synced 2025-03-05 15:05:47 +02:00
Implement command line arguments
This commit is contained in:
parent
a227153bc2
commit
8746067321
196
config.go
Normal file
196
config.go
Normal file
@ -0,0 +1,196 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
zglob "github.com/mattn/go-zglob"
|
||||
"github.com/mgechev/revive/formatter"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/mgechev/revive/lint"
|
||||
"github.com/mgechev/revive/rule"
|
||||
)
|
||||
|
||||
var defaultRules = []lint.Rule{
|
||||
&rule.VarDeclarationsRule{},
|
||||
&rule.PackageCommentsRule{},
|
||||
&rule.DotImportsRule{},
|
||||
&rule.BlankImportsRule{},
|
||||
&rule.ExportedRule{},
|
||||
&rule.NamesRule{},
|
||||
&rule.ElseRule{},
|
||||
&rule.IfReturnRule{},
|
||||
&rule.RangeRule{},
|
||||
&rule.ErrorfRule{},
|
||||
&rule.ErrorsRule{},
|
||||
&rule.ErrorStringsRule{},
|
||||
&rule.ReceiverNameRule{},
|
||||
&rule.IncrementDecrementRule{},
|
||||
&rule.ErrorReturnRule{},
|
||||
&rule.UnexportedReturnRule{},
|
||||
&rule.TimeNamesRule{},
|
||||
&rule.ContextKeyTypeRule{},
|
||||
&rule.ContextArgumentsRule{},
|
||||
}
|
||||
|
||||
var allRules = append([]lint.Rule{
|
||||
&rule.ArgumentsLimitRule{},
|
||||
&rule.CyclomaticRule{},
|
||||
}, defaultRules...)
|
||||
|
||||
var allFormatters = []lint.Formatter{
|
||||
&formatter.CLIFormatter{},
|
||||
&formatter.JSONFormatter{},
|
||||
}
|
||||
|
||||
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 {
|
||||
panic("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 {
|
||||
panic("cannot read the config file")
|
||||
}
|
||||
_, err = toml.Decode(string(file), config)
|
||||
if err != nil {
|
||||
panic("cannot parse the config file: " + err.Error())
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func normalizeConfig(config *lint.Config) {
|
||||
severity := config.Severity
|
||||
if severity != "" {
|
||||
for k, v := range config.Rules {
|
||||
if v.Severity == "" {
|
||||
v.Severity = severity
|
||||
}
|
||||
config.Rules[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["cli"]
|
||||
if formatterName != "" {
|
||||
f, ok := formatters[formatterName]
|
||||
if !ok {
|
||||
panic("unknown formatter " + formatterName)
|
||||
}
|
||||
formatter = f
|
||||
}
|
||||
return formatter
|
||||
}
|
||||
|
||||
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 getFiles() []string {
|
||||
globs := flag.Args()
|
||||
if len(globs) == 0 {
|
||||
panic("files not specified")
|
||||
}
|
||||
|
||||
var matches []string
|
||||
for _, g := range globs {
|
||||
m, err := zglob.Glob(g)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
matches = append(matches, m...)
|
||||
}
|
||||
|
||||
if excludeGlobs == "" {
|
||||
return matches
|
||||
}
|
||||
|
||||
excluded := map[string]bool{}
|
||||
excludeGlobSlice := strings.Split(excludeGlobs, " ")
|
||||
for _, g := range excludeGlobSlice {
|
||||
m, err := zglob.Glob(g)
|
||||
if err != nil {
|
||||
panic("error while parsing glob from exclude " + err.Error())
|
||||
}
|
||||
for _, match := range m {
|
||||
excluded[match] = true
|
||||
}
|
||||
}
|
||||
|
||||
var finalMatches []string
|
||||
for _, m := range matches {
|
||||
if _, ok := excluded[m]; !ok {
|
||||
finalMatches = append(finalMatches, m)
|
||||
}
|
||||
}
|
||||
|
||||
return finalMatches
|
||||
}
|
||||
|
||||
var configPath string
|
||||
var excludeGlobs string
|
||||
var formatterName string
|
||||
var help bool
|
||||
|
||||
var originalUsage = flag.Usage
|
||||
|
||||
func init() {
|
||||
flag.Usage = func() {
|
||||
fmt.Println(banner)
|
||||
originalUsage()
|
||||
}
|
||||
const (
|
||||
configUsage = "path to the configuration TOML file"
|
||||
excludeUsage = "glob which specifies files to be excluded"
|
||||
formatterUsage = "formatter to be used for the output"
|
||||
)
|
||||
flag.StringVar(&configPath, "config", "", configUsage)
|
||||
flag.StringVar(&excludeGlobs, "exclude", "", excludeUsage)
|
||||
flag.StringVar(&formatterName, "formatter", "", formatterUsage)
|
||||
flag.Parse()
|
||||
}
|
@ -2,9 +2,9 @@ severity = "warning"
|
||||
confidence = 0.8
|
||||
|
||||
[rule.else]
|
||||
severity = "error"
|
||||
[rule.names]
|
||||
[rule.argument-limit]
|
||||
arguments = [2]
|
||||
[rule.cyclomatic]
|
||||
severity = "error"
|
||||
arguments = [3]
|
@ -1,7 +1,7 @@
|
||||
// Test for returning errors.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
package pkg
|
||||
|
||||
// Returns nothing
|
||||
func f() { // ok
|
||||
|
@ -20,6 +20,11 @@ type CLIFormatter struct {
|
||||
Metadata lint.FormatterMetadata
|
||||
}
|
||||
|
||||
// Name returns the name of the formatter
|
||||
func (f *CLIFormatter) Name() string {
|
||||
return "cli"
|
||||
}
|
||||
|
||||
func formatFailure(failure lint.Failure, severity lint.Severity) []string {
|
||||
fString := color.BlueString(failure.Failure)
|
||||
fName := color.RedString(failure.RuleName)
|
||||
|
@ -12,6 +12,11 @@ type JSONFormatter struct {
|
||||
Metadata lint.FormatterMetadata
|
||||
}
|
||||
|
||||
// Name returns the name of the formatter
|
||||
func (f *JSONFormatter) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
// Format formats the failures gotten from the lint.
|
||||
func (f *JSONFormatter) Format(failures <-chan lint.Failure, config lint.RulesConfig) (string, error) {
|
||||
var slice []lint.Failure
|
||||
|
@ -9,5 +9,6 @@ type FormatterMetadata struct {
|
||||
|
||||
// Formatter defines an interface for failure formatters
|
||||
type Formatter interface {
|
||||
Format(<-chan Failure, RulesConfig) string
|
||||
Format(<-chan Failure, RulesConfig) (string, error)
|
||||
Name() string
|
||||
}
|
||||
|
110
main.go
110
main.go
@ -5,122 +5,29 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/mgechev/revive/formatter"
|
||||
"github.com/mgechev/revive/lint"
|
||||
"github.com/mgechev/revive/rule"
|
||||
)
|
||||
|
||||
var allRules = []lint.Rule{
|
||||
&rule.ArgumentsLimitRule{},
|
||||
&rule.VarDeclarationsRule{},
|
||||
&rule.PackageCommentsRule{},
|
||||
&rule.DotImportsRule{},
|
||||
&rule.BlankImportsRule{},
|
||||
&rule.ExportedRule{},
|
||||
&rule.NamesRule{},
|
||||
&rule.ElseRule{},
|
||||
&rule.IfReturnRule{},
|
||||
&rule.RangeRule{},
|
||||
&rule.ErrorfRule{},
|
||||
&rule.ErrorsRule{},
|
||||
&rule.ErrorStringsRule{},
|
||||
&rule.ReceiverNameRule{},
|
||||
&rule.IncrementDecrementRule{},
|
||||
&rule.ErrorReturnRule{},
|
||||
&rule.UnexportedReturnRule{},
|
||||
&rule.TimeNamesRule{},
|
||||
&rule.ContextKeyTypeRule{},
|
||||
&rule.ContextArgumentsRule{},
|
||||
&rule.CyclomaticRule{},
|
||||
}
|
||||
|
||||
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 {
|
||||
panic("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 {
|
||||
panic("cannot read the config file")
|
||||
}
|
||||
_, err = toml.Decode(string(file), config)
|
||||
if err != nil {
|
||||
panic("cannot parse the config file: " + err.Error())
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func normalizeConfig(config *lint.Config) {
|
||||
severity := config.Severity
|
||||
if severity != "" {
|
||||
for k, v := range config.Rules {
|
||||
if v.Severity == "" {
|
||||
v.Severity = severity
|
||||
}
|
||||
config.Rules[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const usage = `
|
||||
Welcome to:
|
||||
_ __ _____ _(_)__ _____
|
||||
const banner = `
|
||||
Welcome to:
|
||||
_ __ _____ _(_)__ _____
|
||||
| '__/ _ \ \ / / \ \ / / _ \
|
||||
| | | __/\ V /| |\ V / __/
|
||||
|_| \___| \_/ |_| \_/ \___|
|
||||
|
||||
Usage:
|
||||
revive [flags] <Go file or directory> ...
|
||||
Flags:
|
||||
-c string path to the configuration TOML file.
|
||||
-e string glob which specifies files to be excluded.
|
||||
-f string formatter to be used for the output.
|
||||
-h output this screen.
|
||||
`
|
||||
|
||||
func main() {
|
||||
src := `
|
||||
package p
|
||||
|
||||
// revive:disable:cyclomatic
|
||||
func Test() {
|
||||
if true || bar && baz {
|
||||
return 42;
|
||||
} else {
|
||||
return 23;
|
||||
}
|
||||
}
|
||||
// revive:enable:cyclomatic
|
||||
|
||||
func foo_bar(a int, b int, c int, d int) {
|
||||
return a + b + c;
|
||||
}`
|
||||
config := getConfig()
|
||||
formatter := getFormatter()
|
||||
files := getFiles()
|
||||
|
||||
revive := lint.New(func(file string) ([]byte, error) {
|
||||
return []byte(src), nil
|
||||
return ioutil.ReadFile(file)
|
||||
})
|
||||
|
||||
config := parseConfig("config.toml")
|
||||
normalizeConfig(config)
|
||||
lintingRules := getLintingRules(config)
|
||||
|
||||
failures, err := revive.Lint([]string{"foo.go", "bar.go", "baz.go"}, lintingRules, config.Rules)
|
||||
failures, err := revive.Lint(files, lintingRules, config.Rules)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -130,7 +37,6 @@ func main() {
|
||||
|
||||
var output string
|
||||
go (func() {
|
||||
var formatter formatter.CLIFormatter
|
||||
output, err = formatter.Format(formatChan, config.Rules)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -143,7 +143,6 @@ func assertFailures(t *testing.T, baseDir string, fi os.FileInfo, src []byte, ru
|
||||
|
||||
ps, err := l.Lint([]string{fi.Name()}, rules, config)
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user