1
0
mirror of https://github.com/prometheus-community/postgres_exporter.git synced 2025-08-08 04:42:07 +03:00
Files
Will Rouesnel 989489096e Refactor repository layout and convert build system to Mage.
This commit implements a massive refactor of the repository, and
moves the build system over to use Mage (magefile.org) which should
allow seamless building across multiple platforms.
2018-03-06 07:29:35 +10:00

414 lines
12 KiB
Go

package main
import (
"fmt"
"os"
"os/exec"
"regexp"
"sort"
"strings"
kingpin "gopkg.in/alecthomas/kingpin.v3-unstable"
)
type LinterConfig struct {
Command string
Pattern string
InstallFrom string
PartitionStrategy partitionStrategy
IsFast bool
defaultEnabled bool
}
type Linter struct {
LinterConfig
Name string
regex *regexp.Regexp
}
// NewLinter returns a new linter from a config
func NewLinter(name string, config LinterConfig) (*Linter, error) {
if p, ok := predefinedPatterns[config.Pattern]; ok {
config.Pattern = p
}
regex, err := regexp.Compile("(?m:" + config.Pattern + ")")
if err != nil {
return nil, err
}
if config.PartitionStrategy == nil {
config.PartitionStrategy = partitionPathsAsDirectories
}
return &Linter{
LinterConfig: config,
Name: name,
regex: regex,
}, nil
}
func (l *Linter) String() string {
return l.Name
}
var predefinedPatterns = map[string]string{
"PATH:LINE:COL:MESSAGE": `^(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
"PATH:LINE:MESSAGE": `^(?P<path>.*?\.go):(?P<line>\d+):\s*(?P<message>.*)$`,
}
func getLinterByName(name string, overrideConf LinterConfig) *Linter {
conf := defaultLinters[name]
if val := overrideConf.Command; val != "" {
conf.Command = val
}
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 parseLinterConfigSpec(name string, spec string) (LinterConfig, error) {
parts := strings.SplitN(spec, ":", 2)
if len(parts) < 2 {
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
}
return config, nil
}
func makeInstallCommand(linters ...string) []string {
cmd := []string{"get"}
if config.VendoredLinters {
cmd = []string{"install"}
} else {
if config.Update {
cmd = append(cmd, "-u")
}
if config.Force {
cmd = append(cmd, "-f")
}
if config.DownloadOnly {
cmd = append(cmd, "-d")
}
}
if config.Debug {
cmd = append(cmd, "-v")
}
cmd = append(cmd, linters...)
return cmd
}
func installLintersWithOneCommand(targets []string) error {
cmd := makeInstallCommand(targets...)
debug("go %s", strings.Join(cmd, " "))
c := exec.Command("go", cmd...) // nolint: gas
c.Stdout = os.Stdout
c.Stderr = os.Stderr
return c.Run()
}
func installLintersIndividually(targets []string) {
failed := []string{}
for _, target := range targets {
cmd := makeInstallCommand(target)
debug("go %s", strings.Join(cmd, " "))
c := exec.Command("go", cmd...) // nolint: gas
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if err := c.Run(); err != nil {
warning("failed to install %s: %s", target, err)
failed = append(failed, target)
}
}
if len(failed) > 0 {
kingpin.Fatalf("failed to install the following linters: %s", strings.Join(failed, ", "))
}
}
func installLinters() {
names := make([]string, 0, len(defaultLinters))
targets := make([]string, 0, len(defaultLinters))
for name, config := range defaultLinters {
if config.InstallFrom == "" {
continue
}
names = append(names, name)
targets = append(targets, config.InstallFrom)
}
sort.Strings(names)
namesStr := strings.Join(names, "\n ")
if config.DownloadOnly {
fmt.Printf("Downloading:\n %s\n", namesStr)
} else {
fmt.Printf("Installing:\n %s\n", namesStr)
}
err := installLintersWithOneCommand(targets)
if err == nil {
return
}
warning("failed to install one or more linters: %s (installing individually)", err)
installLintersIndividually(targets)
}
func getDefaultLinters() []*Linter {
out := []*Linter{}
for name, config := range defaultLinters {
linter, err := NewLinter(name, config)
kingpin.FatalIfError(err, "invalid linter %q", name)
out = append(out, linter)
}
return out
}
func defaultEnabled() []string {
enabled := []string{}
for name, config := range defaultLinters {
if config.defaultEnabled {
enabled = append(enabled, name)
}
}
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{
"maligned": {
Command: "maligned",
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
InstallFrom: "github.com/mdempsky/maligned",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"deadcode": {
Command: "deadcode",
Pattern: `^deadcode: (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
InstallFrom: "github.com/tsenart/deadcode",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
},
"dupl": {
Command: `dupl -plumbing -threshold {duplthreshold}`,
Pattern: `^(?P<path>.*?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
InstallFrom: "github.com/mibk/dupl",
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"errcheck": {
Command: `errcheck -abspath {not_tests=-ignoretests}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/kisielk/errcheck",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"gas": {
Command: `gas -fmt=csv`,
Pattern: `^(?P<path>.*?\.go),(?P<line>\d+),(?P<message>[^,]+,[^,]+,[^,]+)`,
InstallFrom: "github.com/GoASTScanner/gas",
PartitionStrategy: partitionPathsAsFiles,
defaultEnabled: true,
IsFast: true,
},
"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: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"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: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"gofmt": {
Command: `gofmt -l -s`,
Pattern: `^(?P<path>.*?\.go)$`,
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"goimports": {
Command: `goimports -l`,
Pattern: `^(?P<path>.*?\.go)$`,
InstallFrom: "golang.org/x/tools/cmd/goimports",
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"golint": {
Command: `golint -min_confidence {min_confidence}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/golang/lint/golint",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"gosimple": {
Command: `gosimple`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/gosimple",
PartitionStrategy: partitionPathsAsPackages,
},
"gotype": {
Command: `gotype -e {tests=-t}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "golang.org/x/tools/cmd/gotype",
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": {
Command: `ineffassign -n`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/gordonklaus/ineffassign",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"interfacer": {
Command: `interfacer`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "mvdan.cc/interfacer",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"lll": {
Command: `lll -g -l {maxlinelength}`,
Pattern: `PATH:LINE:MESSAGE`,
InstallFrom: "github.com/walle/lll/cmd/lll",
PartitionStrategy: partitionPathsAsFiles,
IsFast: true,
},
"megacheck": {
Command: `megacheck`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/megacheck",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"misspell": {
Command: `misspell -j 1 --locale "{misspelllocale}"`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/client9/misspell/cmd/misspell",
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": {
Command: `safesql`,
Pattern: `^- (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+)$`,
InstallFrom: "github.com/stripe/safesql",
PartitionStrategy: partitionPathsAsPackages,
},
"staticcheck": {
Command: `staticcheck`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/staticcheck",
PartitionStrategy: partitionPathsAsPackages,
},
"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: partitionPathsAsPackages,
defaultEnabled: true,
},
"test": {
Command: `go test`,
Pattern: `^--- FAIL: .*$\s+(?P<path>.*?\.go):(?P<line>\d+): (?P<message>.*)$`,
PartitionStrategy: partitionPathsAsPackages,
},
"testify": {
Command: `go test`,
Pattern: `Location:\s+(?P<path>.*?\.go):(?P<line>\d+)$\s+Error:\s+(?P<message>[^\n]+)`,
PartitionStrategy: partitionPathsAsPackages,
},
"unconvert": {
Command: `unconvert`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "github.com/mdempsky/unconvert",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"unparam": {
Command: `unparam {not_tests=-tests=false}`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "mvdan.cc/unparam",
PartitionStrategy: partitionPathsAsPackages,
},
"unused": {
Command: `unused`,
Pattern: `PATH:LINE:COL:MESSAGE`,
InstallFrom: "honnef.co/go/tools/cmd/unused",
PartitionStrategy: partitionPathsAsPackages,
},
"varcheck": {
Command: `varcheck`,
Pattern: `^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
InstallFrom: "github.com/opennota/check/cmd/varcheck",
PartitionStrategy: partitionPathsAsPackages,
defaultEnabled: true,
},
"vet": {
Command: `govet --no-recurse`,
Pattern: vetPattern,
InstallFrom: "github.com/dnephin/govet",
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
"vetshadow": {
Command: `govet --no-recurse --shadow`,
Pattern: vetPattern,
PartitionStrategy: partitionPathsAsDirectories,
defaultEnabled: true,
IsFast: true,
},
}