1// Copyright 2018 Prometheus Team
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package labels
15
16import (
17	"fmt"
18	"regexp"
19	"strings"
20)
21
22var (
23	re      = regexp.MustCompile(`(?:\s?)(\w+)(=|=~|!=|!~)(?:\"([^"=~!]+)\"|([^"=~!]+)|\"\")`)
24	typeMap = map[string]MatchType{
25		"=":  MatchEqual,
26		"!=": MatchNotEqual,
27		"=~": MatchRegexp,
28		"!~": MatchNotRegexp,
29	}
30)
31
32func ParseMatchers(s string) ([]*Matcher, error) {
33	matchers := []*Matcher{}
34	s = strings.TrimPrefix(s, "{")
35	s = strings.TrimSuffix(s, "}")
36
37	var insideQuotes bool
38	var token string
39	var tokens []string
40	for _, r := range s {
41		if !insideQuotes && r == ',' {
42			tokens = append(tokens, token)
43			token = ""
44			continue
45		}
46		token += string(r)
47		if r == '"' {
48			insideQuotes = !insideQuotes
49		}
50	}
51	if token != "" {
52		tokens = append(tokens, token)
53	}
54	for _, token := range tokens {
55		m, err := ParseMatcher(token)
56		if err != nil {
57			return nil, err
58		}
59		matchers = append(matchers, m)
60	}
61
62	return matchers, nil
63}
64
65func ParseMatcher(s string) (*Matcher, error) {
66	var (
67		name, value string
68		matchType   MatchType
69	)
70
71	ms := re.FindStringSubmatch(s)
72	if len(ms) < 4 {
73		return nil, fmt.Errorf("bad matcher format: %s", s)
74	}
75
76	name = ms[1]
77	if name == "" {
78		return nil, fmt.Errorf("failed to parse label name")
79	}
80
81	matchType, found := typeMap[ms[2]]
82	if !found {
83		return nil, fmt.Errorf("failed to find match operator")
84	}
85
86	if ms[3] != "" {
87		value = ms[3]
88	} else {
89		value = ms[4]
90	}
91
92	return NewMatcher(matchType, name, value)
93}
94