rework skip dir algorithm
This commit is contained in:
parent
441bdb33d1
commit
7dfb9cff3d
@ -54,7 +54,7 @@ func NewRunner(astCache *astcache.Cache, cfg *config.Config, log logutils.Log, g
|
|||||||
processors.NewPathPrettifier(), // must be before diff, nolint and exclude autogenerated processor at least
|
processors.NewPathPrettifier(), // must be before diff, nolint and exclude autogenerated processor at least
|
||||||
processors.NewCgo(goenv),
|
processors.NewCgo(goenv),
|
||||||
skipFilesProcessor,
|
skipFilesProcessor,
|
||||||
skipDirsProcessor,
|
skipDirsProcessor, // must be after path prettifier
|
||||||
|
|
||||||
processors.NewAutogeneratedExclude(astCache),
|
processors.NewAutogeneratedExclude(astCache),
|
||||||
processors.NewExclude(excludeTotalPattern),
|
processors.NewExclude(excludeTotalPattern),
|
||||||
@ -205,6 +205,7 @@ func (r Runner) processLintResults(inCh <-chan lintRes) <-chan lintRes {
|
|||||||
go func() {
|
go func() {
|
||||||
sw := timeutils.NewStopwatch("processing", r.Log)
|
sw := timeutils.NewStopwatch("processing", r.Log)
|
||||||
|
|
||||||
|
var issuesBefore, issuesAfter int
|
||||||
defer close(outCh)
|
defer close(outCh)
|
||||||
|
|
||||||
for res := range inCh {
|
for res := range inCh {
|
||||||
@ -214,7 +215,9 @@ func (r Runner) processLintResults(inCh <-chan lintRes) <-chan lintRes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(res.issues) != 0 {
|
if len(res.issues) != 0 {
|
||||||
|
issuesBefore += len(res.issues)
|
||||||
res.issues = r.processIssues(res.issues, sw)
|
res.issues = r.processIssues(res.issues, sw)
|
||||||
|
issuesAfter += len(res.issues)
|
||||||
outCh <- res
|
outCh <- res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,6 +231,9 @@ func (r Runner) processLintResults(inCh <-chan lintRes) <-chan lintRes {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if issuesBefore != issuesAfter {
|
||||||
|
r.Log.Infof("Issues before processing: %d, after processing: %d", issuesBefore, issuesAfter)
|
||||||
|
}
|
||||||
sw.PrintStages()
|
sw.PrintStages()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package processors
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -13,19 +12,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SkipDirs struct {
|
type SkipDirs struct {
|
||||||
patterns []*regexp.Regexp
|
patterns []*regexp.Regexp
|
||||||
log logutils.Log
|
log logutils.Log
|
||||||
skippedDirs map[string]bool
|
skippedDirs map[string][]string // regexp to dir mapping
|
||||||
sortedAbsArgs []string
|
absArgsDirs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Processor = SkipFiles{}
|
var _ Processor = SkipFiles{}
|
||||||
|
|
||||||
type sortedByLenStrings []string
|
const goFileSuffix = ".go"
|
||||||
|
|
||||||
func (s sortedByLenStrings) Len() int { return len(s) }
|
|
||||||
func (s sortedByLenStrings) Less(i, j int) bool { return len(s[i]) > len(s[j]) }
|
|
||||||
func (s sortedByLenStrings) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
func NewSkipDirs(patterns []string, log logutils.Log, runArgs []string) (*SkipDirs, error) {
|
func NewSkipDirs(patterns []string, log logutils.Log, runArgs []string) (*SkipDirs, error) {
|
||||||
var patternsRe []*regexp.Regexp
|
var patternsRe []*regexp.Regexp
|
||||||
@ -40,24 +35,25 @@ func NewSkipDirs(patterns []string, log logutils.Log, runArgs []string) (*SkipDi
|
|||||||
if len(runArgs) == 0 {
|
if len(runArgs) == 0 {
|
||||||
runArgs = append(runArgs, "./...")
|
runArgs = append(runArgs, "./...")
|
||||||
}
|
}
|
||||||
var sortedAbsArgs []string
|
var absArgsDirs []string
|
||||||
for _, arg := range runArgs {
|
for _, arg := range runArgs {
|
||||||
if filepath.Base(arg) == "..." {
|
base := filepath.Base(arg)
|
||||||
|
if base == "..." || strings.HasSuffix(base, goFileSuffix) {
|
||||||
arg = filepath.Dir(arg)
|
arg = filepath.Dir(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
absArg, err := filepath.Abs(arg)
|
absArg, err := filepath.Abs(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to abs-ify arg %q", arg)
|
return nil, errors.Wrapf(err, "failed to abs-ify arg %q", arg)
|
||||||
}
|
}
|
||||||
sortedAbsArgs = append(sortedAbsArgs, absArg)
|
absArgsDirs = append(absArgsDirs, absArg)
|
||||||
}
|
}
|
||||||
sort.Sort(sortedByLenStrings(sortedAbsArgs))
|
|
||||||
|
|
||||||
return &SkipDirs{
|
return &SkipDirs{
|
||||||
patterns: patternsRe,
|
patterns: patternsRe,
|
||||||
log: log,
|
log: log,
|
||||||
skippedDirs: map[string]bool{},
|
skippedDirs: map[string][]string{},
|
||||||
sortedAbsArgs: sortedAbsArgs,
|
absArgsDirs: absArgsDirs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,38 +69,38 @@ func (p *SkipDirs) Process(issues []result.Issue) ([]result.Issue, error) {
|
|||||||
return filterIssues(issues, p.shouldPassIssue), nil
|
return filterIssues(issues, p.shouldPassIssue), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkipDirs) getLongestArgRelativeIssuePath(i *result.Issue) string {
|
|
||||||
issueAbsPath, err := filepath.Abs(i.FilePath())
|
|
||||||
if err != nil {
|
|
||||||
p.log.Warnf("Can't abs-ify path %q: %s", i.FilePath(), err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, arg := range p.sortedAbsArgs {
|
|
||||||
if !strings.HasPrefix(issueAbsPath, arg) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return i.FilePath()
|
|
||||||
}
|
|
||||||
|
|
||||||
p.log.Infof("Issue path %q isn't relative to any of run args", i.FilePath())
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SkipDirs) shouldPassIssue(i *result.Issue) bool {
|
func (p *SkipDirs) shouldPassIssue(i *result.Issue) bool {
|
||||||
relIssuePath := p.getLongestArgRelativeIssuePath(i)
|
if filepath.IsAbs(i.FilePath()) {
|
||||||
if relIssuePath == "" {
|
p.log.Warnf("Got abs path in skip dirs processor, it should be relative")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(filepath.Base(relIssuePath), ".go") {
|
issueRelDir := filepath.Dir(i.FilePath())
|
||||||
relIssuePath = filepath.Dir(relIssuePath)
|
issueAbsDir, err := filepath.Abs(issueRelDir)
|
||||||
|
if err != nil {
|
||||||
|
p.log.Warnf("Can't abs-ify path %q: %s", issueRelDir, err)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, absArgDir := range p.absArgsDirs {
|
||||||
|
if absArgDir == issueAbsDir {
|
||||||
|
p.log.Infof("Pass issue in file %s because it's dir was explicitly set in arg %s", i.FilePath(), absArgDir)
|
||||||
|
// 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 {
|
for _, pattern := range p.patterns {
|
||||||
if pattern.MatchString(relIssuePath) {
|
if pattern.MatchString(issueRelDir) {
|
||||||
p.skippedDirs[relIssuePath] = true
|
ps := pattern.String()
|
||||||
|
p.skippedDirs[ps] = append(p.skippedDirs[ps], issueRelDir)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,11 +109,7 @@ func (p *SkipDirs) shouldPassIssue(i *result.Issue) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p SkipDirs) Finish() {
|
func (p SkipDirs) Finish() {
|
||||||
if len(p.skippedDirs) != 0 {
|
for pattern, dirs := range p.skippedDirs {
|
||||||
var skippedDirs []string
|
p.log.Infof("Skipped by pattern %s dirs: %s", pattern, dirs)
|
||||||
for dir := range p.skippedDirs {
|
|
||||||
skippedDirs = append(skippedDirs, dir)
|
|
||||||
}
|
|
||||||
p.log.Infof("Skipped dirs: %s", skippedDirs)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,15 +56,21 @@ func TestUnsafeOk(t *testing.T) {
|
|||||||
testshared.NewLintRunner(t).Run("--enable-all", getTestDataDir("unsafe")).ExpectNoIssues()
|
testshared.NewLintRunner(t).Run("--enable-all", getTestDataDir("unsafe")).ExpectNoIssues()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSkippedDirs(t *testing.T) {
|
func TestSkippedDirsNoMatchArg(t *testing.T) {
|
||||||
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config", "--skip-dirs", "skip_me", "-Egolint",
|
dir := getTestDataDir("skipdirs", "skip_me", "nested")
|
||||||
getTestDataDir("skipdirs", "..."))
|
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config", "--skip-dirs", dir, "-Egolint", dir)
|
||||||
|
|
||||||
r.ExpectExitCode(exitcodes.IssuesFound).
|
r.ExpectExitCode(exitcodes.IssuesFound).
|
||||||
ExpectOutputEq("testdata/skipdirs/examples_no_skip/with_issue.go:8:9: if block ends with " +
|
ExpectOutputEq("testdata/skipdirs/skip_me/nested/with_issue.go:8:9: if block ends with " +
|
||||||
"a return statement, so drop this else and outdent its block (golint)\n")
|
"a return statement, so drop this else and outdent its block (golint)\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSkippedDirsTestdata(t *testing.T) {
|
||||||
|
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config", "-Egolint", getTestDataDir("skipdirs", "..."))
|
||||||
|
|
||||||
|
r.ExpectNoIssues() // all was skipped because in testdata
|
||||||
|
}
|
||||||
|
|
||||||
func TestDeadcodeNoFalsePositivesInMainPkg(t *testing.T) {
|
func TestDeadcodeNoFalsePositivesInMainPkg(t *testing.T) {
|
||||||
testshared.NewLintRunner(t).Run("--no-config", "--disable-all", "-Edeadcode", getTestDataDir("deadcode_main_pkg")).ExpectNoIssues()
|
testshared.NewLintRunner(t).Run("--no-config", "--disable-all", "-Edeadcode", getTestDataDir("deadcode_main_pkg")).ExpectNoIssues()
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ type RunResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RunResult) ExpectNoIssues() {
|
func (r *RunResult) ExpectNoIssues() {
|
||||||
assert.Equal(r.t, "", r.output, r.exitCode)
|
assert.Equal(r.t, "", r.output, "exit code is %d", r.exitCode)
|
||||||
assert.Equal(r.t, exitcodes.Success, r.exitCode, r.output)
|
assert.Equal(r.t, exitcodes.Success, r.exitCode, "output is %s", r.output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RunResult) ExpectExitCode(possibleCodes ...int) *RunResult {
|
func (r *RunResult) ExpectExitCode(possibleCodes ...int) *RunResult {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user