github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/commands/root.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "os" 6 "runtime" 7 "runtime/pprof" 8 "runtime/trace" 9 "strconv" 10 11 "github.com/spf13/cobra" 12 "github.com/spf13/pflag" 13 14 "github.com/elek/golangci-lint/pkg/config" 15 "github.com/elek/golangci-lint/pkg/logutils" 16 ) 17 18 func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) { 19 if e.cfg.Run.PrintVersion { 20 fmt.Fprintf(logutils.StdOut, "golangci-lint has version %s built from %s on %s\n", e.version, e.commit, e.date) 21 os.Exit(0) 22 } 23 24 runtime.GOMAXPROCS(e.cfg.Run.Concurrency) 25 26 if e.cfg.Run.CPUProfilePath != "" { 27 f, err := os.Create(e.cfg.Run.CPUProfilePath) 28 if err != nil { 29 e.log.Fatalf("Can't create file %s: %s", e.cfg.Run.CPUProfilePath, err) 30 } 31 if err := pprof.StartCPUProfile(f); err != nil { 32 e.log.Fatalf("Can't start CPU profiling: %s", err) 33 } 34 } 35 36 if e.cfg.Run.MemProfilePath != "" { 37 if rate := os.Getenv("GL_MEMPROFILE_RATE"); rate != "" { 38 runtime.MemProfileRate, _ = strconv.Atoi(rate) 39 } 40 } 41 42 if e.cfg.Run.TracePath != "" { 43 f, err := os.Create(e.cfg.Run.TracePath) 44 if err != nil { 45 e.log.Fatalf("Can't create file %s: %s", e.cfg.Run.TracePath, err) 46 } 47 if err = trace.Start(f); err != nil { 48 e.log.Fatalf("Can't start tracing: %s", err) 49 } 50 } 51 } 52 53 func (e *Executor) persistentPostRun(_ *cobra.Command, _ []string) { 54 if e.cfg.Run.CPUProfilePath != "" { 55 pprof.StopCPUProfile() 56 } 57 if e.cfg.Run.MemProfilePath != "" { 58 f, err := os.Create(e.cfg.Run.MemProfilePath) 59 if err != nil { 60 e.log.Fatalf("Can't create file %s: %s", e.cfg.Run.MemProfilePath, err) 61 } 62 63 var ms runtime.MemStats 64 runtime.ReadMemStats(&ms) 65 printMemStats(&ms, e.log) 66 67 if err := pprof.WriteHeapProfile(f); err != nil { 68 e.log.Fatalf("Can't write heap profile: %s", err) 69 } 70 f.Close() 71 } 72 if e.cfg.Run.TracePath != "" { 73 trace.Stop() 74 } 75 76 } 77 78 func printMemStats(ms *runtime.MemStats, logger logutils.Log) { 79 logger.Infof("Mem stats: alloc=%s total_alloc=%s sys=%s "+ 80 "heap_alloc=%s heap_sys=%s heap_idle=%s heap_released=%s heap_in_use=%s "+ 81 "stack_in_use=%s stack_sys=%s "+ 82 "mspan_sys=%s mcache_sys=%s buck_hash_sys=%s gc_sys=%s other_sys=%s "+ 83 "mallocs_n=%d frees_n=%d heap_objects_n=%d gc_cpu_fraction=%.2f", 84 formatMemory(ms.Alloc), formatMemory(ms.TotalAlloc), formatMemory(ms.Sys), 85 formatMemory(ms.HeapAlloc), formatMemory(ms.HeapSys), 86 formatMemory(ms.HeapIdle), formatMemory(ms.HeapReleased), formatMemory(ms.HeapInuse), 87 formatMemory(ms.StackInuse), formatMemory(ms.StackSys), 88 formatMemory(ms.MSpanSys), formatMemory(ms.MCacheSys), formatMemory(ms.BuckHashSys), 89 formatMemory(ms.GCSys), formatMemory(ms.OtherSys), 90 ms.Mallocs, ms.Frees, ms.HeapObjects, ms.GCCPUFraction) 91 } 92 93 func formatMemory(memBytes uint64) string { 94 const Kb = 1024 95 const Mb = Kb * 1024 96 97 if memBytes < Kb { 98 return fmt.Sprintf("%db", memBytes) 99 } 100 if memBytes < Mb { 101 return fmt.Sprintf("%dkb", memBytes/Kb) 102 } 103 return fmt.Sprintf("%dmb", memBytes/Mb) 104 } 105 106 func getDefaultConcurrency() int { 107 if os.Getenv("HELP_RUN") == "1" { 108 // Make stable concurrency for README help generating builds. 109 const prettyConcurrency = 8 110 return prettyConcurrency 111 } 112 113 return runtime.NumCPU() 114 } 115 116 func (e *Executor) initRoot() { 117 rootCmd := &cobra.Command{ 118 Use: "golangci-lint", 119 Short: "golangci-lint is a smart linters runner.", 120 Long: `Smart, fast linters runner. Run it in cloud for every GitHub pull request on https://golangci.com`, 121 Run: func(cmd *cobra.Command, args []string) { 122 if len(args) != 0 { 123 e.log.Fatalf("Usage: golangci-lint") 124 } 125 if err := cmd.Help(); err != nil { 126 e.log.Fatalf("Can't run help: %s", err) 127 } 128 }, 129 PersistentPreRun: e.persistentPreRun, 130 PersistentPostRun: e.persistentPostRun, 131 } 132 133 initRootFlagSet(rootCmd.PersistentFlags(), e.cfg, e.needVersionOption()) 134 e.rootCmd = rootCmd 135 } 136 137 func (e *Executor) needVersionOption() bool { 138 return e.date != "" 139 } 140 141 func initRootFlagSet(fs *pflag.FlagSet, cfg *config.Config, needVersionOption bool) { 142 fs.BoolVarP(&cfg.Run.IsVerbose, "verbose", "v", false, wh("verbose output")) 143 144 var silent bool 145 fs.BoolVarP(&silent, "silent", "s", false, wh("disables congrats outputs")) 146 if err := fs.MarkHidden("silent"); err != nil { 147 panic(err) 148 } 149 err := fs.MarkDeprecated("silent", 150 "now golangci-lint by default is silent: it doesn't print Congrats message") 151 if err != nil { 152 panic(err) 153 } 154 155 fs.StringVar(&cfg.Run.CPUProfilePath, "cpu-profile-path", "", wh("Path to CPU profile output file")) 156 fs.StringVar(&cfg.Run.MemProfilePath, "mem-profile-path", "", wh("Path to memory profile output file")) 157 fs.StringVar(&cfg.Run.TracePath, "trace-path", "", wh("Path to trace output file")) 158 fs.IntVarP(&cfg.Run.Concurrency, "concurrency", "j", getDefaultConcurrency(), wh("Concurrency (default NumCPU)")) 159 if needVersionOption { 160 fs.BoolVar(&cfg.Run.PrintVersion, "version", false, wh("Print version")) 161 } 162 163 fs.StringVar(&cfg.Output.Color, "color", "auto", wh("Use color when printing; can be 'always', 'auto', or 'never'")) 164 }