Denis Isaev 5514c4393e Fix #17, #87: govet becomes SLOW linter by default
1. Allow govet to work in 2 modes: fast and slow. Default is slow.
In fast mode golangci-lint runs `go install -i` and `go test -i`
for analyzed packages. But it's fast only when:
  - go >= 1.10
  - it's repeated run or $GOPATH/pkg or `go env GOCACHE` is cached
  between CI builds
In slow mode we load program from source code like for another linters
and do it only once for all linters.

3. Patch govet code to warn about any troubles with the type
information. Default behaviour of govet was to hide such warnings.
Fail analysis if there are any troubles with type loading: it will
prevent false-positives and false-negatives from govet.

4. Describe almost all options in .golangci.example.yml and
include it into README. Describe when to use slow or fast mode of govet.

5. Speed up govet: reuse AST parsing: it's already parsed once by
golangci-lint.
For "slow" runs (when we run at least one slow linter) speedup by
not loading type information second time.

6. Improve logging, debug logging

7. Fix crash in logging of AST cache warnings (#118)
2018-06-18 09:47:15 +03:00

141 lines
3.6 KiB
Go

package main
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
"text/template"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
)
func main() {
const (
tmplPath = "README.md.tmpl"
outPath = "README.md"
)
if err := genReadme(tmplPath, outPath); err != nil {
log.Fatalf("failed: %s", err)
}
log.Printf("Successfully generated %s", outPath)
}
func genReadme(tmplPath, outPath string) error {
ctx, err := buildTemplateContext()
if err != nil {
return err
}
out, err := os.Create(outPath)
if err != nil {
return err
}
defer out.Close()
tmpl := template.Must(template.ParseFiles(tmplPath))
return tmpl.Execute(out, ctx)
}
func buildTemplateContext() (map[string]interface{}, error) {
golangciYaml, err := ioutil.ReadFile(".golangci.yml")
if err != nil {
return nil, fmt.Errorf("can't read .golangci.yml: %s", err)
}
golangciYamlExample, err := ioutil.ReadFile(".golangci.example.yml")
if err != nil {
return nil, fmt.Errorf("can't read .golangci.example.yml: %s", err)
}
if err = exec.Command("go", "install", "./cmd/...").Run(); err != nil {
return nil, fmt.Errorf("can't run go install: %s", err)
}
lintersOut, err := exec.Command("golangci-lint", "linters").Output()
if err != nil {
return nil, fmt.Errorf("can't run linters cmd: %s", err)
}
lintersOutParts := bytes.Split(lintersOut, []byte("\n\n"))
helpCmd := exec.Command("golangci-lint", "run", "-h")
helpCmd.Env = append(helpCmd.Env, os.Environ()...)
helpCmd.Env = append(helpCmd.Env, "HELP_RUN=1") // make default concurrency stable: don't depend on machine CPU number
help, err := helpCmd.Output()
if err != nil {
return nil, fmt.Errorf("can't run help cmd: %s", err)
}
helpLines := bytes.Split(help, []byte("\n"))
shortHelp := bytes.Join(helpLines[2:], []byte("\n"))
return map[string]interface{}{
"GolangciYaml": string(golangciYaml),
"GolangciYamlExample": string(golangciYamlExample),
"LintersCommandOutputEnabledOnly": string(lintersOutParts[0]),
"LintersCommandOutputDisabledOnly": string(lintersOutParts[1]),
"EnabledByDefaultLinters": getLintersListMarkdown(true),
"DisabledByDefaultLinters": getLintersListMarkdown(false),
"ThanksList": getThanksList(),
"RunHelpText": string(shortHelp),
}, nil
}
func getLintersListMarkdown(enabled bool) string {
var neededLcs []linter.Config
lcs := lintersdb.GetAllSupportedLinterConfigs()
for _, lc := range lcs {
if lc.EnabledByDefault == enabled {
neededLcs = append(neededLcs, lc)
}
}
var lines []string
for _, lc := range neededLcs {
var link string
if lc.OriginalURL != "" {
link = fmt.Sprintf("[%s](%s)", lc.Linter.Name(), lc.OriginalURL)
} else {
link = lc.Linter.Name()
}
line := fmt.Sprintf("- %s - %s", link, lc.Linter.Desc())
lines = append(lines, line)
}
return strings.Join(lines, "\n")
}
func getThanksList() string {
var lines []string
addedAuthors := map[string]bool{}
for _, lc := range lintersdb.GetAllSupportedLinterConfigs() {
if lc.OriginalURL == "" {
continue
}
const githubPrefix = "https://github.com/"
if !strings.HasPrefix(lc.OriginalURL, githubPrefix) {
continue
}
githubSuffix := strings.TrimPrefix(lc.OriginalURL, githubPrefix)
githubAuthor := strings.Split(githubSuffix, "/")[0]
if addedAuthors[githubAuthor] {
continue
}
addedAuthors[githubAuthor] = true
line := fmt.Sprintf("- [%s](https://github.com/%s)",
githubAuthor, githubAuthor)
lines = append(lines, line)
}
return strings.Join(lines, "\n")
}