@ 260812.1

220302.2 · 5daeaefe4de0b5d6326db5e0ad31fc441e4470dd

Correctly follow symlinks, fix adapter funcs, fix Windows tests

This also tunes DefaultNumWorkers for macOS/Darwin which results in a 22% speed up: ``` name old time/op new time/op delta FastWalk-10 16.8ms ± 1% 13.0ms ± 2% -22.20% (p=0.008 n=5+5)

name old alloc/op new alloc/op delta FastWalk-10 2.13MB ± 0% 2.14MB ± 0% ~ (p=0.151 n=5+5)

name old allocs/op new allocs/op delta FastWalk-10 37.7k ± 0% 37.7k ± 0% -0.01% (p=0.016 n=5+5) ```

reading declarations

Changes to entry_filter_test.go. All files

entry_filter_test.go

@@ -7,6 +7,7 @@ import ( 	"os" 	"path/filepath" 	"runtime"+	"sync" 	"testing" 	"time" @@ -14,80 +15,64 @@ import ( )  func TestEntryFilter(t *testing.T) {-	dirEntry := func(t *testing.T, name string) fs.DirEntry {-		t.Helper()-		fi, err := os.Lstat(name)-		if err != nil {-			t.Fatal(err)-		}-		return fs.FileInfoToDirEntry(fi)-	}- 	tempdir := t.TempDir()--	fileName := filepath.Join(tempdir, "file.txt")-	if err := writeFile(fileName, "file.txt", 0644); err != nil {-		t.Fatal(err)+	files := map[string]string{+		"foo/foo.go": "one",+		"bar/bar.go": "LINK:../foo/foo.go",+		"bar/baz.go": "two",+		"bar/loop":   "LINK:../bar/", // symlink loop+		"file.go":    "three",++		// Use multiple symdirs to increase the chance that one+		// of these and not "foo" is followed first.+		"symdir1": "LINK:foo",+		"symdir2": "LINK:foo",+		"symdir3": "LINK:foo",+		"symdir4": "LINK:foo", 	}+	testCreateFiles(t, tempdir, files) -	linkDir := filepath.Join(tempdir, "dir")-	if err := os.Mkdir(linkDir, 0755); err != nil {-		t.Fatal(err)-	}-	linkName := filepath.Join(linkDir, "link.link")-	if err := symlink(t, "../"+filepath.Base(fileName), linkName); err != nil {+	var mu sync.Mutex+	var seen []os.FileInfo+	filter := fastwalk.NewEntryFilter()+	walkFn := fastwalk.IgnoreDuplicateFiles(func(path string, de fs.DirEntry, err error) error {+		requireNoError(t, err)+		fi1, err := fastwalk.StatDirEntry(path, de)+		if err != nil {+			t.Error(err)+			return err+		}+		mu.Lock()+		defer mu.Unlock()+		if !filter.Entry(path, de) {+			for _, fi2 := range seen {+				if os.SameFile(fi1, fi2) {+					t.Errorf("Visited file twice: %q (%s) and %q (%s)",+						path, fi1.Mode(), fi2.Name(), fi2.Mode())+				}+			}+		}+		seen = append(seen, fi1)+		return nil+	})+	if err := fastwalk.Walk(nil, tempdir, walkFn); err != nil { 		t.Fatal(err) 	} -	// Sanity check-	{-		fi1, err := os.Stat(fileName)+	// Test that true is returned for a non-existent directory+	// On Windows the Info field of the returned DirEntry+	// is already populated so this will succeed.+	if runtime.GOOS != "windows" {+		path := filepath.Join(tempdir, "src", "foo/foo.go")+		fi, err := os.Lstat(path) 		if err != nil { 			t.Fatal(err) 		}-		fi2, err := os.Stat(linkName)-		if err != nil {+		if err := os.Remove(path); err != nil { 			t.Fatal(err) 		}-		if !os.SameFile(fi1, fi2) {-			t.Fatalf("os.SameFile(%q, %q) == false", fileName, linkName)-		}-	}--	filter := fastwalk.NewEntryFilter()-	if seen := filter.Entry(fileName, dirEntry(t, fileName)); seen {-		t.Errorf("filter.Entry(%q) = %t want: %t",-			filepath.Dir(fileName), seen, false)-	}-	if seen := filter.Entry(linkName, dirEntry(t, linkName)); !seen {-		t.Errorf("filter.Entry(%q) = %t want: %t",-			filepath.Dir(linkName), seen, true)-	}--	// Entry should return true (aka seen) if there is an error-	// stat'ing the file.--	infos, err := os.ReadDir(tempdir)-	if err != nil {-		t.Fatal(err)-	}--	// Remove the files-	if err := os.RemoveAll(tempdir); err != nil {-		t.Fatal(err)-	}--	for _, de := range infos {-		// On Windows the Info field of the returned DirEntry-		// is already populated so this will succeed.-		if runtime.GOOS != "windows" {-			if _, err := de.Info(); err == nil {-				t.Fatal(de.Name())-			}-		}-		path := filepath.Join(tempdir, de.Name())-		if seen := filter.Entry(path, de); !seen {-			t.Errorf("filter.Entry(%q) = %t want: %t", de.Name(), seen, true)+		if !filter.Entry(path, fs.FileInfoToDirEntry(fi)) {+			t.Error("EntryFilter should return true when the file does not exist") 		} 	} }