Run CI on mac os only with go1.13 and on windows only on go1.14. Speed up tests. Introduce --allow-parallel-runners. Block on parallel run lock 5s instead of 60s. Don't invalidate analysis cache for minor config changes.
		
			
				
	
	
		
			188 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package lintersdb
 | 
						|
 | 
						|
import (
 | 
						|
	"os"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/golangci/golangci-lint/pkg/config"
 | 
						|
	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
 | 
						|
	"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
 | 
						|
	debugf logutils.DebugFunc
 | 
						|
}
 | 
						|
 | 
						|
func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Config) *EnabledSet {
 | 
						|
	return &EnabledSet{
 | 
						|
		m:      m,
 | 
						|
		v:      v,
 | 
						|
		log:    log,
 | 
						|
		cfg:    cfg,
 | 
						|
		debugf: logutils.Debug("enabled_linters"),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (es EnabledSet) build(lcfg *config.Linters, enabledByDefaultLinters []*linter.Config) map[string]*linter.Config {
 | 
						|
	es.debugf("Linters config: %#v", lcfg)
 | 
						|
	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.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, lc := range resultLintersSet {
 | 
						|
			if lc.IsSlowLinter() {
 | 
						|
				delete(resultLintersSet, name)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for _, name := range lcfg.Enable {
 | 
						|
		for _, lc := range es.m.GetLinterConfigs(name) {
 | 
						|
			// it's important to use lc.Name() nor name because name can be alias
 | 
						|
			resultLintersSet[lc.Name()] = lc
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for _, name := range lcfg.Disable {
 | 
						|
		for _, lc := range es.m.GetLinterConfigs(name) {
 | 
						|
			// it's important to use lc.Name() nor name because name can be alias
 | 
						|
			delete(resultLintersSet, lc.Name())
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return resultLintersSet
 | 
						|
}
 | 
						|
 | 
						|
func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error) {
 | 
						|
	if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	enabledLinters := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
 | 
						|
	if os.Getenv("GL_TEST_RUN") == "1" {
 | 
						|
		es.verbosePrintLintersStatus(enabledLinters)
 | 
						|
	}
 | 
						|
	return enabledLinters, nil
 | 
						|
}
 | 
						|
 | 
						|
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters
 | 
						|
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
 | 
						|
// one metalinter for data reuse and speed up.
 | 
						|
func (es EnabledSet) GetOptimizedLinters() ([]*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())
 | 
						|
	es.verbosePrintLintersStatus(resultLintersSet)
 | 
						|
	es.combineGoAnalysisLinters(resultLintersSet)
 | 
						|
 | 
						|
	var resultLinters []*linter.Config
 | 
						|
	for _, lc := range resultLintersSet {
 | 
						|
		resultLinters = append(resultLinters, lc)
 | 
						|
	}
 | 
						|
 | 
						|
	// Make order of execution of linters (go/analysis metalinter and unused) stable.
 | 
						|
	sort.Slice(resultLinters, func(i, j int) bool {
 | 
						|
		a, b := resultLinters[i], resultLinters[j]
 | 
						|
		if a.DoesChangeTypes != b.DoesChangeTypes {
 | 
						|
			return b.DoesChangeTypes // move type-changing linters to the end to optimize speed
 | 
						|
		}
 | 
						|
		return strings.Compare(a.Name(), b.Name()) < 0
 | 
						|
	})
 | 
						|
 | 
						|
	return resultLinters, nil
 | 
						|
}
 | 
						|
 | 
						|
func (es EnabledSet) combineGoAnalysisLinters(linters map[string]*linter.Config) {
 | 
						|
	var goanalysisLinters []*goanalysis.Linter
 | 
						|
	goanalysisPresets := map[string]bool{}
 | 
						|
	for _, linter := range linters {
 | 
						|
		lnt, ok := linter.Linter.(*goanalysis.Linter)
 | 
						|
		if !ok {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if lnt.LoadMode() == goanalysis.LoadModeWholeProgram {
 | 
						|
			// It's ineffective by CPU and memory to run whole-program and incremental analyzers at once.
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		goanalysisLinters = append(goanalysisLinters, lnt)
 | 
						|
		for _, p := range linter.InPresets {
 | 
						|
			goanalysisPresets[p] = true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if len(goanalysisLinters) <= 1 {
 | 
						|
		es.debugf("Didn't combine go/analysis linters: got only %d linters", len(goanalysisLinters))
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	for _, lnt := range goanalysisLinters {
 | 
						|
		delete(linters, lnt.Name())
 | 
						|
	}
 | 
						|
 | 
						|
	// Make order of execution of go/analysis analyzers stable.
 | 
						|
	sort.Slice(goanalysisLinters, func(i, j int) bool {
 | 
						|
		return strings.Compare(goanalysisLinters[i].Name(), goanalysisLinters[j].Name()) <= 0
 | 
						|
	})
 | 
						|
	ml := goanalysis.NewMetaLinter(goanalysisLinters)
 | 
						|
 | 
						|
	var presets []string
 | 
						|
	for p := range goanalysisPresets {
 | 
						|
		presets = append(presets, p)
 | 
						|
	}
 | 
						|
 | 
						|
	mlConfig := &linter.Config{
 | 
						|
		Linter:           ml,
 | 
						|
		EnabledByDefault: false,
 | 
						|
		InPresets:        presets,
 | 
						|
		AlternativeNames: nil,
 | 
						|
		OriginalURL:      "",
 | 
						|
	}
 | 
						|
 | 
						|
	mlConfig = mlConfig.WithLoadForGoAnalysis()
 | 
						|
 | 
						|
	linters[ml.Name()] = mlConfig
 | 
						|
	es.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters))
 | 
						|
}
 | 
						|
 | 
						|
func (es EnabledSet) verbosePrintLintersStatus(lcs map[string]*linter.Config) {
 | 
						|
	var linterNames []string
 | 
						|
	for _, lc := range lcs {
 | 
						|
		linterNames = append(linterNames, lc.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)
 | 
						|
	}
 | 
						|
}
 |