internal/gopathwalk: create

Extract goimports' logic for walking Go source directories into a
separate package, suitable for use in go/packages. No functional
changes. Added a convenience feature to fastwalk, allowing the user to
say that they're done with a directory and stop receiving callbacks for
it.

Testing is a little light; I expect goimports' tests to cover most
everything we care about.

Change-Id: If047ada4414f5f282637d11fd07e8342fadc9c33
Reviewed-on: https://go-review.googlesource.com/c/138877
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/internal/fastwalk/fastwalk_test.go b/internal/fastwalk/fastwalk_test.go
index e9ab0d5..efb813c 100644
--- a/internal/fastwalk/fastwalk_test.go
+++ b/internal/fastwalk/fastwalk_test.go
@@ -145,6 +145,38 @@
 		})
 }
 
+func TestFastWalk_SkipFiles(t *testing.T) {
+	// Directory iteration order is undefined, so there's no way to know
+	// which file to expect until the walk happens. Rather than mess
+	// with the test infrastructure, just mutate want.
+	var mu sync.Mutex
+	want := map[string]os.FileMode{
+		"":              os.ModeDir,
+		"/src":          os.ModeDir,
+		"/src/zzz":      os.ModeDir,
+		"/src/zzz/c.go": 0,
+	}
+
+	testFastWalk(t, map[string]string{
+		"a_skipfiles.go": "a",
+		"b_skipfiles.go": "b",
+		"zzz/c.go":       "c",
+	},
+		func(path string, typ os.FileMode) error {
+			if strings.HasSuffix(path, "_skipfiles.go") {
+				mu.Lock()
+				defer mu.Unlock()
+				want["/src/"+filepath.Base(path)] = 0
+				return fastwalk.SkipFiles
+			}
+			return nil
+		},
+		want)
+	if len(want) != 5 {
+		t.Errorf("saw too many files: wanted 5, got %v (%v)", len(want), want)
+	}
+}
+
 func TestFastWalk_TraverseSymlink(t *testing.T) {
 	switch runtime.GOOS {
 	case "windows", "plan9":