1
0
mirror of https://github.com/golang/go synced 2024-11-05 14:56:10 -07:00

imports: add configuration mechanism to exclude directories

Each $GOPATH entry may have a file $GOPATH/src/.goimportsignore which
may contain blank lines, #comment lines, or lines naming a directory
relative to the configuration file to ignore when scanning.  No
globbing or regex patterns are allowed.

Updates golang/go#16367 (goimports speed)
Fixes golang/go#16386 (add mechanism to ignore directories)

Change-Id: I8f1a88ae6c4d0ed3075444d70aec3e2228c5ce6a
Reviewed-on: https://go-review.googlesource.com/24971
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Brad Fitzpatrick 2016-07-15 18:28:37 +00:00
parent 7c26c99973
commit ffe4e61c64
3 changed files with 76 additions and 1 deletions

View File

@ -27,6 +27,18 @@ For GoSublime, follow the steps described here:
For other editors, you probably know what to do. For other editors, you probably know what to do.
To exclude directories in your $GOPATH from being scanned for Go
files, goimports respects a configuration file at
$GOPATH/src/.goimportsignore which may contain blank lines, comment
lines (beginning with '#'), or lines naming a directory relative to
the configuration file to ignore when scanning. No globbing or regex
patterns are allowed. Use the "-v" verbose flag to verify it's
working and see what goimports is doing.
File bugs or feature requests at:
https://golang.org/issues/new?title=x/tools/cmd/goimports:+
Happy hacking! Happy hacking!
*/ */

View File

@ -5,6 +5,8 @@
package imports package imports
import ( import (
"bufio"
"bytes"
"fmt" "fmt"
"go/ast" "go/ast"
"go/build" "go/build"
@ -311,10 +313,47 @@ var visitedSymlinks struct {
m map[string]struct{} m map[string]struct{}
} }
var ignoredDirs []os.FileInfo
// populateIgnoredDirs reads an optional config file at <path>/.goimportsignore
// of relative directories to ignore when scanning for go files.
// The provided path is one of the $GOPATH entries with "src" appended.
func populateIgnoredDirs(path string) {
slurp, err := ioutil.ReadFile(filepath.Join(path, ".goimportsignore"))
if err != nil {
return
}
bs := bufio.NewScanner(bytes.NewReader(slurp))
for bs.Scan() {
line := strings.TrimSpace(bs.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
if fi, err := os.Stat(filepath.Join(path, line)); err == nil {
ignoredDirs = append(ignoredDirs, fi)
}
}
}
func skipDir(fi os.FileInfo) bool {
for _, ignoredDir := range ignoredDirs {
if os.SameFile(fi, ignoredDir) {
return true
}
}
return false
}
// shouldTraverse checks if fi, found in dir, is a directory or a symlink to a directory. // shouldTraverse checks if fi, found in dir, is a directory or a symlink to a directory.
// It makes sure symlinks were never visited before to avoid symlink loops. // It makes sure symlinks were never visited before to avoid symlink loops.
func shouldTraverse(dir string, fi os.FileInfo) bool { func shouldTraverse(dir string, fi os.FileInfo) bool {
if fi.IsDir() { if fi.IsDir() {
if skipDir(fi) {
if Debug {
log.Printf("skipping directory %q under %s", fi.Name(), dir)
}
return false
}
return true return true
} }
@ -382,6 +421,9 @@ func scanGoDirs(goRoot bool) {
if isGoroot != goRoot { if isGoroot != goRoot {
continue continue
} }
if !goRoot {
populateIgnoredDirs(path)
}
fsgate.enter() fsgate.enter()
testHookScanDir(path) testHookScanDir(path)
if Debug { if Debug {
@ -554,7 +596,7 @@ func loadExportsGoPath(expectPackage, dir string) map[string]bool {
exportList = append(exportList, k) exportList = append(exportList, k)
} }
sort.Strings(exportList) sort.Strings(exportList)
log.Printf("scanned dir %v (package %v): exports = %v", dir, expectPackage, strings.Join(exportList, ", ")) log.Printf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", "))
} }
return exports return exports
} }

View File

@ -985,6 +985,7 @@ func withEmptyGoPath(fn func()) {
scanGoRootOnce = &sync.Once{} scanGoRootOnce = &sync.Once{}
scanGoPathOnce = &sync.Once{} scanGoPathOnce = &sync.Once{}
dirScan = nil dirScan = nil
ignoredDirs = nil
dirScanMu.Unlock() dirScanMu.Unlock()
oldGOPATH := build.Default.GOPATH oldGOPATH := build.Default.GOPATH
@ -1304,6 +1305,26 @@ func TestImportPathToNameGoPathParse(t *testing.T) {
}) })
} }
func TestIgnoreConfiguration(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
".goimportsignore": "# comment line\n\n example.net", // tests comment, blank line, whitespace trimming
"example.net/pkg/pkg.go": "package pkg\nconst X = 1",
"otherwise-longer-so-worse.example.net/foo/pkg/pkg.go": "package pkg\nconst X = 1",
},
}.test(t, func(t *goimportTest) {
const in = "package x\n\nconst _ = pkg.X\n"
const want = "package x\n\nimport \"otherwise-longer-so-worse.example.net/foo/pkg\"\n\nconst _ = pkg.X\n"
buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(buf) != want {
t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want)
}
})
}
func strSet(ss []string) map[string]bool { func strSet(ss []string) map[string]bool {
m := make(map[string]bool) m := make(map[string]bool)
for _, s := range ss { for _, s := range ss {