aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cli/internal/util/filter
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
commitdd84b9d64fb98746a230cd24233ff50a562c39c9 (patch)
treeb583261ef00b3afe72ec4d6dacb31e57779a6faf /cli/internal/util/filter
parent0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff)
downloadHydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz
HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip
Diffstat (limited to 'cli/internal/util/filter')
-rw-r--r--cli/internal/util/filter/filter.go133
-rw-r--r--cli/internal/util/filter/filter_test.go116
2 files changed, 249 insertions, 0 deletions
diff --git a/cli/internal/util/filter/filter.go b/cli/internal/util/filter/filter.go
new file mode 100644
index 0000000..fbc475d
--- /dev/null
+++ b/cli/internal/util/filter/filter.go
@@ -0,0 +1,133 @@
+// Copyright (c) 2015-2020 InfluxData Inc. MIT License (MIT)
+// https://github.com/influxdata/telegraf
+package filter
+
+import (
+ "strings"
+
+ "github.com/gobwas/glob"
+)
+
+type Filter interface {
+ Match(string) bool
+}
+
+// Compile 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, _ := Compile([]string{"cpu", "mem", "net*"})
+// f.Match("cpu") // true
+// f.Match("network") // true
+// f.Match("memory") // false
+func Compile(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.ContainsAny(s, "*?[")
+}
+
+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
+}
+
+type IncludeExcludeFilter struct {
+ include Filter
+ exclude Filter
+ includeDefault bool
+ excludeDefault bool
+}
+
+func NewIncludeExcludeFilter(
+ include []string,
+ exclude []string,
+) (Filter, error) {
+ return NewIncludeExcludeFilterDefaults(include, exclude, true, false)
+}
+
+func NewIncludeExcludeFilterDefaults(
+ include []string,
+ exclude []string,
+ includeDefault bool,
+ excludeDefault bool,
+) (Filter, error) {
+ in, err := Compile(include)
+ if err != nil {
+ return nil, err
+ }
+
+ ex, err := Compile(exclude)
+ if err != nil {
+ return nil, err
+ }
+
+ return &IncludeExcludeFilter{in, ex, includeDefault, excludeDefault}, nil
+}
+
+func (f *IncludeExcludeFilter) Match(s string) bool {
+ if f.include != nil {
+ if !f.include.Match(s) {
+ return false
+ }
+ } else if !f.includeDefault {
+ return false
+ }
+
+ if f.exclude != nil {
+ if f.exclude.Match(s) {
+ return false
+ }
+ } else if f.excludeDefault {
+ return false
+ }
+
+ return true
+}
diff --git a/cli/internal/util/filter/filter_test.go b/cli/internal/util/filter/filter_test.go
new file mode 100644
index 0000000..727a4b6
--- /dev/null
+++ b/cli/internal/util/filter/filter_test.go
@@ -0,0 +1,116 @@
+// Copyright (c) 2015-2020 InfluxData Inc. MIT License (MIT)
+// https://github.com/influxdata/telegraf
+package filter
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCompile(t *testing.T) {
+ f, err := Compile([]string{})
+ assert.NoError(t, err)
+ assert.Nil(t, f)
+
+ f, err = Compile([]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 = Compile([]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 = Compile([]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 = Compile([]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"))
+}
+
+func TestIncludeExclude(t *testing.T) {
+ tags := []string{}
+ labels := []string{"best", "com_influxdata", "timeseries", "com_influxdata_telegraf", "ever"}
+
+ filter, err := NewIncludeExcludeFilter([]string{}, []string{"com_influx*"})
+ if err != nil {
+ t.Fatalf("Failed to create include/exclude filter - %v", err)
+ }
+
+ for i := range labels {
+ if filter.Match(labels[i]) {
+ tags = append(tags, labels[i])
+ }
+ }
+
+ assert.Equal(t, []string{"best", "timeseries", "ever"}, tags)
+}
+
+var benchbool bool
+
+func BenchmarkFilterSingleNoGlobFalse(b *testing.B) {
+ f, _ := Compile([]string{"cpu"})
+ var tmp bool
+ for n := 0; n < b.N; n++ {
+ tmp = f.Match("network")
+ }
+ benchbool = tmp
+}
+
+func BenchmarkFilterSingleNoGlobTrue(b *testing.B) {
+ f, _ := Compile([]string{"cpu"})
+ var tmp bool
+ for n := 0; n < b.N; n++ {
+ tmp = f.Match("cpu")
+ }
+ benchbool = tmp
+}
+
+func BenchmarkFilter(b *testing.B) {
+ f, _ := Compile([]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, _ := Compile([]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, _ := Compile([]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, _ := Compile([]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
+}