-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
matcher.go
123 lines (102 loc) · 2.7 KB
/
matcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package docker // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/docker"
import (
"fmt"
"regexp"
"strings"
"github.com/gobwas/glob"
)
type stringMatcher struct {
standardItems map[string]bool
anyNegatedStandards bool
regexItems []regexItem
globItems []globbedItem
}
// This utility defines a regex as
// any string between two '/' characters
// with the option of a leading '!' to
// signify negation.
type regexItem struct {
re *regexp.Regexp
isNegated bool
}
func isRegex(s string) bool {
return len(s) > 2 && s[0] == '/' && s[len(s)-1] == '/'
}
type globbedItem struct {
glob glob.Glob
isNegated bool
}
func isGlobbed(s string) bool {
return strings.ContainsAny(s, "*?[]{}!")
}
func newStringMatcher(items []string) (*stringMatcher, error) {
standards := make(map[string]bool)
var regexes []regexItem
var globs []globbedItem
anyNegatedStandards := false
for _, i := range items {
item, isNegated := isNegatedItem(i)
switch {
case isRegex(item):
var re *regexp.Regexp
var err error
// by definition this must lead and end with '/' chars
reText := item[1 : len(item)-1]
re, err = regexp.Compile(reText)
if err != nil {
return nil, fmt.Errorf("invalid regex item: %w", err)
}
regexes = append(regexes, regexItem{re: re, isNegated: isNegated})
case isGlobbed(item):
g, err := glob.Compile(item)
if err != nil {
return nil, fmt.Errorf("invalid glob item: %w", err)
}
globs = append(globs, globbedItem{glob: g, isNegated: isNegated})
default:
standards[item] = isNegated
if isNegated {
anyNegatedStandards = true
}
}
}
return &stringMatcher{
standardItems: standards,
regexItems: regexes,
globItems: globs,
anyNegatedStandards: anyNegatedStandards,
}, nil
}
// isNegatedItem strips a leading '!' and returns
// the remaining substring and true. If no leading
// '!' is found, it returns the input string and false.
func isNegatedItem(value string) (string, bool) {
if strings.HasPrefix(value, "!") {
return value[1:], true
}
return value, false
}
func (f *stringMatcher) matches(s string) bool {
negated, matched := f.standardItems[s]
if matched {
return !negated
}
// If negated standard item "!something" is provided
// and "anything else" is evaluated we will always match.
if f.anyNegatedStandards {
return true
}
for _, reMatch := range f.regexItems {
if reMatch.re.MatchString(s) != reMatch.isNegated {
return true
}
}
for _, globMatch := range f.globItems {
if globMatch.glob.Match(s) != globMatch.isNegated {
return true
}
}
return false
}