validate config and print resources usage
This commit is contained in:
parent
85ee97f776
commit
05f09371ac
@ -1,6 +1,4 @@
|
||||
run:
|
||||
args:
|
||||
- ./...
|
||||
verbose: true
|
||||
concurrency: 4
|
||||
deadline: 1m
|
||||
|
@ -2,11 +2,13 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -21,6 +23,7 @@ import (
|
||||
"github.com/golangci/golangci-lint/pkg/result/processors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
@ -51,6 +54,8 @@ func (e *Executor) initRun() {
|
||||
runCmd.Flags().StringSliceVar(&rc.BuildTags, "build-tags", []string{}, "Build tags (not all linters support them)")
|
||||
runCmd.Flags().DurationVar(&rc.Deadline, "deadline", time.Minute, "Deadline for total work")
|
||||
runCmd.Flags().BoolVar(&rc.AnalyzeTests, "tests", false, "Analyze tests (*_test.go)")
|
||||
runCmd.Flags().BoolVar(&rc.PrintResourcesUsage, "print-resources-usage", false, "Print avg and max memory usage of golangci-lint and total time")
|
||||
runCmd.Flags().StringVarP(&rc.Config, "config", "c", "", "Read config from file path `PATH`")
|
||||
|
||||
// Linters settings config
|
||||
lsc := &e.cfg.LintersSettings
|
||||
@ -98,8 +103,6 @@ func (e *Executor) initRun() {
|
||||
runCmd.Flags().StringVar(&ic.DiffFromRevision, "new-from-rev", "", "Show only new issues created after git revision `REV`")
|
||||
runCmd.Flags().StringVar(&ic.DiffPatchFilePath, "new-from-patch", "", "Show only new issues created in git patch with file path `PATH`")
|
||||
|
||||
runCmd.Flags().StringVarP(&e.cfg.Run.Config, "config", "c", "", "Read config from file path `PATH`")
|
||||
|
||||
e.parseConfig(runCmd)
|
||||
}
|
||||
|
||||
@ -240,45 +243,53 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) (chan result.
|
||||
return runner.Run(ctx, linters, lintCtx), nil
|
||||
}
|
||||
|
||||
func (e *Executor) runAndPrint(ctx context.Context, args []string) error {
|
||||
issues, err := e.runAnalysis(ctx, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var p printers.Printer
|
||||
if e.cfg.Output.Format == config.OutFormatJSON {
|
||||
p = printers.NewJSON()
|
||||
} else {
|
||||
p = printers.NewText(e.cfg.Output.PrintIssuedLine,
|
||||
e.cfg.Output.Format == config.OutFormatColoredLineNumber, e.cfg.Output.PrintLinterName)
|
||||
}
|
||||
gotAnyIssues, err := p.Print(issues)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't print %d issues: %s", len(issues), err)
|
||||
}
|
||||
|
||||
if gotAnyIssues {
|
||||
e.exitCode = e.cfg.Run.ExitCodeIfIssuesFound
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Executor) executeRun(cmd *cobra.Command, args []string) {
|
||||
needTrackResources := e.cfg.Run.IsVerbose || e.cfg.Run.PrintResourcesUsage
|
||||
trackResourcesEndCh := make(chan struct{})
|
||||
defer func() { // XXX: this defer must be before ctx.cancel defer
|
||||
if needTrackResources { // wait until resource tracking finished to print properly
|
||||
<-trackResourcesEndCh
|
||||
}
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.cfg.Run.Deadline)
|
||||
defer cancel()
|
||||
|
||||
defer func(startedAt time.Time) {
|
||||
logrus.Infof("Run took %s", time.Since(startedAt))
|
||||
}(time.Now())
|
||||
if needTrackResources {
|
||||
go watchResources(ctx, trackResourcesEndCh)
|
||||
}
|
||||
|
||||
if e.cfg.Output.PrintWelcomeMessage {
|
||||
fmt.Println("Run this tool in cloud on every github pull request in https://golangci.com for free (public repos)")
|
||||
}
|
||||
|
||||
f := func() error {
|
||||
issues, err := e.runAnalysis(ctx, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var p printers.Printer
|
||||
if e.cfg.Output.Format == config.OutFormatJSON {
|
||||
p = printers.NewJSON()
|
||||
} else {
|
||||
p = printers.NewText(e.cfg.Output.PrintIssuedLine,
|
||||
e.cfg.Output.Format == config.OutFormatColoredLineNumber, e.cfg.Output.PrintLinterName)
|
||||
}
|
||||
gotAnyIssues, err := p.Print(issues)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't print %d issues: %s", len(issues), err)
|
||||
}
|
||||
|
||||
if gotAnyIssues {
|
||||
e.exitCode = e.cfg.Run.ExitCodeIfIssuesFound
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := f(); err != nil {
|
||||
if err := e.runAndPrint(ctx, args); err != nil {
|
||||
log.Print(err)
|
||||
if e.exitCode == 0 {
|
||||
e.exitCode = exitCodeIfFailure
|
||||
@ -289,7 +300,10 @@ func (e *Executor) executeRun(cmd *cobra.Command, args []string) {
|
||||
func (e *Executor) parseConfig(cmd *cobra.Command) {
|
||||
// XXX: hack with double parsing to acces "config" option here
|
||||
if err := cmd.ParseFlags(os.Args); err != nil {
|
||||
log.Fatalf("Can't parse agrs: %s", err)
|
||||
if err == pflag.ErrHelp {
|
||||
return
|
||||
}
|
||||
log.Fatalf("Can't parse args: %s", err)
|
||||
}
|
||||
|
||||
if err := viper.BindPFlags(cmd.Flags()); err != nil {
|
||||
@ -318,4 +332,63 @@ func (e *Executor) parseConfig(cmd *cobra.Command) {
|
||||
if err := viper.Unmarshal(&e.cfg); err != nil {
|
||||
log.Fatalf("Can't unmarshal config by viper: %s", err)
|
||||
}
|
||||
|
||||
if err := e.validateConfig(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) validateConfig() error {
|
||||
c := e.cfg
|
||||
if len(c.Run.Args) != 0 {
|
||||
return errors.New("option run.args in config aren't supported now")
|
||||
}
|
||||
|
||||
if c.Run.CPUProfilePath != "" {
|
||||
return errors.New("option run.cpuprofilepath in config isn't allowed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func watchResources(ctx context.Context, done chan struct{}) {
|
||||
startedAt := time.Now()
|
||||
|
||||
rssValues := []uint64{}
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
|
||||
rssValues = append(rssValues, m.Sys)
|
||||
|
||||
stop := false
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
stop = true
|
||||
case <-ticker.C: // track every second
|
||||
}
|
||||
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var avg, max uint64
|
||||
for _, v := range rssValues {
|
||||
avg += v
|
||||
if v > max {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
avg /= uint64(len(rssValues))
|
||||
|
||||
const MB = 1024 * 1024
|
||||
maxMB := float64(max) / MB
|
||||
logrus.Infof("Memory: %d samples, avg is %.1fMB, max is %.1fMB",
|
||||
len(rssValues), float64(avg)/MB, maxMB)
|
||||
logrus.Infof("Execution took %s", time.Since(startedAt))
|
||||
close(done)
|
||||
}
|
||||
|
@ -39,9 +39,10 @@ var DefaultExcludePatterns = []string{
|
||||
}
|
||||
|
||||
type Run struct {
|
||||
IsVerbose bool `mapstructure:"verbose"`
|
||||
CPUProfilePath string
|
||||
Concurrency int
|
||||
IsVerbose bool `mapstructure:"verbose"`
|
||||
CPUProfilePath string
|
||||
Concurrency int
|
||||
PrintResourcesUsage bool `mapstructure:"print-resources-usage"`
|
||||
|
||||
Config string
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user