Skip to content

Commit

Permalink
✨ feat(fs): add new util func SearchNameUp() for search file or dir path
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Mar 16, 2023
1 parent 247c554 commit d6255ee
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
97 changes: 97 additions & 0 deletions fsutil/find.go
@@ -0,0 +1,97 @@
package fsutil

import (
"io/fs"
"os"
"path/filepath"
)

// SearchNameUp find file/dir name in dirPath or parent dirs,
// return the name of directory path
//
// Usage:
//
// repoDir := fsutil.SearchNameUp("/path/to/dir", ".git")
func SearchNameUp(dirPath, name string) string {
dirPath = ToAbsPath(dirPath)

for {
namePath := filepath.Join(dirPath, name)
if PathExists(namePath) {
return dirPath
}

prevLn := len(dirPath)
dirPath = filepath.Dir(dirPath)
if prevLn == len(dirPath) {
return ""
}
}
}

// GlobWithFunc handle matched file
func GlobWithFunc(pattern string, fn func(filePath string) error) (err error) {
files, err := filepath.Glob(pattern)
if err != nil {
return err
}

for _, filePath := range files {
err = fn(filePath)
if err != nil {
break
}
}
return
}

type (
// FilterFunc type for FindInDir
FilterFunc func(fPath string, ent fs.DirEntry) bool
// HandleFunc type for FindInDir
HandleFunc func(fPath string, ent fs.DirEntry) error
)

// FindInDir code refer the go pkg: path/filepath.glob()
// - tip: will be not find in subdir.
//
// filters: return false will skip the file.
func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error) {
fi, err := os.Stat(dir)
if err != nil || !fi.IsDir() {
return // ignore I/O error
}

// names, _ := d.Readdirnames(-1)
// sort.Strings(names)

des, err := os.ReadDir(dir)
if err != nil {
return
}

for _, ent := range des {
baseName := ent.Name()
filePath := dir + "/" + baseName

// call filters
if len(filters) > 0 {
var filtered = false
for _, filter := range filters {
if !filter(filePath, ent) {
filtered = true
break
}
}

if filtered {
continue
}
}

if err := handleFn(filePath, ent); err != nil {
return err
}
}
return nil
}
62 changes: 62 additions & 0 deletions fsutil/find_test.go
@@ -0,0 +1,62 @@
package fsutil_test

import (
"io/fs"
"strings"
"testing"

"github.com/gookit/goutil/dump"
"github.com/gookit/goutil/errorx"
"github.com/gookit/goutil/fsutil"
"github.com/gookit/goutil/testutil/assert"
)

func TestSearchNameUp(t *testing.T) {
p := fsutil.SearchNameUp("testdata", "finder")
assert.NotEmpty(t, p)
assert.True(t, strings.HasSuffix(p, "fsutil"))

p = fsutil.SearchNameUp("testdata", ".dotdir")
assert.NotEmpty(t, p)
assert.True(t, strings.HasSuffix(p, "testdata"))

p = fsutil.SearchNameUp("testdata", "test.jpg")
assert.NotEmpty(t, p)
assert.True(t, strings.HasSuffix(p, "testdata"))

p = fsutil.SearchNameUp("testdata", "not-exists")
assert.Empty(t, p)
}

func TestFindInDir(t *testing.T) {
err := fsutil.FindInDir("path-not-exist", nil)
assert.NoErr(t, err)

err = fsutil.FindInDir("testdata/test.jpg", nil)
assert.NoErr(t, err)

files := make([]string, 0, 8)
err = fsutil.FindInDir("testdata", func(fPath string, de fs.DirEntry) error {
files = append(files, fPath)
return nil
})

dump.P(files)
assert.NoErr(t, err)
assert.True(t, len(files) > 0)

files = files[:0]
err = fsutil.FindInDir("testdata", func(fPath string, de fs.DirEntry) error {
files = append(files, fPath)
return nil
}, func(fPath string, de fs.DirEntry) bool {
return !strings.HasPrefix(de.Name(), ".")
})
assert.NoErr(t, err)
assert.True(t, len(files) > 0)

err = fsutil.FindInDir("testdata", func(fPath string, de fs.DirEntry) error {
return errorx.Raw("handle error")
})
assert.Err(t, err)
}

0 comments on commit d6255ee

Please sign in to comment.