diff --git a/go.mod b/go.mod index 1c452be0..3bff4e3e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/golangci/golangci-lint require ( github.com/BurntSushi/toml v0.3.1 // indirect - github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2 + github.com/OpenPeeDeeP/depguard v1.0.0 github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/fatih/color v1.6.0 github.com/go-critic/go-critic v0.0.0-20181204210945-1df300866540 diff --git a/go.sum b/go.sum index 58ababec..6cce0d29 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2 h1:HTOmFEEYrWi4MW5ZKUx6xfeyM10Sx3kQF65xiQJMPYA= -github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= +github.com/OpenPeeDeeP/depguard v1.0.0 h1:k9QF73nrHT3nPLz3lu6G5s+3Hi8Je36ODr1F5gjAXXM= +github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/vendor/github.com/OpenPeeDeeP/depguard/README.md b/vendor/github.com/OpenPeeDeeP/depguard/README.md index 6f742511..3f7f2a4b 100644 --- a/vendor/github.com/OpenPeeDeeP/depguard/README.md +++ b/vendor/github.com/OpenPeeDeeP/depguard/README.md @@ -28,6 +28,9 @@ The following is an example configuration file. "packages": [ "github.com/OpenPeeDeeP/depguard" ], + "inTests": [ + "github.com/stretchr/testify" + ], "includeGoRoot": true } ``` @@ -35,6 +38,7 @@ The following is an example configuration file. - `type` can be either `whitelist` or `blacklist`. This check is case insensitive. If not specified the default is `blacklist`. - `packages` is a list of packages for the list type specified. +- `inTests` is a list of packages allowed/disallowed only in test files. - Set `includeGoRoot` to true if you want to check the list against standard lib. If not specified the default is false. diff --git a/vendor/github.com/OpenPeeDeeP/depguard/depguard.go b/vendor/github.com/OpenPeeDeeP/depguard/depguard.go index 433cf8ff..b547c0b6 100644 --- a/vendor/github.com/OpenPeeDeeP/depguard/depguard.go +++ b/vendor/github.com/OpenPeeDeeP/depguard/depguard.go @@ -1,7 +1,6 @@ package depguard import ( - "go/build" "go/token" "os" "sort" @@ -11,44 +10,50 @@ import ( "golang.org/x/tools/go/loader" ) -//ListType states what kind of list is passed in. +// ListType states what kind of list is passed in. type ListType int const ( - //LTBlacklist states the list given is a blacklist. (default) + // LTBlacklist states the list given is a blacklist. (default) LTBlacklist ListType = iota - //LTWhitelist states the list given is a whitelist. + // LTWhitelist states the list given is a whitelist. LTWhitelist ) -//StringToListType makes it easier to turn a string into a ListType. -//It assumes that the string representation is lower case. +// StringToListType makes it easier to turn a string into a ListType. +// It assumes that the string representation is lower case. var StringToListType = map[string]ListType{ "whitelist": LTWhitelist, "blacklist": LTBlacklist, } -//Issue with the package with PackageName at the Position. +// Issue with the package with PackageName at the Position. type Issue struct { PackageName string Position token.Position } -//Depguard checks imports to make sure they follow the given list and constraints. +// Depguard checks imports to make sure they follow the given list and constraints. type Depguard struct { - ListType ListType + ListType ListType + IncludeGoRoot bool + Packages []string - IncludeGoRoot bool prefixPackages []string globPackages []glob.Glob - buildCtx *build.Context - cwd string + + TestPackages []string + prefixTestPackages []string + globTestPackages []glob.Glob + + rootChecker *RootChecker + cwd string } -//Run checks for dependencies given the program and validates them against -//Packages. +// Run checks for dependencies given the program and validates them against +// Packages. func (dg *Depguard) Run(config *loader.Config, prog *loader.Program) ([]*Issue, error) { - //Shortcut execution on an empty blacklist as that means every package is allowed + // Shortcut execution on an empty blacklist as that means every package is allowed if dg.ListType == LTBlacklist && len(dg.Packages) == 0 { return nil, nil } @@ -56,15 +61,20 @@ func (dg *Depguard) Run(config *loader.Config, prog *loader.Program) ([]*Issue, if err := dg.initialize(config, prog); err != nil { return nil, err } - directImports, err := dg.createImportMap(prog) if err != nil { return nil, err } var issues []*Issue for pkg, positions := range directImports { - if dg.flagIt(pkg) { - for _, pos := range positions { + for _, pos := range positions { + + prefixList, globList := dg.prefixPackages, dg.globPackages + if len(dg.TestPackages) > 0 && strings.Index(pos.Filename, "_test.go") != -1 { + prefixList, globList = dg.prefixTestPackages, dg.globTestPackages + } + + if dg.flagIt(pkg, prefixList, globList) { issues = append(issues, &Issue{ PackageName: pkg, Position: pos, @@ -76,7 +86,7 @@ func (dg *Depguard) Run(config *loader.Config, prog *loader.Program) ([]*Issue, } func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) error { - //Try and get the current working directory + // Try and get the current working directory dg.cwd = config.Cwd if dg.cwd == "" { var err error @@ -86,12 +96,9 @@ func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) erro } } - //Use the &build.Default if one is not specified - dg.buildCtx = config.Build - if dg.buildCtx == nil { - dg.buildCtx = &build.Default - } + dg.rootChecker = NewRootChecker(config.Build) + // parse ordinary guarded packages for _, pkg := range dg.Packages { if strings.ContainsAny(pkg, "!?*[]{}") { g, err := glob.Compile(pkg, '/') @@ -104,27 +111,44 @@ func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) erro } } - //Sort the packages so we can have a faster search in the array + // Sort the packages so we can have a faster search in the array sort.Strings(dg.prefixPackages) + + // parse guarded tests packages + for _, pkg := range dg.TestPackages { + if strings.ContainsAny(pkg, "!?*[]{}") { + g, err := glob.Compile(pkg, '/') + if err != nil { + return err + } + dg.globTestPackages = append(dg.globTestPackages, g) + } else { + dg.prefixTestPackages = append(dg.prefixTestPackages, pkg) + } + } + + // Sort the test packages so we can have a faster search in the array + sort.Strings(dg.prefixTestPackages) + return nil } func (dg *Depguard) createImportMap(prog *loader.Program) (map[string][]token.Position, error) { importMap := make(map[string][]token.Position) - //For the directly imported packages + // For the directly imported packages for _, imported := range prog.InitialPackages() { - //Go through their files + // Go through their files for _, file := range imported.Files { - //And populate a map of all direct imports and their positions - //This will filter out GoRoot depending on the Depguard.IncludeGoRoot + // And populate a map of all direct imports and their positions + // This will filter out GoRoot depending on the Depguard.IncludeGoRoot for _, fileImport := range file.Imports { fileImportPath := cleanBasicLitString(fileImport.Path.Value) if !dg.IncludeGoRoot { - pkg, err := dg.buildCtx.Import(fileImportPath, dg.cwd, 0) + isRoot, err := dg.rootChecker.IsRoot(fileImportPath, dg.cwd) if err != nil { return nil, err } - if pkg.Goroot { + if isRoot { continue } } @@ -143,29 +167,29 @@ func (dg *Depguard) createImportMap(prog *loader.Program) (map[string][]token.Po return importMap, nil } -func (dg *Depguard) pkgInList(pkg string) bool { - if dg.pkgInPrefixList(pkg) { +func (dg *Depguard) pkgInList(pkg string, prefixList []string, globList []glob.Glob) bool { + if dg.pkgInPrefixList(pkg, prefixList) { return true } - return dg.pkgInGlobList(pkg) + return dg.pkgInGlobList(pkg, globList) } -func (dg *Depguard) pkgInPrefixList(pkg string) bool { - //Idx represents where in the package slice the passed in package would go - //when sorted. -1 Just means that it would be at the very front of the slice. - idx := sort.Search(len(dg.prefixPackages), func(i int) bool { - return dg.prefixPackages[i] > pkg +func (dg *Depguard) pkgInPrefixList(pkg string, prefixList []string) bool { + // Idx represents where in the package slice the passed in package would go + // when sorted. -1 Just means that it would be at the very front of the slice. + idx := sort.Search(len(prefixList), func(i int) bool { + return prefixList[i] > pkg }) - 1 - //This means that the package passed in has no way to be prefixed by anything - //in the package list as it is already smaller then everything + // This means that the package passed in has no way to be prefixed by anything + // in the package list as it is already smaller then everything if idx == -1 { return false } - return strings.HasPrefix(pkg, dg.prefixPackages[idx]) + return strings.HasPrefix(pkg, prefixList[idx]) } -func (dg *Depguard) pkgInGlobList(pkg string) bool { - for _, g := range dg.globPackages { +func (dg *Depguard) pkgInGlobList(pkg string, globList []glob.Glob) bool { + for _, g := range globList { if g.Match(pkg) { return true } @@ -173,11 +197,11 @@ func (dg *Depguard) pkgInGlobList(pkg string) bool { return false } -//InList | WhiteList | BlackList +// InList | WhiteList | BlackList // y | | x // n | x | -func (dg *Depguard) flagIt(pkg string) bool { - return dg.pkgInList(pkg) == (dg.ListType == LTBlacklist) +func (dg *Depguard) flagIt(pkg string, prefixList []string, globList []glob.Glob) bool { + return dg.pkgInList(pkg, prefixList, globList) == (dg.ListType == LTBlacklist) } func cleanBasicLitString(value string) string { diff --git a/vendor/github.com/OpenPeeDeeP/depguard/rootchecker.go b/vendor/github.com/OpenPeeDeeP/depguard/rootchecker.go new file mode 100644 index 00000000..7dae0efd --- /dev/null +++ b/vendor/github.com/OpenPeeDeeP/depguard/rootchecker.go @@ -0,0 +1,52 @@ +package depguard + +import ( + "go/build" +) + +// RootChecker checks if import paths point to root packages. +type RootChecker struct { + buildCtx *build.Context + cache map[string]bool +} + +// NewRootChecker creates a new RootChecker instance using the build.Context +// given, or build.Default. +func NewRootChecker(buildCtx *build.Context) *RootChecker { + // Use the &build.Default if build.Context is not specified + ctx := buildCtx + if ctx == nil { + ctx = &build.Default + } + return &RootChecker{ + buildCtx: ctx, + cache: make(map[string]bool, 0), + } +} + +// IsRoot checks if the given import path (imported from sourceDir) +// points to a a root package. Subsequent calls with the same arguments +// are cached. This is not thread-safe. +func (rc *RootChecker) IsRoot(path, sourceDir string) (bool, error) { + key := path + ":::" + sourceDir + isRoot, ok := rc.cache[key] + if ok { + return isRoot, nil + } + isRoot, err := rc.calcIsRoot(path, sourceDir) + if err != nil { + return false, err + } + rc.cache[key] = isRoot + return isRoot, nil +} + +// calcIsRoot performs the call to the build context to check if +// the import path points to a root package. +func (rc *RootChecker) calcIsRoot(path, sourceDir string) (bool, error) { + pkg, err := rc.buildCtx.Import(path, sourceDir, build.FindOnly) + if err != nil { + return false, err + } + return pkg.Goroot, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 0cb94687..89160bf2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,6 +1,6 @@ # github.com/BurntSushi/toml v0.3.1 github.com/BurntSushi/toml -# github.com/OpenPeeDeeP/depguard v0.0.0-20180806142446-a69c782687b2 +# github.com/OpenPeeDeeP/depguard v1.0.0 github.com/OpenPeeDeeP/depguard # github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 github.com/StackExchange/wmi