80 lines
1.6 KiB
Go
80 lines
1.6 KiB
Go
|
package filter
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
|
||
|
"github.com/gobwas/glob"
|
||
|
)
|
||
|
|
||
|
type Filter interface {
|
||
|
Match(string) bool
|
||
|
}
|
||
|
|
||
|
// CompileFilter takes a list of string filters and returns a Filter interface
|
||
|
// for matching a given string against the filter list. The filter list
|
||
|
// supports glob matching too, ie:
|
||
|
//
|
||
|
// f, _ := CompileFilter([]string{"cpu", "mem", "net*"})
|
||
|
// f.Match("cpu") // true
|
||
|
// f.Match("network") // true
|
||
|
// f.Match("memory") // false
|
||
|
//
|
||
|
func CompileFilter(filters []string) (Filter, error) {
|
||
|
// return if there is nothing to compile
|
||
|
if len(filters) == 0 {
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
// check if we can compile a non-glob filter
|
||
|
noGlob := true
|
||
|
for _, filter := range filters {
|
||
|
if hasMeta(filter) {
|
||
|
noGlob = false
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch {
|
||
|
case noGlob:
|
||
|
// return non-globbing filter if not needed.
|
||
|
return compileFilterNoGlob(filters), nil
|
||
|
case len(filters) == 1:
|
||
|
return glob.Compile(filters[0])
|
||
|
default:
|
||
|
return glob.Compile("{" + strings.Join(filters, ",") + "}")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// hasMeta reports whether path contains any magic glob characters.
|
||
|
func hasMeta(s string) bool {
|
||
|
return strings.IndexAny(s, "*?[") >= 0
|
||
|
}
|
||
|
|
||
|
type filter struct {
|
||
|
m map[string]struct{}
|
||
|
}
|
||
|
|
||
|
func (f *filter) Match(s string) bool {
|
||
|
_, ok := f.m[s]
|
||
|
return ok
|
||
|
}
|
||
|
|
||
|
type filtersingle struct {
|
||
|
s string
|
||
|
}
|
||
|
|
||
|
func (f *filtersingle) Match(s string) bool {
|
||
|
return f.s == s
|
||
|
}
|
||
|
|
||
|
func compileFilterNoGlob(filters []string) Filter {
|
||
|
if len(filters) == 1 {
|
||
|
return &filtersingle{s: filters[0]}
|
||
|
}
|
||
|
out := filter{m: make(map[string]struct{})}
|
||
|
for _, filter := range filters {
|
||
|
out.m[filter] = struct{}{}
|
||
|
}
|
||
|
return &out
|
||
|
}
|