--unset 1 year ago
parent
commit
d5002d801d
4 changed files with 149 additions and 0 deletions
  1. 93 0
      filterfs.go
  2. 52 0
      filterfs_test.go
  3. 3 0
      go.mod
  4. 1 0
      testfs.go

+ 93 - 0
filterfs.go

@@ -0,0 +1,93 @@
+package filterfs
+
+import "io/fs"
+import "fmt"
+
+// Filter returns true to include a file name and false to exclude it.
+type Filter func(name string) bool
+
+type FS struct {
+	underlying fs.FS
+	filter     Filter
+}
+
+func Apply(sys fs.FS, filter Filter) FS {
+	return FS{sys, filter}
+}
+
+type File struct {
+	underlying fs.ReadDirFile
+	filter     Filter
+}
+
+func (f File) Stat() (fs.FileInfo, error) {
+	return f.underlying.Stat()
+}
+
+func (f File) Read(buf []byte) (int, error) {
+	return f.underlying.Read(buf)
+}
+
+func (f File) Close() error {
+	return f.underlying.Close()
+}
+
+func filterEntries(filter Filter, entries []fs.DirEntry) []fs.DirEntry {
+	result := []fs.DirEntry{}
+	for _, entry := range entries {
+		if filter(entry.Name()) {
+			result = append(result, entry)
+		}
+	}
+	return result
+}
+
+func (f File) ReadDir(n int) ([]fs.DirEntry, error) {
+	entries, err := f.underlying.ReadDir(n)
+	if err != nil {
+		return entries, err
+	}
+	return filterEntries(f.filter, entries), nil
+}
+
+func (sys FS) Open(name string) (fs.File, error) {
+	file, err := sys.underlying.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	if dir, ok := file.(fs.ReadDirFile); ok {
+		return File{dir, sys.filter}, nil
+	} else {
+		return file, nil
+	}
+}
+
+func (sys FS) Glob(pattern string) ([]string, error) {
+	entries, err := fs.Glob(sys.underlying, pattern)
+	if err != nil {
+		return entries, err
+	}
+	result := []string{}
+	for _, entry := range entries {
+		if sys.filter(entry) {
+			result = append(result, entry)
+		}
+	}
+	fmt.Printf("%v\n", entries)
+	fmt.Printf("%v\n", result)
+	return result, nil
+}
+
+/*
+func (sys FS) ReadDir(fname string) ([]fs.DirEntry, error) {
+	entries, err := fs.ReadDir(sys.underlying, fname)
+	if err != nil {
+		return entries, err
+	}
+	return filterEntries(sys.filter, entries), nil
+}
+*/
+
+var _ fs.FS = &FS{}
+var _ fs.GlobFS = &FS{}
+var _ fs.ReadDirFS = &FS{}

+ 52 - 0
filterfs_test.go

@@ -0,0 +1,52 @@
+package filterfs
+
+import "testing"
+import "testing/fstest"
+import "reflect"
+import "regexp"
+
+type Is struct{ *testing.T }
+
+func (is *Is) Is(test bool) {
+	if !test {
+		is.Fatalf("Expected true.\n")
+	}
+}
+
+func (is *Is) Equal(expected, actual any) {
+	if !reflect.DeepEqual(expected, actual) {
+		is.Fatalf("Not equal: %v != %v.\n", expected, actual)
+	}
+}
+
+func (is *Is) Nil(actual any) {
+	if actual != nil {
+		is.Fatalf("Expected nil: %v.\n", actual)
+	}
+}
+
+func helperMakeFS() fstest.MapFS {
+	return fstest.MapFS{
+		"foo.go":      {Data: []byte("1")},
+		"bar/foo.go":  {Data: []byte("2")},
+		"foo.txt":     {Data: []byte("a")},
+		"bar/foo.txt": {Data: []byte("b")},
+	}
+}
+
+func TestTest(t *testing.T) {
+	is := Is{t}
+	under := helperMakeFS()
+	is.Nil(fstest.TestFS(under, "foo.go", "bar/foo.go"))
+}
+
+func TestFilesystem(t *testing.T) {
+	is := Is{t}
+	under := helperMakeFS()
+
+	filtered := Apply(under, func(name string) bool {
+		ok, _ := regexp.Match(".*\\.go", []byte(name))
+		return ok
+	})
+	is.Nil(fstest.TestFS(filtered, "foo.go", "bar/foo.go"))
+}

+ 3 - 0
go.mod

@@ -0,0 +1,3 @@
+module src.eruta.nl/beoran/filterfs
+
+go 1.18

+ 1 - 0
testfs.go

@@ -0,0 +1 @@
+package filterfs