dev: clean context loader (#4480)
This commit is contained in:
parent
1aa28ec6a4
commit
6fda81008d
@ -363,19 +363,18 @@ func (c *runCommand) runAnalysis(ctx context.Context, args []string) ([]result.I
|
||||
c.reportData.AddLinter(lc.Name(), isEnabled, lc.EnabledByDefault)
|
||||
}
|
||||
|
||||
lintCtx, err := c.contextLoader.Load(ctx, lintersToRun)
|
||||
lintCtx, err := c.contextLoader.Load(ctx, c.log.Child(logutils.DebugKeyLintersContext), lintersToRun)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("context loading failed: %w", err)
|
||||
}
|
||||
lintCtx.Log = c.log.Child(logutils.DebugKeyLintersContext)
|
||||
|
||||
runner, err := lint.NewRunner(c.log.Child(logutils.DebugKeyRunner),
|
||||
c.cfg, c.goenv, c.lineCache, c.fileCache, c.dbManager, lintCtx.Packages)
|
||||
c.cfg, c.goenv, c.lineCache, c.fileCache, c.dbManager, lintCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return runner.Run(ctx, lintersToRun, lintCtx)
|
||||
return runner.Run(ctx, lintersToRun)
|
||||
}
|
||||
|
||||
func (c *runCommand) setOutputToDevNull() (savedStdout, savedStderr *os.File) {
|
||||
|
@ -50,6 +50,37 @@ func NewContextLoader(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
|
||||
}
|
||||
}
|
||||
|
||||
func (cl *ContextLoader) Load(ctx context.Context, log logutils.Log, linters []*linter.Config) (*linter.Context, error) {
|
||||
loadMode := cl.findLoadMode(linters)
|
||||
pkgs, err := cl.loadPackages(ctx, loadMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load packages: %w", err)
|
||||
}
|
||||
|
||||
deduplicatedPkgs := cl.filterDuplicatePackages(pkgs)
|
||||
|
||||
if len(deduplicatedPkgs) == 0 {
|
||||
return nil, exitcodes.ErrNoGoFiles
|
||||
}
|
||||
|
||||
ret := &linter.Context{
|
||||
Packages: deduplicatedPkgs,
|
||||
|
||||
// At least `unused` linters works properly only on original (not deduplicated) packages,
|
||||
// see https://github.com/golangci/golangci-lint/pull/585.
|
||||
OriginalPackages: pkgs,
|
||||
|
||||
Cfg: cl.cfg,
|
||||
Log: log,
|
||||
FileCache: cl.fileCache,
|
||||
LineCache: cl.lineCache,
|
||||
PkgCache: cl.pkgCache,
|
||||
LoadGuard: cl.loadGuard,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (cl *ContextLoader) prepareBuildContext() {
|
||||
// Set GOROOT to have working cross-compilation: cross-compiled binaries
|
||||
// have invalid GOROOT. XXX: can't use runtime.GOROOT().
|
||||
@ -213,13 +244,6 @@ func (cl *ContextLoader) loadPackages(ctx context.Context, loadMode packages.Loa
|
||||
return nil, fmt.Errorf("failed to load with go/packages: %w", err)
|
||||
}
|
||||
|
||||
// Currently, go/packages doesn't guarantee that error will be returned
|
||||
// if context was canceled. See
|
||||
// https://github.com/golang/tools/commit/c5cec6710e927457c3c29d6c156415e8539a5111#r39261855
|
||||
if ctx.Err() != nil {
|
||||
return nil, fmt.Errorf("timed out to load packages: %w", ctx.Err())
|
||||
}
|
||||
|
||||
if loadMode&packages.NeedSyntax == 0 {
|
||||
// Needed e.g. for go/analysis loading.
|
||||
fset := token.NewFileSet()
|
||||
@ -293,34 +317,3 @@ func (cl *ContextLoader) filterDuplicatePackages(pkgs []*packages.Package) []*pa
|
||||
|
||||
return retPkgs
|
||||
}
|
||||
|
||||
func (cl *ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*linter.Context, error) {
|
||||
loadMode := cl.findLoadMode(linters)
|
||||
pkgs, err := cl.loadPackages(ctx, loadMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load packages: %w", err)
|
||||
}
|
||||
|
||||
deduplicatedPkgs := cl.filterDuplicatePackages(pkgs)
|
||||
|
||||
if len(deduplicatedPkgs) == 0 {
|
||||
return nil, exitcodes.ErrNoGoFiles
|
||||
}
|
||||
|
||||
ret := &linter.Context{
|
||||
Packages: deduplicatedPkgs,
|
||||
|
||||
// At least `unused` linters works properly only on original (not deduplicated) packages,
|
||||
// see https://github.com/golangci/golangci-lint/pull/585.
|
||||
OriginalPackages: pkgs,
|
||||
|
||||
Cfg: cl.cfg,
|
||||
Log: cl.log,
|
||||
FileCache: cl.fileCache,
|
||||
LineCache: cl.lineCache,
|
||||
PkgCache: cl.pkgCache,
|
||||
LoadGuard: cl.loadGuard,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ import (
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
gopackages "golang.org/x/tools/go/packages"
|
||||
|
||||
"github.com/golangci/golangci-lint/internal/errorutil"
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/fsutils"
|
||||
@ -22,14 +20,21 @@ import (
|
||||
"github.com/golangci/golangci-lint/pkg/timeutils"
|
||||
)
|
||||
|
||||
type processorStat struct {
|
||||
inCount int
|
||||
outCount int
|
||||
}
|
||||
|
||||
type Runner struct {
|
||||
Processors []processors.Processor
|
||||
Log logutils.Log
|
||||
|
||||
lintCtx *linter.Context
|
||||
Processors []processors.Processor
|
||||
}
|
||||
|
||||
func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env,
|
||||
lineCache *fsutils.LineCache, fileCache *fsutils.FileCache,
|
||||
dbManager *lintersdb.Manager, pkgs []*gopackages.Package) (*Runner, error) {
|
||||
dbManager *lintersdb.Manager, lintCtx *linter.Context) (*Runner, error) {
|
||||
// Beware that some processors need to add the path prefix when working with paths
|
||||
// because they get invoked before the path prefixer (exclude and severity rules)
|
||||
// or process other paths (skip files).
|
||||
@ -75,7 +80,7 @@ func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env,
|
||||
processors.NewCgo(goenv),
|
||||
|
||||
// Must go after Cgo.
|
||||
processors.NewFilenameUnadjuster(pkgs, log.Child(logutils.DebugKeyFilenameUnadjuster)),
|
||||
processors.NewFilenameUnadjuster(lintCtx.Packages, log.Child(logutils.DebugKeyFilenameUnadjuster)),
|
||||
|
||||
// Must be before diff, nolint and exclude autogenerated processor at least.
|
||||
processors.NewPathPrettifier(),
|
||||
@ -107,10 +112,38 @@ func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env,
|
||||
processors.NewPathPrefixer(cfg.Output.PathPrefix),
|
||||
processors.NewSortResults(cfg),
|
||||
},
|
||||
lintCtx: lintCtx,
|
||||
Log: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]result.Issue, error) {
|
||||
sw := timeutils.NewStopwatch("linters", r.Log)
|
||||
defer sw.Print()
|
||||
|
||||
var (
|
||||
lintErrors error
|
||||
issues []result.Issue
|
||||
)
|
||||
|
||||
for _, lc := range linters {
|
||||
lc := lc
|
||||
sw.TrackStage(lc.Name(), func() {
|
||||
linterIssues, err := r.runLinterSafe(ctx, r.lintCtx, lc)
|
||||
if err != nil {
|
||||
lintErrors = errors.Join(lintErrors, fmt.Errorf("can't run linter %s", lc.Linter.Name()), err)
|
||||
r.Log.Warnf("Can't run linter %s: %v", lc.Linter.Name(), err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
issues = append(issues, linterIssues...)
|
||||
})
|
||||
}
|
||||
|
||||
return r.processLintResults(issues), lintErrors
|
||||
}
|
||||
|
||||
func (r *Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context,
|
||||
lc *linter.Config) (ret []result.Issue, err error) {
|
||||
defer func() {
|
||||
@ -151,12 +184,7 @@ func (r *Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context,
|
||||
return issues, nil
|
||||
}
|
||||
|
||||
type processorStat struct {
|
||||
inCount int
|
||||
outCount int
|
||||
}
|
||||
|
||||
func (r Runner) processLintResults(inIssues []result.Issue) []result.Issue {
|
||||
func (r *Runner) processLintResults(inIssues []result.Issue) []result.Issue {
|
||||
sw := timeutils.NewStopwatch("processing", r.Log)
|
||||
|
||||
var issuesBefore, issuesAfter int
|
||||
@ -187,7 +215,7 @@ func (r Runner) processLintResults(inIssues []result.Issue) []result.Issue {
|
||||
return outIssues
|
||||
}
|
||||
|
||||
func (r Runner) printPerProcessorStat(stat map[string]processorStat) {
|
||||
func (r *Runner) printPerProcessorStat(stat map[string]processorStat) {
|
||||
parts := make([]string, 0, len(stat))
|
||||
for name, ps := range stat {
|
||||
if ps.inCount != 0 {
|
||||
@ -199,33 +227,6 @@ func (r Runner) printPerProcessorStat(stat map[string]processorStat) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||
sw := timeutils.NewStopwatch("linters", r.Log)
|
||||
defer sw.Print()
|
||||
|
||||
var (
|
||||
lintErrors error
|
||||
issues []result.Issue
|
||||
)
|
||||
|
||||
for _, lc := range linters {
|
||||
lc := lc
|
||||
sw.TrackStage(lc.Name(), func() {
|
||||
linterIssues, err := r.runLinterSafe(ctx, lintCtx, lc)
|
||||
if err != nil {
|
||||
lintErrors = errors.Join(lintErrors, fmt.Errorf("can't run linter %s", lc.Linter.Name()), err)
|
||||
r.Log.Warnf("Can't run linter %s: %v", lc.Linter.Name(), err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
issues = append(issues, linterIssues...)
|
||||
})
|
||||
}
|
||||
|
||||
return r.processLintResults(issues), lintErrors
|
||||
}
|
||||
|
||||
func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, statPerProcessor map[string]processorStat) []result.Issue {
|
||||
for _, p := range r.Processors {
|
||||
var newIssues []result.Issue
|
||||
|
Loading…
x
Reference in New Issue
Block a user