Add filesystem glob support
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
package pcre
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"go.arsenm.dev/pcre/lib"
|
||||
@@ -66,3 +70,93 @@ func CompileGlob(glob string) (*Regexp, error) {
|
||||
// Compile converted glob and return results
|
||||
return Compile(pattern)
|
||||
}
|
||||
|
||||
// Glob returns a list of matches for the given glob pattern.
|
||||
// It returns nil if there was no match. If the glob contains
|
||||
// "**", it will recurse through the directory, which may be
|
||||
// extremely slow depending on which directory is being searched.
|
||||
func Glob(glob string) ([]string, error) {
|
||||
// If glob is empty, return nil
|
||||
if glob == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// If the glob is a file path, return the file
|
||||
_, err := os.Lstat(glob)
|
||||
if err == nil {
|
||||
return []string{glob}, nil
|
||||
}
|
||||
|
||||
// If the glob has no glob characters, return nil
|
||||
if !hasGlobChars(glob) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Split glob by filepath separator
|
||||
paths := strings.Split(glob, string(filepath.Separator))
|
||||
|
||||
var splitDir []string
|
||||
// For every path in split list
|
||||
for _, path := range paths {
|
||||
// If glob characters forund, stop
|
||||
if hasGlobChars(path) {
|
||||
break
|
||||
}
|
||||
// Add path to splitDir
|
||||
splitDir = append(splitDir, path)
|
||||
}
|
||||
|
||||
// Join splitDir and add filepath separator. This is the directory that will be searched.
|
||||
dir := filepath.Join(splitDir...)
|
||||
|
||||
if filepath.IsAbs(glob) {
|
||||
dir = string(filepath.Separator) + dir
|
||||
}
|
||||
|
||||
// If the directory is not accessible, return error
|
||||
_, err = os.Lstat(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Compile glob pattern
|
||||
r, err := CompileGlob(glob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
var matches []string
|
||||
// If glob contains "**" (starstar), walk recursively. Otherwise, only search dir.
|
||||
if strings.Contains(glob, "**") {
|
||||
err = filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if r.MatchString(path) {
|
||||
matches = append(matches, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
files, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, file := range files {
|
||||
// Get full path of file
|
||||
path := filepath.Join(dir, file.Name())
|
||||
if r.MatchString(path) {
|
||||
matches = append(matches, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
// hasGlobChars checks if the string has any
|
||||
// characters that are part of a glob.
|
||||
func hasGlobChars(s string) bool {
|
||||
return strings.ContainsAny(s, "*[]?")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user