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  }