syncthing/meta/metalint_test.go

119 lines
2.6 KiB
Go
Raw Permalink Normal View History

// Copyright (C) 2017 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package meta
import (
"bytes"
"log"
"os/exec"
"strings"
"testing"
)
var (
// fast linters complete in a fraction of a second and might as well be
// run always as part of the build
fastLinters = []string{
"deadcode",
"golint",
"ineffassign",
"vet",
}
// slow linters take several seconds and are run only as part of the
// "metalint" command.
slowLinters = []string{
"gosimple",
"staticcheck",
"structcheck",
"unused",
"varcheck",
}
// Which parts of the tree to lint
build: Support builds outside of GOPATH This adds support for building with the source placed anywhere and no GOPATH set. The build script handles this by creating a temporary GOPATH in the system temp dir (or another specified location) and mirroring the source there before building. The resulting binaries etc still end up in the same place as usual, meaning at least the "build", "install", "tar", "zip", "deb", "snap", "test", "vet", "lint", "metalint" and "clean" commands work without a GOPATH. To this end these commands internally use fully qualified package paths like "github.com/syncthing/syncthing/cmd/..." instead of "./cmd/..." like before. There is a new command "gopath" that prepares and echoes the directory of the temporary GOPATH. This can be used to run other non-build go commands: export GOPATH=$(go run build.go gopath) // GOPATH is now set go test -v -race github.com/syncthing/syncthing/cmd/... There is a new option "-no-build-gopath" that prevents the check-and-copy step, instead assuming the temporary GOPATH is already created and up to date. This is a performance optimization for build servers running multiple builds commands in sequence: go run build.go gopath // creates a temporary GOPATH go run build.go -no-build-gopath -goos=... tar // reuses GOPATH go run build.go -no-build-gopath -goos=... tar // reuses GOPATH The temporary GOPATH is placed in the system temporary directory (os.TempDir()) unless overridden by the STTMPDIR variable. It is named after the hash of the current directory where build.go is run. The reason for this is that the name should be unique to a source checkout without risk for conflict, but still persistent between runs of build.go. GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4253 LGTM: AudriusButkevicius, imsodin
2017-07-11 07:57:58 +00:00
lintDirs = []string{
".",
"../cmd/...",
"../lib/...",
"../script/...",
}
// Messages to ignore
lintExcludes = []string{
".pb.go",
"should have comment",
"protocol.Vector composite literal uses unkeyed fields",
"cli.Requires composite literal uses unkeyed fields",
"Use DialContext instead", // Go 1.7
"os.SEEK_SET is deprecated", // Go 1.7
"SA4017", // staticcheck "is a pure function but its return value is ignored"
}
)
func TestCheckMetalint(t *testing.T) {
if !isGometalinterInstalled() {
return
}
gometalinter(t, lintDirs, lintExcludes...)
}
func isGometalinterInstalled() bool {
if _, err := runError("gometalinter", "--disable-all"); err != nil {
log.Println("gometalinter is not installed")
return false
}
return true
}
func gometalinter(t *testing.T, dirs []string, excludes ...string) bool {
params := []string{"--disable-all", "--concurrency=2", "--deadline=300s"}
for _, linter := range fastLinters {
params = append(params, "--enable="+linter)
}
if !testing.Short() {
for _, linter := range slowLinters {
params = append(params, "--enable="+linter)
}
}
for _, exclude := range excludes {
params = append(params, "--exclude="+exclude)
}
params = append(params, dirs...)
bs, _ := runError("gometalinter", params...)
nerr := 0
lines := make(map[string]struct{})
for _, line := range strings.Split(string(bs), "\n") {
if line == "" {
continue
}
if _, ok := lines[line]; ok {
continue
}
log.Println(line)
if strings.Contains(line, "executable file not found") {
log.Println(` - Try "go run build.go setup" to install missing tools`)
}
lines[line] = struct{}{}
nerr++
}
return nerr == 0
}
func runError(cmd string, args ...string) ([]byte, error) {
ecmd := exec.Command(cmd, args...)
bs, err := ecmd.CombinedOutput()
return bytes.TrimSpace(bs), err
}