-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
1,713 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package filter | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCompileFilter(t *testing.T) { | ||
f, err := CompileFilter([]string{}) | ||
assert.NoError(t, err) | ||
assert.Nil(t, f) | ||
|
||
f, err = CompileFilter([]string{"cpu"}) | ||
assert.NoError(t, err) | ||
assert.True(t, f.Match("cpu")) | ||
assert.False(t, f.Match("cpu0")) | ||
assert.False(t, f.Match("mem")) | ||
|
||
f, err = CompileFilter([]string{"cpu*"}) | ||
assert.NoError(t, err) | ||
assert.True(t, f.Match("cpu")) | ||
assert.True(t, f.Match("cpu0")) | ||
assert.False(t, f.Match("mem")) | ||
|
||
f, err = CompileFilter([]string{"cpu", "mem"}) | ||
assert.NoError(t, err) | ||
assert.True(t, f.Match("cpu")) | ||
assert.False(t, f.Match("cpu0")) | ||
assert.True(t, f.Match("mem")) | ||
|
||
f, err = CompileFilter([]string{"cpu", "mem", "net*"}) | ||
assert.NoError(t, err) | ||
assert.True(t, f.Match("cpu")) | ||
assert.False(t, f.Match("cpu0")) | ||
assert.True(t, f.Match("mem")) | ||
assert.True(t, f.Match("network")) | ||
} | ||
|
||
var benchbool bool | ||
|
||
func BenchmarkFilterSingleNoGlobFalse(b *testing.B) { | ||
f, _ := CompileFilter([]string{"cpu"}) | ||
var tmp bool | ||
for n := 0; n < b.N; n++ { | ||
tmp = f.Match("network") | ||
} | ||
benchbool = tmp | ||
} | ||
|
||
func BenchmarkFilterSingleNoGlobTrue(b *testing.B) { | ||
f, _ := CompileFilter([]string{"cpu"}) | ||
var tmp bool | ||
for n := 0; n < b.N; n++ { | ||
tmp = f.Match("cpu") | ||
} | ||
benchbool = tmp | ||
} | ||
|
||
func BenchmarkFilter(b *testing.B) { | ||
f, _ := CompileFilter([]string{"cpu", "mem", "net*"}) | ||
var tmp bool | ||
for n := 0; n < b.N; n++ { | ||
tmp = f.Match("network") | ||
} | ||
benchbool = tmp | ||
} | ||
|
||
func BenchmarkFilterNoGlob(b *testing.B) { | ||
f, _ := CompileFilter([]string{"cpu", "mem", "net"}) | ||
var tmp bool | ||
for n := 0; n < b.N; n++ { | ||
tmp = f.Match("net") | ||
} | ||
benchbool = tmp | ||
} | ||
|
||
func BenchmarkFilter2(b *testing.B) { | ||
f, _ := CompileFilter([]string{"aa", "bb", "c", "ad", "ar", "at", "aq", | ||
"aw", "az", "axxx", "ab", "cpu", "mem", "net*"}) | ||
var tmp bool | ||
for n := 0; n < b.N; n++ { | ||
tmp = f.Match("network") | ||
} | ||
benchbool = tmp | ||
} | ||
|
||
func BenchmarkFilter2NoGlob(b *testing.B) { | ||
f, _ := CompileFilter([]string{"aa", "bb", "c", "ad", "ar", "at", "aq", | ||
"aw", "az", "axxx", "ab", "cpu", "mem", "net"}) | ||
var tmp bool | ||
for n := 0; n < b.N; n++ { | ||
tmp = f.Match("net") | ||
} | ||
benchbool = tmp | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.