refactor lintersdb: split it into abstractions
This commit is contained in:
parent
c37ad6652e
commit
a24cc87a06
pkg
@ -2,6 +2,7 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/golangci/golangci-lint/pkg/config"
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||||
"github.com/golangci/golangci-lint/pkg/report"
|
"github.com/golangci/golangci-lint/pkg/report"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -10,15 +11,14 @@ import (
|
|||||||
type Executor struct {
|
type Executor struct {
|
||||||
rootCmd *cobra.Command
|
rootCmd *cobra.Command
|
||||||
|
|
||||||
cfg *config.Config
|
exitCode int
|
||||||
|
|
||||||
exitCode int
|
|
||||||
|
|
||||||
version, commit, date string
|
version, commit, date string
|
||||||
|
|
||||||
log logutils.Log
|
cfg *config.Config
|
||||||
|
log logutils.Log
|
||||||
reportData report.Data
|
reportData report.Data
|
||||||
|
DBManager *lintersdb.Manager
|
||||||
|
EnabledLintersSet *lintersdb.EnabledSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExecutor(version, commit, date string) *Executor {
|
func NewExecutor(version, commit, date string) *Executor {
|
||||||
@ -30,6 +30,9 @@ func NewExecutor(version, commit, date string) *Executor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.log = report.NewLogWrapper(logutils.NewStderrLog(""), &e.reportData)
|
e.log = report.NewLogWrapper(logutils.NewStderrLog(""), &e.reportData)
|
||||||
|
e.DBManager = lintersdb.NewManager()
|
||||||
|
e.EnabledLintersSet = lintersdb.NewEnabledSet(e.DBManager, &lintersdb.Validator{},
|
||||||
|
e.log.Child("lintersdb"), e.cfg)
|
||||||
|
|
||||||
e.initRoot()
|
e.initRoot()
|
||||||
e.initRun()
|
e.initRun()
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
|
||||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -41,7 +40,7 @@ func printLinterConfigs(lcs []linter.Config) {
|
|||||||
|
|
||||||
func (e Executor) executeLintersHelp(cmd *cobra.Command, args []string) {
|
func (e Executor) executeLintersHelp(cmd *cobra.Command, args []string) {
|
||||||
var enabledLCs, disabledLCs []linter.Config
|
var enabledLCs, disabledLCs []linter.Config
|
||||||
for _, lc := range lintersdb.GetAllSupportedLinterConfigs() {
|
for _, lc := range e.DBManager.GetAllSupportedLinterConfigs() {
|
||||||
if lc.EnabledByDefault {
|
if lc.EnabledByDefault {
|
||||||
enabledLCs = append(enabledLCs, lc)
|
enabledLCs = append(enabledLCs, lc)
|
||||||
} else {
|
} else {
|
||||||
@ -55,8 +54,8 @@ func (e Executor) executeLintersHelp(cmd *cobra.Command, args []string) {
|
|||||||
printLinterConfigs(disabledLCs)
|
printLinterConfigs(disabledLCs)
|
||||||
|
|
||||||
color.Green("\nLinters presets:")
|
color.Green("\nLinters presets:")
|
||||||
for _, p := range lintersdb.AllPresets() {
|
for _, p := range e.DBManager.AllPresets() {
|
||||||
linters := lintersdb.GetAllLinterConfigsForPreset(p)
|
linters := e.DBManager.GetAllLinterConfigsForPreset(p)
|
||||||
linterNames := []string{}
|
linterNames := []string{}
|
||||||
for _, lc := range linters {
|
for _, lc := range linters {
|
||||||
linterNames = append(linterNames, lc.Linter.Name())
|
linterNames = append(linterNames, lc.Linter.Name())
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ func IsLinterInConfigsList(name string, linters []linter.Config) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e Executor) executeLinters(cmd *cobra.Command, args []string) {
|
func (e Executor) executeLinters(cmd *cobra.Command, args []string) {
|
||||||
enabledLCs, err := lintersdb.GetEnabledLinters(e.cfg, e.log.Child("lintersdb"))
|
enabledLCs, err := e.EnabledLintersSet.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Can't get enabled linters: %s", err)
|
log.Fatalf("Can't get enabled linters: %s", err)
|
||||||
}
|
}
|
||||||
@ -40,7 +39,7 @@ func (e Executor) executeLinters(cmd *cobra.Command, args []string) {
|
|||||||
printLinterConfigs(enabledLCs)
|
printLinterConfigs(enabledLCs)
|
||||||
|
|
||||||
var disabledLCs []linter.Config
|
var disabledLCs []linter.Config
|
||||||
for _, lc := range lintersdb.GetAllSupportedLinterConfigs() {
|
for _, lc := range e.DBManager.GetAllSupportedLinterConfigs() {
|
||||||
if !IsLinterInConfigsList(lc.Linter.Name(), enabledLCs) {
|
if !IsLinterInConfigsList(lc.Linter.Name(), enabledLCs) {
|
||||||
disabledLCs = append(disabledLCs, lc)
|
disabledLCs = append(disabledLCs, lc)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func wh(text string) string {
|
|||||||
return color.GreenString(text)
|
return color.GreenString(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
|
func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager) {
|
||||||
hideFlag := func(name string) {
|
hideFlag := func(name string) {
|
||||||
if err := fs.MarkHidden(name); err != nil {
|
if err := fs.MarkHidden(name); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -137,7 +137,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
|
|||||||
fs.BoolVar(&lc.DisableAll, "disable-all", false, wh("Disable all linters"))
|
fs.BoolVar(&lc.DisableAll, "disable-all", false, wh("Disable all linters"))
|
||||||
fs.StringSliceVarP(&lc.Presets, "presets", "p", nil,
|
fs.StringSliceVarP(&lc.Presets, "presets", "p", nil,
|
||||||
wh(fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see "+
|
wh(fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see "+
|
||||||
"them. This option implies option --disable-all", strings.Join(lintersdb.AllPresets(), "|"))))
|
"them. This option implies option --disable-all", strings.Join(m.AllPresets(), "|"))))
|
||||||
fs.BoolVar(&lc.Fast, "fast", false, wh("Run only fast linters from enabled linters set"))
|
fs.BoolVar(&lc.Fast, "fast", false, wh("Run only fast linters from enabled linters set"))
|
||||||
|
|
||||||
// Issues config
|
// Issues config
|
||||||
@ -167,7 +167,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) {
|
|||||||
func (e *Executor) initRunConfiguration(cmd *cobra.Command) {
|
func (e *Executor) initRunConfiguration(cmd *cobra.Command) {
|
||||||
fs := cmd.Flags()
|
fs := cmd.Flags()
|
||||||
fs.SortFlags = false // sort them as they are defined here
|
fs.SortFlags = false // sort them as they are defined here
|
||||||
initFlagSet(fs, e.cfg)
|
initFlagSet(fs, e.cfg, e.DBManager)
|
||||||
|
|
||||||
// init e.cfg by values from config: flags parse will see these values
|
// init e.cfg by values from config: flags parse will see these values
|
||||||
// like the default ones. It will overwrite them only if the same option
|
// like the default ones. It will overwrite them only if the same option
|
||||||
@ -178,7 +178,7 @@ func (e *Executor) initRunConfiguration(cmd *cobra.Command) {
|
|||||||
// `changed` variable inside string slice vars will be shared.
|
// `changed` variable inside string slice vars will be shared.
|
||||||
// Use another config variable here, not e.cfg, to not
|
// Use another config variable here, not e.cfg, to not
|
||||||
// affect main parsing by this parsing of only config option.
|
// affect main parsing by this parsing of only config option.
|
||||||
initFlagSet(fs, cfg)
|
initFlagSet(fs, cfg, e.DBManager)
|
||||||
|
|
||||||
// Parse max options, even force version option: don't want
|
// Parse max options, even force version option: don't want
|
||||||
// to get access to Executor here: it's error-prone to use
|
// to get access to Executor here: it's error-prone to use
|
||||||
@ -232,12 +232,12 @@ func fixSlicesFlags(fs *pflag.FlagSet) {
|
|||||||
func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan result.Issue, error) {
|
func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan result.Issue, error) {
|
||||||
e.cfg.Run.Args = args
|
e.cfg.Run.Args = args
|
||||||
|
|
||||||
linters, err := lintersdb.GetEnabledLinters(e.cfg, e.log.Child("lintersdb"))
|
linters, err := e.EnabledLintersSet.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, lc := range lintersdb.GetAllSupportedLinterConfigs() {
|
for _, lc := range e.DBManager.GetAllSupportedLinterConfigs() {
|
||||||
isEnabled := false
|
isEnabled := false
|
||||||
for _, linter := range linters {
|
for _, linter := range linters {
|
||||||
if linter.Linter.Name() == lc.Linter.Name() {
|
if linter.Linter.Name() == lc.Linter.Name() {
|
||||||
|
148
pkg/lint/lintersdb/enabled_set.go
Normal file
148
pkg/lint/lintersdb/enabled_set.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package lintersdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/golinters"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EnabledSet struct {
|
||||||
|
m *Manager
|
||||||
|
v *Validator
|
||||||
|
log logutils.Log
|
||||||
|
cfg *config.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Config) *EnabledSet {
|
||||||
|
return &EnabledSet{
|
||||||
|
m: m,
|
||||||
|
v: v,
|
||||||
|
log: log,
|
||||||
|
cfg: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint:gocyclo
|
||||||
|
func (es EnabledSet) build(lcfg *config.Linters, enabledByDefaultLinters []linter.Config) map[string]*linter.Config {
|
||||||
|
resultLintersSet := map[string]*linter.Config{}
|
||||||
|
switch {
|
||||||
|
case len(lcfg.Presets) != 0:
|
||||||
|
break // imply --disable-all
|
||||||
|
case lcfg.EnableAll:
|
||||||
|
resultLintersSet = linterConfigsToMap(es.m.GetAllSupportedLinterConfigs())
|
||||||
|
case lcfg.DisableAll:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
resultLintersSet = linterConfigsToMap(enabledByDefaultLinters)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --presets can only add linters to default set
|
||||||
|
for _, p := range lcfg.Presets {
|
||||||
|
for _, lc := range es.m.GetAllLinterConfigsForPreset(p) {
|
||||||
|
lc := lc
|
||||||
|
resultLintersSet[lc.Linter.Name()] = &lc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --fast removes slow linters from current set.
|
||||||
|
// It should be after --presets to be able to run only fast linters in preset.
|
||||||
|
// It should be before --enable and --disable to be able to enable or disable specific linter.
|
||||||
|
if lcfg.Fast {
|
||||||
|
for name := range resultLintersSet {
|
||||||
|
if es.m.getLinterConfig(name).DoesFullImport {
|
||||||
|
delete(resultLintersSet, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range lcfg.Enable {
|
||||||
|
resultLintersSet[name] = es.m.getLinterConfig(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range lcfg.Disable {
|
||||||
|
if name == "megacheck" {
|
||||||
|
for _, ln := range getAllMegacheckSubLinterNames() {
|
||||||
|
delete(resultLintersSet, ln)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(resultLintersSet, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
es.optimizeLintersSet(resultLintersSet)
|
||||||
|
return resultLintersSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllMegacheckSubLinterNames() []string {
|
||||||
|
unusedName := golinters.Megacheck{UnusedEnabled: true}.Name()
|
||||||
|
gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name()
|
||||||
|
staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name()
|
||||||
|
return []string{unusedName, gosimpleName, staticcheckName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (es EnabledSet) optimizeLintersSet(linters map[string]*linter.Config) {
|
||||||
|
unusedName := golinters.Megacheck{UnusedEnabled: true}.Name()
|
||||||
|
gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name()
|
||||||
|
staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name()
|
||||||
|
fullName := golinters.Megacheck{GosimpleEnabled: true, UnusedEnabled: true, StaticcheckEnabled: true}.Name()
|
||||||
|
allNames := []string{unusedName, gosimpleName, staticcheckName, fullName}
|
||||||
|
|
||||||
|
megacheckCount := 0
|
||||||
|
for _, n := range allNames {
|
||||||
|
if linters[n] != nil {
|
||||||
|
megacheckCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if megacheckCount <= 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isFullEnabled := linters[fullName] != nil
|
||||||
|
mega := golinters.Megacheck{
|
||||||
|
UnusedEnabled: isFullEnabled || linters[unusedName] != nil,
|
||||||
|
GosimpleEnabled: isFullEnabled || linters[gosimpleName] != nil,
|
||||||
|
StaticcheckEnabled: isFullEnabled || linters[staticcheckName] != nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, n := range allNames {
|
||||||
|
delete(linters, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
lc := *es.m.getLinterConfig("megacheck")
|
||||||
|
lc.Linter = mega
|
||||||
|
linters[mega.Name()] = &lc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (es EnabledSet) Get() ([]linter.Config, error) {
|
||||||
|
if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultLintersSet := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
|
||||||
|
|
||||||
|
var resultLinters []linter.Config
|
||||||
|
for _, lc := range resultLintersSet {
|
||||||
|
resultLinters = append(resultLinters, *lc)
|
||||||
|
}
|
||||||
|
|
||||||
|
es.verbosePrintLintersStatus(resultLinters)
|
||||||
|
|
||||||
|
return resultLinters, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (es EnabledSet) verbosePrintLintersStatus(lcs []linter.Config) {
|
||||||
|
var linterNames []string
|
||||||
|
for _, lc := range lcs {
|
||||||
|
linterNames = append(linterNames, lc.Linter.Name())
|
||||||
|
}
|
||||||
|
sort.StringSlice(linterNames).Sort()
|
||||||
|
es.log.Infof("Active %d linters: %s", len(linterNames), linterNames)
|
||||||
|
|
||||||
|
if len(es.cfg.Linters.Presets) != 0 {
|
||||||
|
sort.StringSlice(es.cfg.Linters.Presets).Sort()
|
||||||
|
es.log.Infof("Active presets: %s", es.cfg.Linters.Presets)
|
||||||
|
}
|
||||||
|
}
|
@ -44,13 +44,15 @@ func TestGetEnabledLintersSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m := NewManager()
|
||||||
|
es := NewEnabledSet(m, &Validator{}, nil, nil)
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.name, func(t *testing.T) {
|
t.Run(c.name, func(t *testing.T) {
|
||||||
defaultLinters := []linter.Config{}
|
defaultLinters := []linter.Config{}
|
||||||
for _, ln := range c.def {
|
for _, ln := range c.def {
|
||||||
defaultLinters = append(defaultLinters, *getLinterConfig(ln))
|
defaultLinters = append(defaultLinters, *m.getLinterConfig(ln))
|
||||||
}
|
}
|
||||||
els := getEnabledLintersSet(&c.cfg, defaultLinters)
|
els := es.build(&c.cfg, defaultLinters)
|
||||||
var enabledLinters []string
|
var enabledLinters []string
|
||||||
for ln, lc := range els {
|
for ln, lc := range els {
|
||||||
assert.Equal(t, ln, lc.Linter.Name())
|
assert.Equal(t, ln, lc.Linter.Name())
|
@ -1,43 +1,42 @@
|
|||||||
package lintersdb
|
package lintersdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/config"
|
|
||||||
"github.com/golangci/golangci-lint/pkg/golinters"
|
"github.com/golangci/golangci-lint/pkg/golinters"
|
||||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func AllPresets() []string {
|
type Manager struct {
|
||||||
|
nameToLC map[string]linter.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewManager() *Manager {
|
||||||
|
m := &Manager{}
|
||||||
|
nameToLC := make(map[string]linter.Config)
|
||||||
|
for _, lc := range m.GetAllSupportedLinterConfigs() {
|
||||||
|
nameToLC[lc.Linter.Name()] = lc
|
||||||
|
}
|
||||||
|
|
||||||
|
m.nameToLC = nameToLC
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Manager) AllPresets() []string {
|
||||||
return []string{linter.PresetBugs, linter.PresetUnused, linter.PresetFormatting,
|
return []string{linter.PresetBugs, linter.PresetUnused, linter.PresetFormatting,
|
||||||
linter.PresetStyle, linter.PresetComplexity, linter.PresetPerformance}
|
linter.PresetStyle, linter.PresetComplexity, linter.PresetPerformance}
|
||||||
}
|
}
|
||||||
|
|
||||||
func allPresetsSet() map[string]bool {
|
func (m Manager) allPresetsSet() map[string]bool {
|
||||||
ret := map[string]bool{}
|
ret := map[string]bool{}
|
||||||
for _, p := range AllPresets() {
|
for _, p := range m.AllPresets() {
|
||||||
ret[p] = true
|
ret[p] = true
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
var nameToLC map[string]linter.Config
|
func (m Manager) getLinterConfig(name string) *linter.Config {
|
||||||
var nameToLCOnce sync.Once
|
lc, ok := m.nameToLC[name]
|
||||||
|
|
||||||
func getLinterConfig(name string) *linter.Config {
|
|
||||||
nameToLCOnce.Do(func() {
|
|
||||||
nameToLC = make(map[string]linter.Config)
|
|
||||||
for _, lc := range GetAllSupportedLinterConfigs() {
|
|
||||||
nameToLC[lc.Linter.Name()] = lc
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
lc, ok := nameToLC[name]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -55,7 +54,7 @@ func enableLinterConfigs(lcs []linter.Config, isEnabled func(lc *linter.Config)
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllSupportedLinterConfigs() []linter.Config {
|
func (Manager) GetAllSupportedLinterConfigs() []linter.Config {
|
||||||
lcs := []linter.Config{
|
lcs := []linter.Config{
|
||||||
linter.NewConfig(golinters.Govet{}).
|
linter.NewConfig(golinters.Govet{}).
|
||||||
WithFullImport(). // TODO: depend on it's configuration here
|
WithFullImport(). // TODO: depend on it's configuration here
|
||||||
@ -207,9 +206,9 @@ func GetAllSupportedLinterConfigs() []linter.Config {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllEnabledByDefaultLinters() []linter.Config {
|
func (m Manager) GetAllEnabledByDefaultLinters() []linter.Config {
|
||||||
var ret []linter.Config
|
var ret []linter.Config
|
||||||
for _, lc := range GetAllSupportedLinterConfigs() {
|
for _, lc := range m.GetAllSupportedLinterConfigs() {
|
||||||
if lc.EnabledByDefault {
|
if lc.EnabledByDefault {
|
||||||
ret = append(ret, lc)
|
ret = append(ret, lc)
|
||||||
}
|
}
|
||||||
@ -228,89 +227,9 @@ func linterConfigsToMap(lcs []linter.Config) map[string]*linter.Config {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateLintersNames(cfg *config.Linters) error {
|
func (m Manager) GetAllLinterConfigsForPreset(p string) []linter.Config {
|
||||||
allNames := append([]string{}, cfg.Enable...)
|
|
||||||
allNames = append(allNames, cfg.Disable...)
|
|
||||||
for _, name := range allNames {
|
|
||||||
if getLinterConfig(name) == nil {
|
|
||||||
return fmt.Errorf("no such linter %q", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validatePresets(cfg *config.Linters) error {
|
|
||||||
allPresets := allPresetsSet()
|
|
||||||
for _, p := range cfg.Presets {
|
|
||||||
if !allPresets[p] {
|
|
||||||
return fmt.Errorf("no such preset %q: only next presets exist: (%s)", p, strings.Join(AllPresets(), "|"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.Presets) != 0 && cfg.EnableAll {
|
|
||||||
return fmt.Errorf("--presets is incompatible with --enable-all")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateAllDisableEnableOptions(cfg *config.Linters) error {
|
|
||||||
if cfg.EnableAll && cfg.DisableAll {
|
|
||||||
return fmt.Errorf("--enable-all and --disable-all options must not be combined")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.DisableAll {
|
|
||||||
if len(cfg.Enable) == 0 && len(cfg.Presets) == 0 {
|
|
||||||
return fmt.Errorf("all linters were disabled, but no one linter was enabled: must enable at least one")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.Disable) != 0 {
|
|
||||||
return fmt.Errorf("can't combine options --disable-all and --disable %s", cfg.Disable[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.EnableAll && len(cfg.Enable) != 0 && !cfg.Fast {
|
|
||||||
return fmt.Errorf("can't combine options --enable-all and --enable %s", cfg.Enable[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateDisabledAndEnabledAtOneMoment(cfg *config.Linters) error {
|
|
||||||
enabledLintersSet := map[string]bool{}
|
|
||||||
for _, name := range cfg.Enable {
|
|
||||||
enabledLintersSet[name] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, name := range cfg.Disable {
|
|
||||||
if enabledLintersSet[name] {
|
|
||||||
return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateEnabledDisabledLintersConfig(cfg *config.Linters) error {
|
|
||||||
validators := []func(cfg *config.Linters) error{
|
|
||||||
validateLintersNames,
|
|
||||||
validatePresets,
|
|
||||||
validateAllDisableEnableOptions,
|
|
||||||
validateDisabledAndEnabledAtOneMoment,
|
|
||||||
}
|
|
||||||
for _, v := range validators {
|
|
||||||
if err := v(cfg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAllLinterConfigsForPreset(p string) []linter.Config {
|
|
||||||
ret := []linter.Config{}
|
ret := []linter.Config{}
|
||||||
for _, lc := range GetAllSupportedLinterConfigs() {
|
for _, lc := range m.GetAllSupportedLinterConfigs() {
|
||||||
for _, ip := range lc.InPresets {
|
for _, ip := range lc.InPresets {
|
||||||
if p == ip {
|
if p == ip {
|
||||||
ret = append(ret, lc)
|
ret = append(ret, lc)
|
||||||
@ -321,127 +240,3 @@ func GetAllLinterConfigsForPreset(p string) []linter.Config {
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint:gocyclo
|
|
||||||
func getEnabledLintersSet(lcfg *config.Linters,
|
|
||||||
enabledByDefaultLinters []linter.Config) map[string]*linter.Config {
|
|
||||||
|
|
||||||
resultLintersSet := map[string]*linter.Config{}
|
|
||||||
switch {
|
|
||||||
case len(lcfg.Presets) != 0:
|
|
||||||
break // imply --disable-all
|
|
||||||
case lcfg.EnableAll:
|
|
||||||
resultLintersSet = linterConfigsToMap(GetAllSupportedLinterConfigs())
|
|
||||||
case lcfg.DisableAll:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
resultLintersSet = linterConfigsToMap(enabledByDefaultLinters)
|
|
||||||
}
|
|
||||||
|
|
||||||
// --presets can only add linters to default set
|
|
||||||
for _, p := range lcfg.Presets {
|
|
||||||
for _, lc := range GetAllLinterConfigsForPreset(p) {
|
|
||||||
lc := lc
|
|
||||||
resultLintersSet[lc.Linter.Name()] = &lc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --fast removes slow linters from current set.
|
|
||||||
// It should be after --presets to be able to run only fast linters in preset.
|
|
||||||
// It should be before --enable and --disable to be able to enable or disable specific linter.
|
|
||||||
if lcfg.Fast {
|
|
||||||
for name := range resultLintersSet {
|
|
||||||
if getLinterConfig(name).DoesFullImport {
|
|
||||||
delete(resultLintersSet, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, name := range lcfg.Enable {
|
|
||||||
resultLintersSet[name] = getLinterConfig(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, name := range lcfg.Disable {
|
|
||||||
if name == "megacheck" {
|
|
||||||
for _, ln := range getAllMegacheckSubLinterNames() {
|
|
||||||
delete(resultLintersSet, ln)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete(resultLintersSet, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
optimizeLintersSet(resultLintersSet)
|
|
||||||
return resultLintersSet
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllMegacheckSubLinterNames() []string {
|
|
||||||
unusedName := golinters.Megacheck{UnusedEnabled: true}.Name()
|
|
||||||
gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name()
|
|
||||||
staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name()
|
|
||||||
return []string{unusedName, gosimpleName, staticcheckName}
|
|
||||||
}
|
|
||||||
|
|
||||||
func optimizeLintersSet(linters map[string]*linter.Config) {
|
|
||||||
unusedName := golinters.Megacheck{UnusedEnabled: true}.Name()
|
|
||||||
gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name()
|
|
||||||
staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name()
|
|
||||||
fullName := golinters.Megacheck{GosimpleEnabled: true, UnusedEnabled: true, StaticcheckEnabled: true}.Name()
|
|
||||||
allNames := []string{unusedName, gosimpleName, staticcheckName, fullName}
|
|
||||||
|
|
||||||
megacheckCount := 0
|
|
||||||
for _, n := range allNames {
|
|
||||||
if linters[n] != nil {
|
|
||||||
megacheckCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if megacheckCount <= 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isFullEnabled := linters[fullName] != nil
|
|
||||||
m := golinters.Megacheck{
|
|
||||||
UnusedEnabled: isFullEnabled || linters[unusedName] != nil,
|
|
||||||
GosimpleEnabled: isFullEnabled || linters[gosimpleName] != nil,
|
|
||||||
StaticcheckEnabled: isFullEnabled || linters[staticcheckName] != nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, n := range allNames {
|
|
||||||
delete(linters, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
lc := *getLinterConfig("megacheck")
|
|
||||||
lc.Linter = m
|
|
||||||
linters[m.Name()] = &lc
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetEnabledLinters(cfg *config.Config, log logutils.Log) ([]linter.Config, error) {
|
|
||||||
if err := validateEnabledDisabledLintersConfig(&cfg.Linters); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resultLintersSet := getEnabledLintersSet(&cfg.Linters, GetAllEnabledByDefaultLinters())
|
|
||||||
|
|
||||||
var resultLinters []linter.Config
|
|
||||||
for _, lc := range resultLintersSet {
|
|
||||||
resultLinters = append(resultLinters, *lc)
|
|
||||||
}
|
|
||||||
|
|
||||||
verbosePrintLintersStatus(cfg, resultLinters, log)
|
|
||||||
|
|
||||||
return resultLinters, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func verbosePrintLintersStatus(cfg *config.Config, lcs []linter.Config, log logutils.Log) {
|
|
||||||
var linterNames []string
|
|
||||||
for _, lc := range lcs {
|
|
||||||
linterNames = append(linterNames, lc.Linter.Name())
|
|
||||||
}
|
|
||||||
sort.StringSlice(linterNames).Sort()
|
|
||||||
log.Infof("Active %d linters: %s", len(linterNames), linterNames)
|
|
||||||
|
|
||||||
if len(cfg.Linters.Presets) != 0 {
|
|
||||||
sort.StringSlice(cfg.Linters.Presets).Sort()
|
|
||||||
log.Infof("Active presets: %s", cfg.Linters.Presets)
|
|
||||||
}
|
|
||||||
}
|
|
93
pkg/lint/lintersdb/validator.go
Normal file
93
pkg/lint/lintersdb/validator.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package lintersdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Validator struct {
|
||||||
|
m *Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Validator) validateLintersNames(cfg *config.Linters) error {
|
||||||
|
allNames := append([]string{}, cfg.Enable...)
|
||||||
|
allNames = append(allNames, cfg.Disable...)
|
||||||
|
for _, name := range allNames {
|
||||||
|
if v.m.getLinterConfig(name) == nil {
|
||||||
|
return fmt.Errorf("no such linter %q", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Validator) validatePresets(cfg *config.Linters) error {
|
||||||
|
allPresets := v.m.allPresetsSet()
|
||||||
|
for _, p := range cfg.Presets {
|
||||||
|
if !allPresets[p] {
|
||||||
|
return fmt.Errorf("no such preset %q: only next presets exist: (%s)",
|
||||||
|
p, strings.Join(v.m.AllPresets(), "|"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.Presets) != 0 && cfg.EnableAll {
|
||||||
|
return fmt.Errorf("--presets is incompatible with --enable-all")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Validator) validateAllDisableEnableOptions(cfg *config.Linters) error {
|
||||||
|
if cfg.EnableAll && cfg.DisableAll {
|
||||||
|
return fmt.Errorf("--enable-all and --disable-all options must not be combined")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.DisableAll {
|
||||||
|
if len(cfg.Enable) == 0 && len(cfg.Presets) == 0 {
|
||||||
|
return fmt.Errorf("all linters were disabled, but no one linter was enabled: must enable at least one")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.Disable) != 0 {
|
||||||
|
return fmt.Errorf("can't combine options --disable-all and --disable %s", cfg.Disable[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.EnableAll && len(cfg.Enable) != 0 && !cfg.Fast {
|
||||||
|
return fmt.Errorf("can't combine options --enable-all and --enable %s", cfg.Enable[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Validator) validateDisabledAndEnabledAtOneMoment(cfg *config.Linters) error {
|
||||||
|
enabledLintersSet := map[string]bool{}
|
||||||
|
for _, name := range cfg.Enable {
|
||||||
|
enabledLintersSet[name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range cfg.Disable {
|
||||||
|
if enabledLintersSet[name] {
|
||||||
|
return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Validator) validateEnabledDisabledLintersConfig(cfg *config.Linters) error {
|
||||||
|
validators := []func(cfg *config.Linters) error{
|
||||||
|
v.validateLintersNames,
|
||||||
|
v.validatePresets,
|
||||||
|
v.validateAllDisableEnableOptions,
|
||||||
|
v.validateDisabledAndEnabledAtOneMoment,
|
||||||
|
}
|
||||||
|
for _, v := range validators {
|
||||||
|
if err := v(cfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user