Add cross-compilation Makefile targets and tar-based releases.
Revamp the build system to be more inline with other Prometheus exporters. Notably add Darwin and Windows build targets, and add support for releases using tar files.
This commit is contained in:
58
tools/vendor/github.com/alecthomas/gometalinter/README.md
generated
vendored
58
tools/vendor/github.com/alecthomas/gometalinter/README.md
generated
vendored
@@ -19,7 +19,6 @@
|
||||
- [2. Analyse the debug output](#2-analyse-the-debug-output)
|
||||
- [3. Report an issue.](#3-report-an-issue)
|
||||
- [How do I filter issues between two git refs?](#how-do-i-filter-issues-between-two-git-refs)
|
||||
- [Details](#details)
|
||||
- [Checkstyle XML format](#checkstyle-xml-format)
|
||||
|
||||
<!-- /MarkdownTOC -->
|
||||
@@ -57,12 +56,13 @@ It is intended for use with editor/IDE integration.
|
||||
- [go vet](https://golang.org/cmd/vet/) - Reports potential errors that otherwise compile.
|
||||
- [go tool vet --shadow](https://golang.org/cmd/vet/#hdr-Shadowed_variables) - Reports variables that may have been unintentionally shadowed.
|
||||
- [gotype](https://golang.org/x/tools/cmd/gotype) - Syntactic and semantic analysis similar to the Go compiler.
|
||||
- [gotype -x](https://golang.org/x/tools/cmd/gotype) - Syntactic and semantic analysis in external test packages (similar to the Go compiler).
|
||||
- [deadcode](https://github.com/tsenart/deadcode) - Finds unused code.
|
||||
- [gocyclo](https://github.com/alecthomas/gocyclo) - Computes the cyclomatic complexity of functions.
|
||||
- [golint](https://github.com/golang/lint) - Google's (mostly stylistic) linter.
|
||||
- [varcheck](https://github.com/opennota/check) - Find unused global variables and constants.
|
||||
- [structcheck](https://github.com/opennota/check) - Find unused struct fields.
|
||||
- [aligncheck](https://github.com/opennota/check) - Warn about un-optimally aligned structures.
|
||||
- [maligned](https://github.com/mdempsky/maligned) - Detect structs that would take less memory if their fields were sorted.
|
||||
- [errcheck](https://github.com/kisielk/errcheck) - Check that error return values are used.
|
||||
- [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck) - Run staticcheck, gosimple and unused, sharing work.
|
||||
- [dupl](https://github.com/mibk/dupl) - Reports potentially duplicated code.
|
||||
@@ -81,6 +81,7 @@ Disabled by default (enable with `--enable=<linter>`):
|
||||
- [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) - Report simplifications in code.
|
||||
- [lll](https://github.com/walle/lll) - Report long lines (see `--line-length=N`).
|
||||
- [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words.
|
||||
- [nakedret](https://github.com/alexkohler/nakedret) - Finds naked returns.
|
||||
- [unparam](https://github.com/mvdan/unparam) - Find unused function parameters.
|
||||
- [unused](https://github.com/dominikh/go-tools/tree/master/cmd/unused) - Find unused variables.
|
||||
- [safesql](https://github.com/stripe/safesql) - Finds potential SQL injection vulnerabilities.
|
||||
@@ -91,14 +92,15 @@ Additional linters can be added through the command line with `--linter=NAME:COM
|
||||
## Configuration file
|
||||
|
||||
gometalinter now supports a JSON configuration file which can be loaded via
|
||||
`--config=<file>`. The format of this file is determined by the Config struct
|
||||
in `config.go`.
|
||||
`--config=<file>`. The format of this file is determined by the `Config` struct
|
||||
in [config.go](https://github.com/alecthomas/gometalinter/blob/master/config.go).
|
||||
|
||||
The configuration file mostly corresponds to command-line flags, with the following exceptions:
|
||||
|
||||
- Linters defined in the configuration file will overlay existing definitions, not replace them.
|
||||
- "Enable" defines the exact set of linters that will be enabled (default
|
||||
linters are disabled).
|
||||
linters are disabled). `--help` displays the list of default linters with the exact names
|
||||
you must use.
|
||||
|
||||
Here is an example configuration file:
|
||||
|
||||
@@ -108,6 +110,34 @@ Here is an example configuration file:
|
||||
}
|
||||
```
|
||||
|
||||
### Adding Custom linters
|
||||
|
||||
Linters can be added and customized from the config file using the `Linters` field.
|
||||
Linters supports the following fields:
|
||||
|
||||
* `Command` - the path to the linter binary and any default arguments
|
||||
* `Pattern` - a regular expression used to parse the linter output
|
||||
* `IsFast` - if the linter should be run when the `--fast` flag is used
|
||||
* `PartitionStrategy` - how paths args should be passed to the linter command:
|
||||
* `directories` - call the linter once with a list of all the directories
|
||||
* `files` - call the linter once with a list of all the files
|
||||
* `packages` - call the linter once with a list of all the package paths
|
||||
* `files-by-package` - call the linter once per package with a list of the
|
||||
files in the package.
|
||||
* `single-directory` - call the linter once per directory
|
||||
|
||||
The config for default linters can be overridden by using the name of the
|
||||
linter.
|
||||
|
||||
Additional linters can be configured via the command line using the format
|
||||
`NAME:COMMAND:PATTERN`.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
$ gometalinter --linter='vet:go tool vet -printfuncs=Infof,Debugf,Warningf,Errorf:PATH:LINE:MESSAGE' .
|
||||
```
|
||||
|
||||
## Installing
|
||||
|
||||
There are two options for installing gometalinter.
|
||||
@@ -171,7 +201,8 @@ Install all known linters:
|
||||
$ gometalinter --install
|
||||
Installing:
|
||||
structcheck
|
||||
aligncheck
|
||||
maligned
|
||||
nakedret
|
||||
deadcode
|
||||
gocyclo
|
||||
ineffassign
|
||||
@@ -308,21 +339,6 @@ gometalinter |& revgrep master # Show issues between master and HEAD (or
|
||||
gometalinter |& revgrep origin/master # Show issues that haven't been pushed.
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
Additional linters can be configured via the command line:
|
||||
|
||||
```
|
||||
$ gometalinter --linter='vet:go tool vet -printfuncs=Infof,Debugf,Warningf,Errorf {path}:PATH:LINE:MESSAGE' .
|
||||
stutter.go:21:15:warning: error return value not checked (defer a.Close()) (errcheck)
|
||||
stutter.go:22:15:warning: error return value not checked (defer a.Close()) (errcheck)
|
||||
stutter.go:27:6:warning: error return value not checked (doit() // test for errcheck) (errcheck)
|
||||
stutter.go:9::warning: unused global variable unusedGlobal (varcheck)
|
||||
stutter.go:13::warning: unused struct field MyStruct.Unused (structcheck)
|
||||
stutter.go:12:6:warning: exported type MyStruct should have comment or be unexported (golint)
|
||||
stutter.go:16:6:warning: exported type PublicUndocumented should have comment or be unexported (deadcode)
|
||||
```
|
||||
|
||||
## Checkstyle XML format
|
||||
|
||||
`gometalinter` supports [checkstyle](http://checkstyle.sourceforge.net/)
|
||||
|
||||
32
tools/vendor/github.com/alecthomas/gometalinter/aggregate.go
generated
vendored
32
tools/vendor/github.com/alecthomas/gometalinter/aggregate.go
generated
vendored
@@ -5,27 +5,21 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
issueKey struct {
|
||||
path string
|
||||
line, col int
|
||||
message string
|
||||
}
|
||||
|
||||
multiIssue struct {
|
||||
*Issue
|
||||
linterNames []string
|
||||
}
|
||||
)
|
||||
|
||||
func maybeAggregateIssues(issues chan *Issue) chan *Issue {
|
||||
if !config.Aggregate {
|
||||
return issues
|
||||
}
|
||||
return aggregateIssues(issues)
|
||||
type issueKey struct {
|
||||
path string
|
||||
line, col int
|
||||
message string
|
||||
}
|
||||
|
||||
func aggregateIssues(issues chan *Issue) chan *Issue {
|
||||
type multiIssue struct {
|
||||
*Issue
|
||||
linterNames []string
|
||||
}
|
||||
|
||||
// AggregateIssueChan reads issues from a channel, aggregates issues which have
|
||||
// the same file, line, vol, and message, and returns aggregated issues on
|
||||
// a new channel.
|
||||
func AggregateIssueChan(issues chan *Issue) chan *Issue {
|
||||
out := make(chan *Issue, 1000000)
|
||||
issueMap := make(map[issueKey]*multiIssue)
|
||||
go func() {
|
||||
|
||||
2
tools/vendor/github.com/alecthomas/gometalinter/checkstyle.go
generated
vendored
2
tools/vendor/github.com/alecthomas/gometalinter/checkstyle.go
generated
vendored
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
type checkstyleOutput struct {
|
||||
|
||||
46
tools/vendor/github.com/alecthomas/gometalinter/config.go
generated
vendored
46
tools/vendor/github.com/alecthomas/gometalinter/config.go
generated
vendored
@@ -8,12 +8,12 @@ import (
|
||||
)
|
||||
|
||||
// Config for gometalinter. This can be loaded from a JSON file with --config.
|
||||
type Config struct { // nolint: aligncheck
|
||||
// A map of linter name to "<command>:<pattern>".
|
||||
type Config struct { // nolint: maligned
|
||||
// A map from linter name -> <LinterConfig|string>.
|
||||
//
|
||||
// <command> should always include {path} as the target directory to execute. Globs in <command>
|
||||
// are expanded by gometalinter (not by the shell).
|
||||
Linters map[string]string
|
||||
// For backwards compatibility, the value stored in the JSON blob can also
|
||||
// be a string of the form "<command>:<pattern>".
|
||||
Linters map[string]StringOrLinterConfig
|
||||
|
||||
// The set of linters that should be enabled.
|
||||
Enable []string
|
||||
@@ -51,6 +51,35 @@ type Config struct { // nolint: aligncheck
|
||||
EnableGC bool
|
||||
Aggregate bool
|
||||
EnableAll bool
|
||||
|
||||
// Warn if a nolint directive was never matched to a linter issue
|
||||
WarnUnmatchedDirective bool
|
||||
|
||||
formatTemplate *template.Template
|
||||
}
|
||||
|
||||
type StringOrLinterConfig LinterConfig
|
||||
|
||||
func (c *StringOrLinterConfig) UnmarshalJSON(raw []byte) error {
|
||||
var linterConfig LinterConfig
|
||||
// first try to un-marshall directly into struct
|
||||
origErr := json.Unmarshal(raw, &linterConfig)
|
||||
if origErr == nil {
|
||||
*c = StringOrLinterConfig(linterConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
// i.e. bytes didn't represent the struct, treat them as a string
|
||||
var linterSpec string
|
||||
if err := json.Unmarshal(raw, &linterSpec); err != nil {
|
||||
return origErr
|
||||
}
|
||||
linter, err := parseLinterConfigSpec("", linterSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*c = StringOrLinterConfig(linter)
|
||||
return nil
|
||||
}
|
||||
|
||||
type jsonDuration time.Duration
|
||||
@@ -70,17 +99,16 @@ func (td *jsonDuration) Duration() time.Duration {
|
||||
return time.Duration(*td)
|
||||
}
|
||||
|
||||
// TODO: should be a field on Config struct
|
||||
var formatTemplate = &template.Template{}
|
||||
|
||||
var sortKeys = []string{"none", "path", "line", "column", "severity", "message", "linter"}
|
||||
|
||||
// Configuration defaults.
|
||||
var config = &Config{
|
||||
Format: "{{.Path}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})",
|
||||
Format: DefaultIssueFormat,
|
||||
|
||||
Linters: map[string]StringOrLinterConfig{},
|
||||
Severity: map[string]string{
|
||||
"gotype": "error",
|
||||
"gotypex": "error",
|
||||
"test": "error",
|
||||
"testify": "error",
|
||||
"vet": "error",
|
||||
|
||||
62
tools/vendor/github.com/alecthomas/gometalinter/directives.go
generated
vendored
62
tools/vendor/github.com/alecthomas/gometalinter/directives.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
@@ -14,6 +15,7 @@ type ignoredRange struct {
|
||||
col int
|
||||
start, end int
|
||||
linters []string
|
||||
matched bool
|
||||
}
|
||||
|
||||
func (i *ignoredRange) matches(issue *Issue) bool {
|
||||
@@ -35,6 +37,14 @@ func (i *ignoredRange) near(col, start int) bool {
|
||||
return col == i.col && i.end == start-1
|
||||
}
|
||||
|
||||
func (i *ignoredRange) String() string {
|
||||
linters := strings.Join(i.linters, ",")
|
||||
if len(i.linters) == 0 {
|
||||
linters = "all"
|
||||
}
|
||||
return fmt.Sprintf("%s:%d-%d", linters, i.start, i.end)
|
||||
}
|
||||
|
||||
type ignoredRanges []*ignoredRange
|
||||
|
||||
func (ir ignoredRanges) Len() int { return len(ir) }
|
||||
@@ -66,12 +76,43 @@ func (d *directiveParser) IsIgnored(issue *Issue) bool {
|
||||
d.lock.Unlock()
|
||||
for _, r := range ranges {
|
||||
if r.matches(issue) {
|
||||
debug("nolint: matched %s to issue %s", r, issue)
|
||||
r.matched = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Unmatched returns all the ranges which were never used to ignore an issue
|
||||
func (d *directiveParser) Unmatched() map[string]ignoredRanges {
|
||||
unmatched := map[string]ignoredRanges{}
|
||||
for path, ranges := range d.files {
|
||||
for _, ignore := range ranges {
|
||||
if !ignore.matched {
|
||||
unmatched[path] = append(unmatched[path], ignore)
|
||||
}
|
||||
}
|
||||
}
|
||||
return unmatched
|
||||
}
|
||||
|
||||
// LoadFiles from a list of directories
|
||||
func (d *directiveParser) LoadFiles(paths []string) error {
|
||||
d.lock.Lock()
|
||||
defer d.lock.Unlock()
|
||||
filenames, err := pathsToFileGlobs(paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, filename := range filenames {
|
||||
ranges := d.parseFile(filename)
|
||||
sort.Sort(ranges)
|
||||
d.files[filename] = ranges
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Takes a set of ignoredRanges, determines if they immediately precede a statement
|
||||
// construct, and expands the range to include that construct. Why? So you can
|
||||
// precede a function or struct with //nolint
|
||||
@@ -150,7 +191,28 @@ func filterIssuesViaDirectives(directives *directiveParser, issues chan *Issue)
|
||||
out <- issue
|
||||
}
|
||||
}
|
||||
|
||||
if config.WarnUnmatchedDirective {
|
||||
for _, issue := range warnOnUnusedDirective(directives) {
|
||||
out <- issue
|
||||
}
|
||||
}
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func warnOnUnusedDirective(directives *directiveParser) []*Issue {
|
||||
out := []*Issue{}
|
||||
for path, ranges := range directives.Unmatched() {
|
||||
for _, ignore := range ranges {
|
||||
issue, _ := NewIssue("nolint", config.formatTemplate)
|
||||
issue.Path = path
|
||||
issue.Line = ignore.start
|
||||
issue.Col = ignore.col
|
||||
issue.Message = "nolint directive did not match any issue"
|
||||
out = append(out, issue)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
155
tools/vendor/github.com/alecthomas/gometalinter/execute.go
generated
vendored
155
tools/vendor/github.com/alecthomas/gometalinter/execute.go
generated
vendored
@@ -8,14 +8,13 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/shlex"
|
||||
"gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
type Vars map[string]string
|
||||
@@ -41,34 +40,8 @@ func (v Vars) Replace(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
// Severity of linter message.
|
||||
type Severity string
|
||||
|
||||
// Linter message severity levels.
|
||||
const ( // nolint: deadcode
|
||||
Error Severity = "error"
|
||||
Warning Severity = "warning"
|
||||
)
|
||||
|
||||
type Issue struct {
|
||||
Linter string `json:"linter"`
|
||||
Severity Severity `json:"severity"`
|
||||
Path string `json:"path"`
|
||||
Line int `json:"line"`
|
||||
Col int `json:"col"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (i *Issue) String() string {
|
||||
buf := new(bytes.Buffer)
|
||||
err := formatTemplate.Execute(buf, i)
|
||||
kingpin.FatalIfError(err, "Invalid output format")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type linterState struct {
|
||||
*Linter
|
||||
paths []string
|
||||
issues chan *Issue
|
||||
vars Vars
|
||||
exclude *regexp.Regexp
|
||||
@@ -76,26 +49,34 @@ type linterState struct {
|
||||
deadline <-chan time.Time
|
||||
}
|
||||
|
||||
func (l *linterState) Partitions() ([][]string, error) {
|
||||
command := l.vars.Replace(l.Command)
|
||||
cmdArgs, err := parseCommand(command)
|
||||
func (l *linterState) Partitions(paths []string) ([][]string, error) {
|
||||
cmdArgs, err := parseCommand(l.command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts, err := l.Linter.PartitionStrategy(cmdArgs, l.paths)
|
||||
parts, err := l.Linter.PartitionStrategy(cmdArgs, paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
func (l *linterState) command() string {
|
||||
return l.vars.Replace(l.Command)
|
||||
}
|
||||
|
||||
func runLinters(linters map[string]*Linter, paths []string, concurrency int, exclude, include *regexp.Regexp) (chan *Issue, chan error) {
|
||||
errch := make(chan error, len(linters))
|
||||
concurrencych := make(chan bool, concurrency)
|
||||
incomingIssues := make(chan *Issue, 1000000)
|
||||
processedIssues := filterIssuesViaDirectives(
|
||||
newDirectiveParser(),
|
||||
maybeSortIssues(maybeAggregateIssues(incomingIssues)))
|
||||
|
||||
directiveParser := newDirectiveParser()
|
||||
if config.WarnUnmatchedDirective {
|
||||
directiveParser.LoadFiles(paths)
|
||||
}
|
||||
|
||||
processedIssues := maybeSortIssues(filterIssuesViaDirectives(
|
||||
directiveParser, maybeAggregateIssues(incomingIssues)))
|
||||
|
||||
vars := Vars{
|
||||
"duplthreshold": fmt.Sprintf("%d", config.DuplThreshold),
|
||||
@@ -105,43 +86,46 @@ func runLinters(linters map[string]*Linter, paths []string, concurrency int, exc
|
||||
"min_occurrences": fmt.Sprintf("%d", config.MinOccurrences),
|
||||
"min_const_length": fmt.Sprintf("%d", config.MinConstLength),
|
||||
"tests": "",
|
||||
"not_tests": "true",
|
||||
}
|
||||
if config.Test {
|
||||
vars["tests"] = "-t"
|
||||
vars["tests"] = "true"
|
||||
vars["not_tests"] = ""
|
||||
}
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
id := 1
|
||||
for _, linter := range linters {
|
||||
deadline := time.After(config.Deadline.Duration())
|
||||
state := &linterState{
|
||||
Linter: linter,
|
||||
issues: incomingIssues,
|
||||
paths: paths,
|
||||
vars: vars,
|
||||
exclude: exclude,
|
||||
include: include,
|
||||
deadline: deadline,
|
||||
}
|
||||
|
||||
partitions, err := state.Partitions()
|
||||
partitions, err := state.Partitions(paths)
|
||||
if err != nil {
|
||||
errch <- err
|
||||
continue
|
||||
}
|
||||
for _, args := range partitions {
|
||||
wg.Add(1)
|
||||
concurrencych <- true
|
||||
// Call the goroutine with a copy of the args array so that the
|
||||
// contents of the array are not modified by the next iteration of
|
||||
// the above for loop
|
||||
go func(args []string) {
|
||||
concurrencych <- true
|
||||
err := executeLinter(state, args)
|
||||
go func(id int, args []string) {
|
||||
err := executeLinter(id, state, args)
|
||||
if err != nil {
|
||||
errch <- err
|
||||
}
|
||||
<-concurrencych
|
||||
wg.Done()
|
||||
}(append(args))
|
||||
}(id, args)
|
||||
id++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,13 +137,14 @@ func runLinters(linters map[string]*Linter, paths []string, concurrency int, exc
|
||||
return processedIssues, errch
|
||||
}
|
||||
|
||||
func executeLinter(state *linterState, args []string) error {
|
||||
func executeLinter(id int, state *linterState, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("missing linter command")
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
debug("executing %s", strings.Join(args, " "))
|
||||
dbg := namespacedDebug(fmt.Sprintf("[%s.%d]: ", state.Name, id))
|
||||
dbg("executing %s", strings.Join(args, " "))
|
||||
buf := bytes.NewBuffer(nil)
|
||||
command := args[0]
|
||||
cmd := exec.Command(command, args[1:]...) // nolint: gas
|
||||
@@ -191,12 +176,12 @@ func executeLinter(state *linterState, args []string) error {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
debug("warning: %s returned %s: %s", command, err, buf.String())
|
||||
dbg("warning: %s returned %s: %s", command, err, buf.String())
|
||||
}
|
||||
|
||||
processOutput(state, buf.Bytes())
|
||||
processOutput(dbg, state, buf.Bytes())
|
||||
elapsed := time.Since(start)
|
||||
debug("%s linter took %s", state.Name, elapsed)
|
||||
dbg("%s linter took %s", state.Name, elapsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -216,10 +201,10 @@ func parseCommand(command string) ([]string, error) {
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func processOutput(state *linterState, out []byte) {
|
||||
func processOutput(dbg debugFunction, state *linterState, out []byte) {
|
||||
re := state.regex
|
||||
all := re.FindAllSubmatchIndex(out, -1)
|
||||
debug("%s hits %d: %s", state.Name, len(all), state.Pattern)
|
||||
dbg("%s hits %d: %s", state.Name, len(all), state.Pattern)
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
@@ -239,7 +224,9 @@ func processOutput(state *linterState, out []byte) {
|
||||
group = append(group, fragment)
|
||||
}
|
||||
|
||||
issue := &Issue{Line: 1, Linter: state.Linter.Name}
|
||||
issue, err := NewIssue(state.Linter.Name, config.formatTemplate)
|
||||
kingpin.FatalIfError(err, "Invalid output format")
|
||||
|
||||
for i, name := range re.SubexpNames() {
|
||||
if group[i] == nil {
|
||||
continue
|
||||
@@ -275,8 +262,6 @@ func processOutput(state *linterState, out []byte) {
|
||||
}
|
||||
if sev, ok := config.Severity[state.Name]; ok {
|
||||
issue.Severity = Severity(sev)
|
||||
} else {
|
||||
issue.Severity = Warning
|
||||
}
|
||||
if state.exclude != nil && state.exclude.MatchString(issue.String()) {
|
||||
continue
|
||||
@@ -319,66 +304,16 @@ func resolvePath(path string) string {
|
||||
return path
|
||||
}
|
||||
|
||||
type sortedIssues struct {
|
||||
issues []*Issue
|
||||
order []string
|
||||
}
|
||||
|
||||
func (s *sortedIssues) Len() int { return len(s.issues) }
|
||||
func (s *sortedIssues) Swap(i, j int) { s.issues[i], s.issues[j] = s.issues[j], s.issues[i] }
|
||||
|
||||
// nolint: gocyclo
|
||||
func (s *sortedIssues) Less(i, j int) bool {
|
||||
l, r := s.issues[i], s.issues[j]
|
||||
for _, key := range s.order {
|
||||
switch key {
|
||||
case "path":
|
||||
if l.Path > r.Path {
|
||||
return false
|
||||
}
|
||||
case "line":
|
||||
if l.Line > r.Line {
|
||||
return false
|
||||
}
|
||||
case "column":
|
||||
if l.Col > r.Col {
|
||||
return false
|
||||
}
|
||||
case "severity":
|
||||
if l.Severity > r.Severity {
|
||||
return false
|
||||
}
|
||||
case "message":
|
||||
if l.Message > r.Message {
|
||||
return false
|
||||
}
|
||||
case "linter":
|
||||
if l.Linter > r.Linter {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func maybeSortIssues(issues chan *Issue) chan *Issue {
|
||||
if reflect.DeepEqual([]string{"none"}, config.Sort) {
|
||||
return issues
|
||||
}
|
||||
out := make(chan *Issue, 1000000)
|
||||
sorted := &sortedIssues{
|
||||
issues: []*Issue{},
|
||||
order: config.Sort,
|
||||
}
|
||||
go func() {
|
||||
for issue := range issues {
|
||||
sorted.issues = append(sorted.issues, issue)
|
||||
}
|
||||
sort.Sort(sorted)
|
||||
for _, issue := range sorted.issues {
|
||||
out <- issue
|
||||
}
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
return SortIssueChan(issues, config.Sort)
|
||||
}
|
||||
|
||||
func maybeAggregateIssues(issues chan *Issue) chan *Issue {
|
||||
if !config.Aggregate {
|
||||
return issues
|
||||
}
|
||||
return AggregateIssueChan(issues)
|
||||
}
|
||||
|
||||
114
tools/vendor/github.com/alecthomas/gometalinter/issue.go
generated
vendored
Normal file
114
tools/vendor/github.com/alecthomas/gometalinter/issue.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// DefaultIssueFormat used to print an issue
|
||||
const DefaultIssueFormat = "{{.Path}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})"
|
||||
|
||||
// Severity of linter message
|
||||
type Severity string
|
||||
|
||||
// Linter message severity levels.
|
||||
const (
|
||||
Error Severity = "error"
|
||||
Warning Severity = "warning"
|
||||
)
|
||||
|
||||
type Issue struct {
|
||||
Linter string `json:"linter"`
|
||||
Severity Severity `json:"severity"`
|
||||
Path string `json:"path"`
|
||||
Line int `json:"line"`
|
||||
Col int `json:"col"`
|
||||
Message string `json:"message"`
|
||||
formatTmpl *template.Template
|
||||
}
|
||||
|
||||
// NewIssue returns a new issue. Returns an error if formatTmpl is not a valid
|
||||
// template for an Issue.
|
||||
func NewIssue(linter string, formatTmpl *template.Template) (*Issue, error) {
|
||||
issue := &Issue{
|
||||
Line: 1,
|
||||
Severity: Warning,
|
||||
Linter: linter,
|
||||
formatTmpl: formatTmpl,
|
||||
}
|
||||
err := formatTmpl.Execute(ioutil.Discard, issue)
|
||||
return issue, err
|
||||
}
|
||||
|
||||
func (i *Issue) String() string {
|
||||
if i.formatTmpl == nil {
|
||||
col := ""
|
||||
if i.Col != 0 {
|
||||
col = fmt.Sprintf("%d", i.Col)
|
||||
}
|
||||
return fmt.Sprintf("%s:%d:%s:%s: %s (%s)", strings.TrimSpace(i.Path), i.Line, col, i.Severity, strings.TrimSpace(i.Message), i.Linter)
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
_ = i.formatTmpl.Execute(buf, i)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type sortedIssues struct {
|
||||
issues []*Issue
|
||||
order []string
|
||||
}
|
||||
|
||||
func (s *sortedIssues) Len() int { return len(s.issues) }
|
||||
func (s *sortedIssues) Swap(i, j int) { s.issues[i], s.issues[j] = s.issues[j], s.issues[i] }
|
||||
|
||||
func (s *sortedIssues) Less(i, j int) bool {
|
||||
l, r := s.issues[i], s.issues[j]
|
||||
return CompareIssue(*l, *r, s.order)
|
||||
}
|
||||
|
||||
// CompareIssue two Issues and return true if left should sort before right
|
||||
// nolint: gocyclo
|
||||
func CompareIssue(l, r Issue, order []string) bool {
|
||||
for _, key := range order {
|
||||
switch {
|
||||
case key == "path" && l.Path != r.Path:
|
||||
return l.Path < r.Path
|
||||
case key == "line" && l.Line != r.Line:
|
||||
return l.Line < r.Line
|
||||
case key == "column" && l.Col != r.Col:
|
||||
return l.Col < r.Col
|
||||
case key == "severity" && l.Severity != r.Severity:
|
||||
return l.Severity < r.Severity
|
||||
case key == "message" && l.Message != r.Message:
|
||||
return l.Message < r.Message
|
||||
case key == "linter" && l.Linter != r.Linter:
|
||||
return l.Linter < r.Linter
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// SortIssueChan reads issues from one channel, sorts them, and returns them to another
|
||||
// channel
|
||||
func SortIssueChan(issues chan *Issue, order []string) chan *Issue {
|
||||
out := make(chan *Issue, 1000000)
|
||||
sorted := &sortedIssues{
|
||||
issues: []*Issue{},
|
||||
order: order,
|
||||
}
|
||||
go func() {
|
||||
for issue := range issues {
|
||||
sorted.issues = append(sorted.issues, issue)
|
||||
}
|
||||
sort.Sort(sorted)
|
||||
for _, issue := range sorted.issues {
|
||||
out <- issue
|
||||
}
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
}
|
||||
181
tools/vendor/github.com/alecthomas/gometalinter/linters.go
generated
vendored
181
tools/vendor/github.com/alecthomas/gometalinter/linters.go
generated
vendored
@@ -8,11 +8,10 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
type LinterConfig struct {
|
||||
Name string
|
||||
Command string
|
||||
Pattern string
|
||||
InstallFrom string
|
||||
@@ -23,11 +22,12 @@ type LinterConfig struct {
|
||||
|
||||
type Linter struct {
|
||||
LinterConfig
|
||||
Name string
|
||||
regex *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewLinter returns a new linter from a config
|
||||
func NewLinter(config LinterConfig) (*Linter, error) {
|
||||
func NewLinter(name string, config LinterConfig) (*Linter, error) {
|
||||
if p, ok := predefinedPatterns[config.Pattern]; ok {
|
||||
config.Pattern = p
|
||||
}
|
||||
@@ -35,8 +35,12 @@ func NewLinter(config LinterConfig) (*Linter, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.PartitionStrategy == nil {
|
||||
config.PartitionStrategy = partitionPathsAsDirectories
|
||||
}
|
||||
return &Linter{
|
||||
LinterConfig: config,
|
||||
Name: name,
|
||||
regex: regex,
|
||||
}, nil
|
||||
}
|
||||
@@ -50,26 +54,41 @@ var predefinedPatterns = map[string]string{
|
||||
"PATH:LINE:MESSAGE": `^(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*)$`,
|
||||
}
|
||||
|
||||
func getLinterByName(name string, customSpec string) *Linter {
|
||||
if customSpec != "" {
|
||||
return parseLinterSpec(name, customSpec)
|
||||
func getLinterByName(name string, overrideConf LinterConfig) *Linter {
|
||||
conf := defaultLinters[name]
|
||||
if val := overrideConf.Command; val != "" {
|
||||
conf.Command = val
|
||||
}
|
||||
linter, _ := NewLinter(defaultLinters[name])
|
||||
if val := overrideConf.Pattern; val != "" {
|
||||
conf.Pattern = val
|
||||
}
|
||||
if val := overrideConf.InstallFrom; val != "" {
|
||||
conf.InstallFrom = val
|
||||
}
|
||||
if overrideConf.IsFast {
|
||||
conf.IsFast = true
|
||||
}
|
||||
if val := overrideConf.PartitionStrategy; val != nil {
|
||||
conf.PartitionStrategy = val
|
||||
}
|
||||
|
||||
linter, _ := NewLinter(name, conf)
|
||||
return linter
|
||||
}
|
||||
|
||||
func parseLinterSpec(name string, spec string) *Linter {
|
||||
func parseLinterConfigSpec(name string, spec string) (LinterConfig, error) {
|
||||
parts := strings.SplitN(spec, ":", 2)
|
||||
if len(parts) < 2 {
|
||||
kingpin.Fatalf("invalid linter: %q", spec)
|
||||
return LinterConfig{}, fmt.Errorf("linter spec needs at least two components")
|
||||
}
|
||||
|
||||
config := defaultLinters[name]
|
||||
config.Command, config.Pattern = parts[0], parts[1]
|
||||
if predefined, ok := predefinedPatterns[config.Pattern]; ok {
|
||||
config.Pattern = predefined
|
||||
}
|
||||
|
||||
linter, err := NewLinter(config)
|
||||
kingpin.FatalIfError(err, "invalid linter %q", name)
|
||||
return linter
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func makeInstallCommand(linters ...string) []string {
|
||||
@@ -148,9 +167,9 @@ func installLinters() {
|
||||
|
||||
func getDefaultLinters() []*Linter {
|
||||
out := []*Linter{}
|
||||
for _, config := range defaultLinters {
|
||||
linter, err := NewLinter(config)
|
||||
kingpin.FatalIfError(err, "invalid linter %q", config.Name)
|
||||
for name, config := range defaultLinters {
|
||||
linter, err := NewLinter(name, config)
|
||||
kingpin.FatalIfError(err, "invalid linter %q", name)
|
||||
out = append(out, linter)
|
||||
}
|
||||
return out
|
||||
@@ -166,226 +185,228 @@ func defaultEnabled() []string {
|
||||
return enabled
|
||||
}
|
||||
|
||||
func validateLinters(linters map[string]*Linter, config *Config) error {
|
||||
var unknownLinters []string
|
||||
for name := range linters {
|
||||
if _, isDefault := defaultLinters[name]; !isDefault {
|
||||
if _, isCustom := config.Linters[name]; !isCustom {
|
||||
unknownLinters = append(unknownLinters, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(unknownLinters) > 0 {
|
||||
return fmt.Errorf("unknown linters: %s", strings.Join(unknownLinters, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const vetPattern = `^(?:vet:.*?\.go:\s+(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*))|(?:(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*))$`
|
||||
|
||||
var defaultLinters = map[string]LinterConfig{
|
||||
"aligncheck": {
|
||||
Name: "aligncheck",
|
||||
Command: "aligncheck",
|
||||
"maligned": {
|
||||
Command: "maligned",
|
||||
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
|
||||
InstallFrom: "github.com/opennota/check/cmd/aligncheck",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
InstallFrom: "github.com/mdempsky/maligned",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"deadcode": {
|
||||
Name: "deadcode",
|
||||
Command: "deadcode",
|
||||
Pattern: `^deadcode: (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/tsenart/deadcode",
|
||||
PartitionStrategy: partitionToMaxArgSize,
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"dupl": {
|
||||
Name: "dupl",
|
||||
Command: `dupl -plumbing -threshold {duplthreshold}`,
|
||||
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/mibk/dupl",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithFileGlobs,
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"errcheck": {
|
||||
Name: "errcheck",
|
||||
Command: `errcheck -abspath`,
|
||||
Command: `errcheck -abspath {not_tests=-ignoretests}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/kisielk/errcheck",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"gas": {
|
||||
Name: "gas",
|
||||
Command: `gas -fmt=csv`,
|
||||
Pattern: `^(?P<path>.*?\.go),(?P<line>\d+),(?P<message>[^,]+,[^,]+,[^,]+)`,
|
||||
InstallFrom: "github.com/GoASTScanner/gas",
|
||||
PartitionStrategy: partitionToMaxArgSize,
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"goconst": {
|
||||
Name: "goconst",
|
||||
Command: `goconst -min-occurrences {min_occurrences} -min-length {min_const_length}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/jgautheron/goconst/cmd/goconst",
|
||||
PartitionStrategy: partitionToMaxArgSize,
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gocyclo": {
|
||||
Name: "gocyclo",
|
||||
Command: `gocyclo -over {mincyclo}`,
|
||||
Pattern: `^(?P<cyclo>\d+)\s+\S+\s(?P<function>\S+)\s+(?P<path>.*?\.go):(?P<line>\d+):(\d+)$`,
|
||||
InstallFrom: "github.com/alecthomas/gocyclo",
|
||||
PartitionStrategy: partitionToMaxArgSize,
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gofmt": {
|
||||
Name: "gofmt",
|
||||
Command: `gofmt -l -s`,
|
||||
Pattern: `^(?P<path>.*?\.go)$`,
|
||||
PartitionStrategy: partitionToMaxArgSizeWithFileGlobs,
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"goimports": {
|
||||
Name: "goimports",
|
||||
Command: `goimports -l`,
|
||||
Pattern: `^(?P<path>.*?\.go)$`,
|
||||
InstallFrom: "golang.org/x/tools/cmd/goimports",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithFileGlobs,
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"golint": {
|
||||
Name: "golint",
|
||||
Command: `golint -min_confidence {min_confidence}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/golang/lint/golint",
|
||||
PartitionStrategy: partitionToMaxArgSize,
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gosimple": {
|
||||
Name: "gosimple",
|
||||
Command: `gosimple`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/gosimple",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"gotype": {
|
||||
Name: "gotype",
|
||||
Command: `gotype -e {tests=-t}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "golang.org/x/tools/cmd/gotype",
|
||||
PartitionStrategy: partitionToMaxArgSize,
|
||||
PartitionStrategy: partitionPathsByDirectory,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"gotypex": {
|
||||
Command: `gotype -e -x`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "golang.org/x/tools/cmd/gotype",
|
||||
PartitionStrategy: partitionPathsByDirectory,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"ineffassign": {
|
||||
Name: "ineffassign",
|
||||
Command: `ineffassign -n`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/gordonklaus/ineffassign",
|
||||
PartitionStrategy: partitionToMaxArgSize,
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"interfacer": {
|
||||
Name: "interfacer",
|
||||
Command: `interfacer`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/mvdan/interfacer/cmd/interfacer",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
InstallFrom: "mvdan.cc/interfacer",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"lll": {
|
||||
Name: "lll",
|
||||
Command: `lll -g -l {maxlinelength}`,
|
||||
Pattern: `PATH:LINE:MESSAGE`,
|
||||
InstallFrom: "github.com/walle/lll/cmd/lll",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithFileGlobs,
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"megacheck": {
|
||||
Name: "megacheck",
|
||||
Command: `megacheck`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/megacheck",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"misspell": {
|
||||
Name: "misspell",
|
||||
Command: `misspell -j 1`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/client9/misspell/cmd/misspell",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithFileGlobs,
|
||||
PartitionStrategy: partitionPathsAsFiles,
|
||||
IsFast: true,
|
||||
},
|
||||
"nakedret": {
|
||||
Command: `nakedret`,
|
||||
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+)\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/alexkohler/nakedret",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
},
|
||||
"safesql": {
|
||||
Name: "safesql",
|
||||
Command: `safesql`,
|
||||
Pattern: `^- (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+)$`,
|
||||
InstallFrom: "github.com/stripe/safesql",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"staticcheck": {
|
||||
Name: "staticcheck",
|
||||
Command: `staticcheck`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/staticcheck",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"structcheck": {
|
||||
Name: "structcheck",
|
||||
Command: `structcheck {tests=-t}`,
|
||||
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
|
||||
InstallFrom: "github.com/opennota/check/cmd/structcheck",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"test": {
|
||||
Name: "test",
|
||||
Command: `go test`,
|
||||
Pattern: `^--- FAIL: .*$\s+(?P<path>.*?\.go):(?P<line>\d+): (?P<message>.*)$`,
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"testify": {
|
||||
Name: "testify",
|
||||
Command: `go test`,
|
||||
Pattern: `Location:\s+(?P<path>.*?\.go):(?P<line>\d+)$\s+Error:\s+(?P<message>[^\n]+)`,
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"unconvert": {
|
||||
Name: "unconvert",
|
||||
Command: `unconvert`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/mdempsky/unconvert",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"unparam": {
|
||||
Name: "unparam",
|
||||
Command: `unparam`,
|
||||
Command: `unparam {not_tests=-tests=false}`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "github.com/mvdan/unparam",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
InstallFrom: "mvdan.cc/unparam",
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"unused": {
|
||||
Name: "unused",
|
||||
Command: `unused`,
|
||||
Pattern: `PATH:LINE:COL:MESSAGE`,
|
||||
InstallFrom: "honnef.co/go/tools/cmd/unused",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
},
|
||||
"varcheck": {
|
||||
Name: "varcheck",
|
||||
Command: `varcheck`,
|
||||
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
|
||||
InstallFrom: "github.com/opennota/check/cmd/varcheck",
|
||||
PartitionStrategy: partitionToMaxArgSizeWithPackagePaths,
|
||||
PartitionStrategy: partitionPathsAsPackages,
|
||||
defaultEnabled: true,
|
||||
},
|
||||
"vet": {
|
||||
Name: "vet",
|
||||
Command: `go tool vet`,
|
||||
Command: `govet --no-recurse`,
|
||||
Pattern: vetPattern,
|
||||
PartitionStrategy: partitionToPackageFileGlobs,
|
||||
InstallFrom: "github.com/dnephin/govet",
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
"vetshadow": {
|
||||
Name: "vetshadow",
|
||||
Command: `go tool vet --shadow`,
|
||||
Command: `govet --no-recurse --shadow`,
|
||||
Pattern: vetPattern,
|
||||
PartitionStrategy: partitionToPackageFileGlobs,
|
||||
PartitionStrategy: partitionPathsAsDirectories,
|
||||
defaultEnabled: true,
|
||||
IsFast: true,
|
||||
},
|
||||
|
||||
47
tools/vendor/github.com/alecthomas/gometalinter/main.go
generated
vendored
47
tools/vendor/github.com/alecthomas/gometalinter/main.go
generated
vendored
@@ -14,7 +14,7 @@ import (
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -26,10 +26,10 @@ var (
|
||||
)
|
||||
|
||||
func setupFlags(app *kingpin.Application) {
|
||||
app.Flag("config", "Load JSON configuration from file.").Action(loadConfig).String()
|
||||
app.Flag("config", "Load JSON configuration from file.").Envar("GOMETALINTER_CONFIG").Action(loadConfig).String()
|
||||
app.Flag("disable", "Disable previously enabled linters.").PlaceHolder("LINTER").Short('D').Action(disableAction).Strings()
|
||||
app.Flag("enable", "Enable previously disabled linters.").PlaceHolder("LINTER").Short('E').Action(enableAction).Strings()
|
||||
app.Flag("linter", "Define a linter.").PlaceHolder("NAME:COMMAND:PATTERN").StringMapVar(&config.Linters)
|
||||
app.Flag("linter", "Define a linter.").PlaceHolder("NAME:COMMAND:PATTERN").Action(cliLinterOverrides).StringMap()
|
||||
app.Flag("message-overrides", "Override message from linter. {message} will be expanded to the original message.").PlaceHolder("LINTER:MESSAGE").StringMapVar(&config.MessageOverride)
|
||||
app.Flag("severity", "Map of linter severities.").PlaceHolder("LINTER:SEVERITY").StringMapVar(&config.Severity)
|
||||
app.Flag("disable-all", "Disable all linters.").Action(disableAllAction).Bool()
|
||||
@@ -51,19 +51,36 @@ func setupFlags(app *kingpin.Application) {
|
||||
app.Flag("line-length", "Report lines longer than N (using lll).").PlaceHolder("80").IntVar(&config.LineLength)
|
||||
app.Flag("min-confidence", "Minimum confidence interval to pass to golint.").PlaceHolder(".80").FloatVar(&config.MinConfidence)
|
||||
app.Flag("min-occurrences", "Minimum occurrences to pass to goconst.").PlaceHolder("3").IntVar(&config.MinOccurrences)
|
||||
app.Flag("min-const-length", "Minimumum constant length.").PlaceHolder("3").IntVar(&config.MinConstLength)
|
||||
app.Flag("min-const-length", "Minimum constant length.").PlaceHolder("3").IntVar(&config.MinConstLength)
|
||||
app.Flag("dupl-threshold", "Minimum token sequence as a clone for dupl.").PlaceHolder("50").IntVar(&config.DuplThreshold)
|
||||
app.Flag("sort", fmt.Sprintf("Sort output by any of %s.", strings.Join(sortKeys, ", "))).PlaceHolder("none").EnumsVar(&config.Sort, sortKeys...)
|
||||
app.Flag("tests", "Include test files for linters that support this option").Short('t').BoolVar(&config.Test)
|
||||
app.Flag("tests", "Include test files for linters that support this option.").Short('t').BoolVar(&config.Test)
|
||||
app.Flag("deadline", "Cancel linters if they have not completed within this duration.").PlaceHolder("30s").DurationVar((*time.Duration)(&config.Deadline))
|
||||
app.Flag("errors", "Only show errors.").BoolVar(&config.Errors)
|
||||
app.Flag("json", "Generate structured JSON rather than standard line-based output.").BoolVar(&config.JSON)
|
||||
app.Flag("checkstyle", "Generate checkstyle XML rather than standard line-based output.").BoolVar(&config.Checkstyle)
|
||||
app.Flag("enable-gc", "Enable GC for linters (useful on large repositories).").BoolVar(&config.EnableGC)
|
||||
app.Flag("aggregate", "Aggregate issues reported by several linters.").BoolVar(&config.Aggregate)
|
||||
app.Flag("warn-unmatched-nolint", "Warn if a nolint directive is not matched with an issue.").BoolVar(&config.WarnUnmatchedDirective)
|
||||
app.GetFlag("help").Short('h')
|
||||
}
|
||||
|
||||
func cliLinterOverrides(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
// expected input structure - <name>:<command-spec>
|
||||
parts := strings.SplitN(*element.Value, ":", 2)
|
||||
if len(parts) < 2 {
|
||||
return fmt.Errorf("incorrectly formatted input: %s", *element.Value)
|
||||
}
|
||||
name := parts[0]
|
||||
spec := parts[1]
|
||||
conf, err := parseLinterConfigSpec(name, spec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("incorrectly formatted input: %s", *element.Value)
|
||||
}
|
||||
config.Linters[name] = StringOrLinterConfig(conf)
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadConfig(app *kingpin.Application, element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
|
||||
r, err := os.Open(*element.Value)
|
||||
if err != nil {
|
||||
@@ -114,12 +131,20 @@ func enableAllAction(app *kingpin.Application, element *kingpin.ParseElement, ct
|
||||
return nil
|
||||
}
|
||||
|
||||
type debugFunction func(format string, args ...interface{})
|
||||
|
||||
func debug(format string, args ...interface{}) {
|
||||
if config.Debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG: "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
func namespacedDebug(prefix string) debugFunction {
|
||||
return func(format string, args ...interface{}) {
|
||||
debug(prefix+format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func warning(format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, "WARNING: "+format+"\n", args...)
|
||||
}
|
||||
@@ -131,8 +156,8 @@ func formatLinters() string {
|
||||
if install == "()" {
|
||||
install = ""
|
||||
}
|
||||
fmt.Fprintf(w, " %s %s\n %s\n %s\n",
|
||||
linter.Name, install, linter.Command, linter.Pattern)
|
||||
fmt.Fprintf(w, " %s: %s\n\tcommand: %s\n\tregex: %s\n\tfast: %t\n\tdefault enabled: %t\n\n",
|
||||
linter.Name, install, linter.Command, linter.Pattern, linter.IsFast, linter.defaultEnabled)
|
||||
}
|
||||
return w.String()
|
||||
}
|
||||
@@ -176,6 +201,9 @@ Severity override map (default is "warning"):
|
||||
paths := resolvePaths(*pathsArg, config.Skip)
|
||||
|
||||
linters := lintersFromConfig(config)
|
||||
err := validateLinters(linters, config)
|
||||
kingpin.FatalIfError(err, "")
|
||||
|
||||
issues, errch := runLinters(linters, paths, config.Concurrency, exclude, include)
|
||||
status := 0
|
||||
if config.JSON {
|
||||
@@ -198,7 +226,7 @@ Severity override map (default is "warning"):
|
||||
func processConfig(config *Config) (include *regexp.Regexp, exclude *regexp.Regexp) {
|
||||
tmpl, err := template.New("output").Parse(config.Format)
|
||||
kingpin.FatalIfError(err, "invalid format %q", config.Format)
|
||||
formatTemplate = tmpl
|
||||
config.formatTemplate = tmpl
|
||||
|
||||
// Linters are by their very nature, short lived, so disable GC.
|
||||
// Reduced (user) linting time on kingpin from 0.97s to 0.64s.
|
||||
@@ -340,8 +368,7 @@ func lintersFromConfig(config *Config) map[string]*Linter {
|
||||
out := map[string]*Linter{}
|
||||
config.Enable = replaceWithMegacheck(config.Enable, config.EnableAll)
|
||||
for _, name := range config.Enable {
|
||||
linter := getLinterByName(name, config.Linters[name])
|
||||
|
||||
linter := getLinterByName(name, LinterConfig(config.Linters[name]))
|
||||
if config.Fast && !linter.IsFast {
|
||||
continue
|
||||
}
|
||||
|
||||
44
tools/vendor/github.com/alecthomas/gometalinter/partition.go
generated
vendored
44
tools/vendor/github.com/alecthomas/gometalinter/partition.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
)
|
||||
@@ -10,6 +11,29 @@ const MaxCommandBytes = 32000
|
||||
|
||||
type partitionStrategy func([]string, []string) ([][]string, error)
|
||||
|
||||
func (ps *partitionStrategy) UnmarshalJSON(raw []byte) error {
|
||||
var strategyName string
|
||||
if err := json.Unmarshal(raw, &strategyName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch strategyName {
|
||||
case "directories":
|
||||
*ps = partitionPathsAsDirectories
|
||||
case "files":
|
||||
*ps = partitionPathsAsFiles
|
||||
case "packages":
|
||||
*ps = partitionPathsAsPackages
|
||||
case "files-by-package":
|
||||
*ps = partitionPathsAsFilesGroupedByPackage
|
||||
case "single-directory":
|
||||
*ps = partitionPathsByDirectory
|
||||
default:
|
||||
return fmt.Errorf("unknown parition strategy %s", strategyName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pathsToFileGlobs(paths []string) ([]string, error) {
|
||||
filePaths := []string{}
|
||||
for _, dir := range paths {
|
||||
@@ -22,7 +46,7 @@ func pathsToFileGlobs(paths []string) ([]string, error) {
|
||||
return filePaths, nil
|
||||
}
|
||||
|
||||
func partitionToMaxArgSize(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
func partitionPathsAsDirectories(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
return partitionToMaxSize(cmdArgs, paths, MaxCommandBytes), nil
|
||||
}
|
||||
|
||||
@@ -72,15 +96,15 @@ func (p *sizePartitioner) end() [][]string {
|
||||
return p.parts
|
||||
}
|
||||
|
||||
func partitionToMaxArgSizeWithFileGlobs(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
func partitionPathsAsFiles(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
filePaths, err := pathsToFileGlobs(paths)
|
||||
if err != nil || len(filePaths) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return partitionToMaxArgSize(cmdArgs, filePaths)
|
||||
return partitionPathsAsDirectories(cmdArgs, filePaths)
|
||||
}
|
||||
|
||||
func partitionToPackageFileGlobs(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
func partitionPathsAsFilesGroupedByPackage(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
parts := [][]string{}
|
||||
for _, path := range paths {
|
||||
filePaths, err := pathsToFileGlobs([]string{path})
|
||||
@@ -95,12 +119,12 @@ func partitionToPackageFileGlobs(cmdArgs []string, paths []string) ([][]string,
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
func partitionToMaxArgSizeWithPackagePaths(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
func partitionPathsAsPackages(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
packagePaths, err := pathsToPackagePaths(paths)
|
||||
if err != nil || len(packagePaths) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return partitionToMaxArgSize(cmdArgs, packagePaths)
|
||||
return partitionPathsAsDirectories(cmdArgs, packagePaths)
|
||||
}
|
||||
|
||||
func pathsToPackagePaths(paths []string) ([]string, error) {
|
||||
@@ -129,3 +153,11 @@ func packageNameFromPath(path string) (string, error) {
|
||||
}
|
||||
return "", fmt.Errorf("%s not in GOPATH", path)
|
||||
}
|
||||
|
||||
func partitionPathsByDirectory(cmdArgs []string, paths []string) ([][]string, error) {
|
||||
parts := [][]string{}
|
||||
for _, path := range paths {
|
||||
parts = append(parts, append(cmdArgs, path))
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user