2019-09-14 20:15:11 +03:00

143 lines
3.4 KiB
Go

package processors
import (
"path/filepath"
"regexp"
"strings"
"github.com/pkg/errors"
"github.com/golangci/golangci-lint/pkg/logutils"
"github.com/golangci/golangci-lint/pkg/result"
)
type skipStat struct {
pattern string
count int
}
type SkipDirs struct {
patterns []*regexp.Regexp
log logutils.Log
skippedDirs map[string]*skipStat
absArgsDirs []string
skippedDirsCache map[string]bool
}
var _ Processor = SkipFiles{}
const goFileSuffix = ".go"
func NewSkipDirs(patterns []string, log logutils.Log, runArgs []string) (*SkipDirs, error) {
var patternsRe []*regexp.Regexp
for _, p := range patterns {
patternRe, err := regexp.Compile(p)
if err != nil {
return nil, errors.Wrapf(err, "can't compile regexp %q", p)
}
patternsRe = append(patternsRe, patternRe)
}
if len(runArgs) == 0 {
runArgs = append(runArgs, "./...")
}
var absArgsDirs []string
for _, arg := range runArgs {
base := filepath.Base(arg)
if base == "..." || strings.HasSuffix(base, goFileSuffix) {
arg = filepath.Dir(arg)
}
absArg, err := filepath.Abs(arg)
if err != nil {
return nil, errors.Wrapf(err, "failed to abs-ify arg %q", arg)
}
absArgsDirs = append(absArgsDirs, absArg)
}
return &SkipDirs{
patterns: patternsRe,
log: log,
skippedDirs: map[string]*skipStat{},
absArgsDirs: absArgsDirs,
skippedDirsCache: map[string]bool{},
}, nil
}
func (p *SkipDirs) Name() string {
return "skip_dirs"
}
func (p *SkipDirs) Process(issues []result.Issue) ([]result.Issue, error) {
if len(p.patterns) == 0 {
return issues, nil
}
return filterIssues(issues, p.shouldPassIssue), nil
}
func (p *SkipDirs) shouldPassIssue(i *result.Issue) bool {
if filepath.IsAbs(i.FilePath()) {
if !isSpecialAutogeneratedFile(i.FilePath()) {
p.log.Warnf("Got abs path %s in skip dirs processor, it should be relative", i.FilePath())
}
return true
}
issueRelDir := filepath.Dir(i.FilePath())
if toPass, ok := p.skippedDirsCache[issueRelDir]; ok {
if !toPass {
p.skippedDirs[issueRelDir].count++
}
return toPass
}
issueAbsDir, err := filepath.Abs(issueRelDir)
if err != nil {
p.log.Warnf("Can't abs-ify path %q: %s", issueRelDir, err)
return true
}
toPass := p.shouldPassIssueDirs(issueRelDir, issueAbsDir)
p.skippedDirsCache[issueRelDir] = toPass
return toPass
}
func (p *SkipDirs) shouldPassIssueDirs(issueRelDir, issueAbsDir string) bool {
for _, absArgDir := range p.absArgsDirs {
if absArgDir == issueAbsDir {
// we must not skip issues if they are from explicitly set dirs
// even if they match skip patterns
return true
}
}
// We use issueRelDir for matching: it's the relative to the current
// work dir path of directory of source file with the issue. It can lead
// to unexpected behavior if we're analyzing files out of current work dir.
// The alternative solution is to find relative to args path, but it has
// disadvantages (https://github.com/golangci/golangci-lint/pull/313).
for _, pattern := range p.patterns {
if pattern.MatchString(issueRelDir) {
ps := pattern.String()
if p.skippedDirs[issueRelDir] == nil {
p.skippedDirs[issueRelDir] = &skipStat{
pattern: ps,
}
}
p.skippedDirs[issueRelDir].count++
return false
}
}
return true
}
func (p *SkipDirs) Finish() {
for dir, stat := range p.skippedDirs {
p.log.Infof("Skipped %d issues from dir %s by pattern %s", stat.count, dir, stat.pattern)
}
}