1
0
mirror of https://github.com/go-task/task.git synced 2025-01-02 03:38:01 +02:00
task/vendor/github.com/mattn/go-zglob/zglob.go

209 lines
4.2 KiB
Go
Raw Normal View History

2017-02-27 22:04:44 +02:00
package zglob
import (
"fmt"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
"github.com/mattn/go-zglob/fastwalk"
)
var (
envre = regexp.MustCompile(`^(\$[a-zA-Z][a-zA-Z0-9_]+|\$\([a-zA-Z][a-zA-Z0-9_]+\))$`)
mu sync.Mutex
)
type zenv struct {
2018-04-28 20:35:15 +02:00
dre *regexp.Regexp
fre *regexp.Regexp
pattern string
root string
2017-02-27 22:04:44 +02:00
}
2018-04-28 20:35:15 +02:00
func New(pattern string) (*zenv, error) {
2017-02-27 22:04:44 +02:00
globmask := ""
root := ""
for n, i := range strings.Split(filepath.ToSlash(pattern), "/") {
if root == "" && strings.Index(i, "*") != -1 {
if globmask == "" {
root = "."
} else {
root = filepath.ToSlash(globmask)
}
}
if n == 0 && i == "~" {
if runtime.GOOS == "windows" {
i = os.Getenv("USERPROFILE")
} else {
i = os.Getenv("HOME")
}
}
if envre.MatchString(i) {
i = strings.Trim(strings.Trim(os.Getenv(i[1:]), "()"), `"`)
}
globmask = filepath.Join(globmask, i)
if n == 0 {
if runtime.GOOS == "windows" && filepath.VolumeName(i) != "" {
globmask = i + "/"
} else if len(globmask) == 0 {
globmask = "/"
}
}
}
if root == "" {
return &zenv{
2018-04-28 20:35:15 +02:00
dre: nil,
fre: nil,
pattern: pattern,
root: "",
2017-02-27 22:04:44 +02:00
}, nil
}
if globmask == "" {
globmask = "."
}
globmask = filepath.ToSlash(filepath.Clean(globmask))
cc := []rune(globmask)
dirmask := ""
filemask := ""
for i := 0; i < len(cc); i++ {
if cc[i] == '*' {
if i < len(cc)-2 && cc[i+1] == '*' && cc[i+2] == '/' {
filemask += "(.*/)?"
2018-01-03 19:12:40 +02:00
if dirmask == "" {
dirmask = filemask
}
2017-02-27 22:04:44 +02:00
i += 2
} else {
filemask += "[^/]*"
}
} else {
c := cc[i]
if c == '/' || ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || 255 < c {
filemask += string(c)
} else {
filemask += fmt.Sprintf("[\\x%02X]", c)
}
if c == '/' && dirmask == "" && strings.Index(filemask, "*") != -1 {
dirmask = filemask
}
}
}
if dirmask == "" {
dirmask = filemask
}
if len(filemask) > 0 && filemask[len(filemask)-1] == '/' {
if root == "" {
root = filemask
}
filemask += "[^/]*"
}
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
dirmask = "(?i:" + dirmask + ")"
filemask = "(?i:" + filemask + ")"
}
return &zenv{
2018-04-28 20:35:15 +02:00
dre: regexp.MustCompile("^" + dirmask),
fre: regexp.MustCompile("^" + filemask + "$"),
pattern: pattern,
root: filepath.Clean(root),
2017-02-27 22:04:44 +02:00
}, nil
}
func Glob(pattern string) ([]string, error) {
2017-11-19 22:26:37 +02:00
return glob(pattern, false)
}
func GlobFollowSymlinks(pattern string) ([]string, error) {
return glob(pattern, true)
}
func glob(pattern string, followSymlinks bool) ([]string, error) {
2018-04-28 20:35:15 +02:00
zenv, err := New(pattern)
2017-02-27 22:04:44 +02:00
if err != nil {
return nil, err
}
if zenv.root == "" {
_, err := os.Stat(pattern)
if err != nil {
return nil, os.ErrNotExist
}
return []string{pattern}, nil
}
relative := !filepath.IsAbs(pattern)
matches := []string{}
fastwalk.FastWalk(zenv.root, func(path string, info os.FileMode) error {
if zenv.root == "." && len(zenv.root) < len(path) {
path = path[len(zenv.root)+1:]
}
path = filepath.ToSlash(path)
2017-11-19 22:26:37 +02:00
if followSymlinks && info == os.ModeSymlink {
followedPath, err := filepath.EvalSymlinks(path)
if err == nil {
fi, err := os.Lstat(followedPath)
if err == nil && fi.IsDir() {
return fastwalk.TraverseLink
}
}
}
2017-02-27 22:04:44 +02:00
if info.IsDir() {
if path == "." || len(path) <= len(zenv.root) {
return nil
}
2018-01-03 19:12:40 +02:00
if zenv.fre.MatchString(path) {
mu.Lock()
matches = append(matches, path)
mu.Unlock()
return nil
}
2017-02-27 22:04:44 +02:00
if !zenv.dre.MatchString(path + "/") {
return filepath.SkipDir
}
}
if zenv.fre.MatchString(path) {
if relative && filepath.IsAbs(path) {
path = path[len(zenv.root)+1:]
}
mu.Lock()
matches = append(matches, path)
mu.Unlock()
}
return nil
})
return matches, nil
}
func Match(pattern, name string) (matched bool, err error) {
2018-04-28 20:35:15 +02:00
zenv, err := New(pattern)
2017-02-27 22:04:44 +02:00
if err != nil {
return false, err
}
2018-04-28 20:35:15 +02:00
return zenv.Match(name), nil
}
func (z *zenv) Match(name string) bool {
if z.root == "" {
return z.pattern == name
2017-02-27 22:04:44 +02:00
}
name = filepath.ToSlash(name)
2018-04-28 20:35:15 +02:00
if name == "." || len(name) <= len(z.root) {
return false
2017-02-27 22:04:44 +02:00
}
2018-04-28 20:35:15 +02:00
if z.fre.MatchString(name) {
return true
2017-02-27 22:04:44 +02:00
}
2018-04-28 20:35:15 +02:00
return false
2017-02-27 22:04:44 +02:00
}