package eval
import (
)
type globPattern struct {
glob.Pattern
Flags globFlag
Buts []string
TypeCb func(os.FileMode) bool
}
type globFlag uint
var typeCbMap = map[string]func(os.FileMode) bool{
"dir": os.FileMode.IsDir,
"regular": os.FileMode.IsRegular,
}
const (
noMatchOK globFlag = 1 << iota
)
func ( globFlag) ( globFlag) bool {
return ( & ) ==
}
var _ vals.ErrIndexer = globPattern{}
var (
ErrMustFollowWildcard = errors.New("must follow wildcard")
ErrModifierMustBeString = errors.New("modifier must be string")
ErrWildcardNoMatch = errors.New("wildcard has no match")
ErrMultipleTypeModifiers = errors.New("only one type modifier allowed")
ErrUnknownTypeModifier = errors.New("unknown type modifier")
)
var runeMatchers = map[string]func(rune) bool{
"control": unicode.IsControl,
"digit": unicode.IsDigit,
"graphic": unicode.IsGraphic,
"letter": unicode.IsLetter,
"lower": unicode.IsDigit,
"mark": unicode.IsMark,
"number": unicode.IsNumber,
"print": unicode.IsPrint,
"punct": unicode.IsPunct,
"space": unicode.IsSpace,
"symbol": unicode.IsSymbol,
"title": unicode.IsTitle,
"upper": unicode.IsUpper,
}
func ( globPattern) ( interface{}) (interface{}, error) {
, := .(string)
if ! {
return nil, ErrModifierMustBeString
}
:=
switch {
case == "nomatch-ok":
.Flags |= noMatchOK
case strings.HasPrefix(, "but:"):
.Buts = append(.Buts, [len("but:"):])
case == "match-hidden":
, := .lastWildSeg()
if != nil {
return nil,
}
.Segments[len(.Segments)-1] = glob.Wild{
Type: .Type, MatchHidden: true, Matchers: .Matchers,
}
case strings.HasPrefix(, "type:"):
if .TypeCb != nil {
return nil, ErrMultipleTypeModifiers
}
:= [len("type:"):]
, := typeCbMap[]
if ! {
return nil, ErrUnknownTypeModifier
}
.TypeCb =
default:
var func(rune) bool
if , := runeMatchers[]; {
=
} else if strings.HasPrefix(, "set:") {
:= [len("set:"):]
= func( rune) bool {
return strings.ContainsRune(, )
}
} else if strings.HasPrefix(, "range:") {
:= [len("range:"):]
:= fmt.Errorf("bad range modifier: %s", parse.Quote())
:= []rune()
if len() != 3 {
return nil,
}
, , := [0], [1], [2]
switch {
case '-':
= func( rune) bool {
return <= && <=
}
case '~':
= func( rune) bool {
return <= && <
}
default:
return nil,
}
} else {
return nil, fmt.Errorf("unknown modifier %s", vals.Repr(, vals.NoPretty))
}
:= .addMatcher()
return ,
}
return , nil
}
func ( globPattern) ( interface{}) (interface{}, error) {
switch rhs := .(type) {
case string:
.append(stringToSegments()...)
return , nil
case globPattern:
.append(.Segments[0])
.Flags |= .Flags
.Buts = append(.Buts, .Buts...)
if .TypeCb != nil && .TypeCb != nil {
return nil, ErrMultipleTypeModifiers
}
if .TypeCb != nil {
.TypeCb = .TypeCb
}
return , nil
}
return nil, vals.ErrConcatNotImplemented
}
func ( globPattern) ( interface{}) (interface{}, error) {
switch lhs := .(type) {
case string:
:= stringToSegments()
= append(, .Segments[0])
return globPattern{Pattern: glob.Pattern{Segments: }, Flags: .Flags,
Buts: .Buts, TypeCb: .TypeCb}, nil
}
return nil, vals.ErrConcatNotImplemented
}
func ( *globPattern) () (glob.Wild, error) {
if len(.Segments) == 0 {
return glob.Wild{}, ErrBadglobPattern
}
if !glob.IsWild(.Segments[len(.Segments)-1]) {
return glob.Wild{}, ErrMustFollowWildcard
}
return .Segments[len(.Segments)-1].(glob.Wild), nil
}
func ( *globPattern) ( func(rune) bool) error {
, := .lastWildSeg()
if != nil {
return
}
.Segments[len(.Segments)-1] = glob.Wild{
Type: .Type, MatchHidden: .MatchHidden,
Matchers: append(.Matchers, ),
}
return nil
}
func ( *globPattern) ( ...glob.Segment) {
.Segments = append(.Segments, ...)
}
func ( string) (glob.Segment, error) {
switch {
case "*":
return glob.Wild{Type: glob.Star, MatchHidden: false, Matchers: nil}, nil
case "**":
return glob.Wild{Type: glob.StarStar, MatchHidden: false, Matchers: nil}, nil
case "?":
return glob.Wild{Type: glob.Question, MatchHidden: false, Matchers: nil}, nil
default:
return nil, fmt.Errorf("bad wildcard: %q", )
}
}
func ( string) []glob.Segment {
:= []glob.Segment{}
for := 0; < len(); {
:=
for ; < len() && [] != '/'; ++ {
}
if > {
= append(, glob.Literal{Data: [:]})
}
if < len() {
for ; < len() && [] == '/'; ++ {
}
= append(, glob.Slash{})
=
} else {
break
}
}
return
}
func ( globPattern, <-chan struct{}) ([]interface{}, error) {
:= make(map[string]struct{})
for , := range .Buts {
[] = struct{}{}
}
:= make([]interface{}, 0)
if !.Glob(func( glob.PathInfo) bool {
select {
case <-:
logger.Println("glob aborted")
return false
default:
}
if , := [.Path]; {
return true
}
if .TypeCb == nil || .TypeCb(.Info.Mode()) {
= append(, .Path)
}
return true
}) {
return nil, ErrInterrupted
}
if len() == 0 && !.Flags.Has(noMatchOK) {
return nil, ErrWildcardNoMatch
}
return , nil
}