forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
matcher.go
134 lines (113 loc) · 3.21 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
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2020 OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http:https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
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
}