cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
baaaa2a8a4c537acd8ab3963accdf2ef0d39534e

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/parser/models.go

390lines · modecode

1package parser
2
3import (
4 "fmt"
5 "strconv"
6 "strings"
7
8 "golang.org/x/exp/slices"
9 "gopkg.in/yaml.v3"
10
11 promparser "github.com/prometheus/prometheus/promql/parser"
12
13 "github.com/cloudflare/pint/internal/comments"
14)
15
16func nodeLines(node *yaml.Node, offset int) (lr LineRange) {
17 switch {
18 case node.Value == "":
19 lr.First = node.Line + offset
20 case node.Style == yaml.LiteralStyle || node.Style == yaml.FoldedStyle:
21 lr.First = node.Line + 1 + offset
22 default:
23 lr.First = node.Line + offset
24 }
25 lr.Last = lr.First + len(strings.Split(strings.TrimSuffix(node.Value, "\n"), "\n")) - 1
26 return lr
27}
28
29func mergeComments(node *yaml.Node) (comments []string) {
30 if node.HeadComment != "" {
31 comments = append(comments, node.HeadComment)
32 }
33 if node.LineComment != "" {
34 comments = append(comments, node.LineComment)
35 }
36 if node.FootComment != "" {
37 comments = append(comments, node.FootComment)
38 }
39 for _, child := range node.Content {
40 comments = append(comments, mergeComments(child)...)
41 }
42 return comments
43}
44
45type YamlNode struct {
46 Value string
47 Lines LineRange
48}
49
50func (yn *YamlNode) IsIdentical(b *YamlNode) bool {
51 if (yn == nil) != (b == nil) {
52 return false
53 }
54 if yn == nil {
55 return true
56 }
57 if yn.Value != b.Value {
58 return false
59 }
60 return true
61}
62
63func newYamlNode(node *yaml.Node, offset int) *YamlNode {
64 n := YamlNode{
65 Lines: nodeLines(node, offset),
66 Value: node.Value,
67 }
68 if node.Alias != nil {
69 n.Value = node.Alias.Value
70 }
71 return &n
72}
73
74func newYamlNodeWithKey(key, node *yaml.Node, offset int) *YamlNode {
75 keyLines := nodeLines(key, offset)
76 valLines := nodeLines(node, offset)
77 n := YamlNode{
78 Lines: LineRange{
79 First: min(keyLines.First, valLines.First),
80 Last: max(keyLines.Last, valLines.Last),
81 },
82 Value: node.Value,
83 }
84 if node.Alias != nil {
85 n.Value = node.Alias.Value
86 }
87 return &n
88}
89
90type YamlKeyValue struct {
91 Key *YamlNode
92 Value *YamlNode
93}
94
95type YamlMap struct {
96 Key *YamlNode
97 Items []*YamlKeyValue
98 Lines LineRange
99}
100
101func (ym *YamlMap) IsIdentical(b *YamlMap) bool {
102 var al, bl []string
103
104 if ym != nil && ym.Items != nil {
105 al = make([]string, 0, len(ym.Items))
106 for _, kv := range ym.Items {
107 al = append(al, fmt.Sprintf("%s: %s", kv.Key.Value, kv.Value.Value))
108 }
109 slices.Sort(al)
110 }
111
112 if b != nil && b.Items != nil {
113 bl = make([]string, 0, len(b.Items))
114 for _, kv := range b.Items {
115 bl = append(bl, fmt.Sprintf("%s: %s", kv.Key.Value, kv.Value.Value))
116 }
117 slices.Sort(bl)
118 }
119
120 return slices.Equal(al, bl)
121}
122
123func (ym YamlMap) GetValue(key string) *YamlNode {
124 for _, child := range ym.Items {
125 if child.Key.Value == key {
126 return child.Value
127 }
128 }
129 return nil
130}
131
132func newYamlMap(key, value *yaml.Node, offset int) *YamlMap {
133 ym := YamlMap{
134 Lines: LineRange{
135 First: key.Line + offset,
136 Last: key.Line + offset,
137 },
138 Key: newYamlNode(key, offset),
139 }
140
141 var ckey *yaml.Node
142 for _, child := range value.Content {
143 if ckey != nil {
144 kv := YamlKeyValue{
145 Key: newYamlNode(ckey, offset),
146 Value: newYamlNode(child, offset),
147 }
148 if kv.Value.Lines.Last > ym.Lines.Last {
149 ym.Lines.Last = kv.Value.Lines.Last
150 }
151 ym.Items = append(ym.Items, &kv)
152 ckey = nil
153 } else {
154 ckey = child
155 }
156 }
157
158 return &ym
159}
160
161type PromQLNode struct {
162 Expr string
163 Node promparser.Expr
164 Children []*PromQLNode
165}
166
167type PromQLError struct {
168 node *PromQLNode
169 Err error
170}
171
172func (pqle PromQLError) Error() string {
173 return pqle.Err.Error()
174}
175
176func (pqle *PromQLError) Unwrap() error {
177 return pqle.Err
178}
179
180func (pqle PromQLError) Node() *PromQLNode {
181 return pqle.node
182}
183
184type PromQLExpr struct {
185 Value *YamlNode
186 SyntaxError error
187 Query *PromQLNode
188}
189
190func (pqle PromQLExpr) IsIdentical(b PromQLExpr) bool {
191 return pqle.Value.Value == b.Value.Value
192}
193
194func newPromQLExpr(key, val *yaml.Node, offset int) *PromQLExpr {
195 expr := PromQLExpr{
196 Value: newYamlNodeWithKey(key, val, offset),
197 }
198
199 qlNode, err := DecodeExpr(expr.Value.Value)
200 if err != nil {
201 expr.SyntaxError = err
202 return &expr
203
204 }
205 expr.Query = qlNode
206 return &expr
207}
208
209type AlertingRule struct {
210 Expr PromQLExpr
211 For *YamlNode
212 KeepFiringFor *YamlNode
213 Labels *YamlMap
214 Annotations *YamlMap
215 Alert YamlNode
216}
217
218func (ar *AlertingRule) IsIdentical(b *AlertingRule) bool {
219 if (ar == nil) != (b == nil) {
220 return false
221 }
222 if ar == nil {
223 return true
224 }
225 if !ar.Alert.IsIdentical(&b.Alert) {
226 return false
227 }
228 if !ar.Expr.IsIdentical(b.Expr) {
229 return false
230 }
231 if !ar.For.IsIdentical(b.For) {
232 return false
233 }
234 if !ar.KeepFiringFor.IsIdentical(b.KeepFiringFor) {
235 return false
236 }
237 if !ar.Labels.IsIdentical(b.Labels) {
238 return false
239 }
240 if !ar.Annotations.IsIdentical(b.Annotations) {
241 return false
242 }
243 return true
244}
245
246type RecordingRule struct {
247 Expr PromQLExpr
248 Labels *YamlMap
249 Record YamlNode
250}
251
252func (rr *RecordingRule) IsIdentical(b *RecordingRule) bool {
253 if (rr == nil) != (b == nil) {
254 return false
255 }
256 if rr == nil {
257 return true
258 }
259 if !rr.Record.IsIdentical(&b.Record) {
260 return false
261 }
262 if !rr.Expr.IsIdentical(b.Expr) {
263 return false
264 }
265 if !rr.Labels.IsIdentical(b.Labels) {
266 return false
267 }
268 return true
269}
270
271type ParseError struct {
272 Err error
273 Fragment string
274 Line int
275}
276
277type LineRange struct {
278 First int
279 Last int
280}
281
282func (lr LineRange) String() string {
283 if lr.First == lr.Last {
284 return strconv.Itoa(lr.First)
285 }
286 return fmt.Sprintf("%d-%d", lr.First, lr.Last)
287}
288
289func (lr LineRange) Expand() []int {
290 lines := make([]int, 0, lr.Last-lr.First+1)
291 for i := lr.First; i <= lr.Last; i++ {
292 lines = append(lines, i)
293 }
294 return lines
295}
296
297type Rule struct {
298 AlertingRule *AlertingRule
299 RecordingRule *RecordingRule
300 Error ParseError
301 Comments []comments.Comment
302 Lines LineRange
303}
304
305func (r Rule) IsIdentical(b Rule) bool {
306 if r.Type() != b.Type() {
307 return false
308 }
309 if !r.AlertingRule.IsIdentical(b.AlertingRule) {
310 return false
311 }
312 if !r.RecordingRule.IsIdentical(b.RecordingRule) {
313 return false
314 }
315
316 ac := make([]string, 0, len(r.Comments))
317 for _, c := range r.Comments {
318 ac = append(ac, c.Value.String())
319 }
320 slices.Sort(ac)
321
322 bc := make([]string, 0, len(r.Comments))
323 for _, c := range b.Comments {
324 bc = append(bc, c.Value.String())
325 }
326 slices.Sort(bc)
327
328 return slices.Equal(ac, bc)
329}
330
331func (r Rule) IsSame(nr Rule) bool {
332 if (r.AlertingRule != nil) != (nr.AlertingRule != nil) {
333 return false
334 }
335 if (r.RecordingRule != nil) != (nr.RecordingRule != nil) {
336 return false
337 }
338 if r.Error != nr.Error {
339 return false
340 }
341 if r.Lines.First != nr.Lines.First {
342 return false
343 }
344 if r.Lines.Last != nr.Lines.Last {
345 return false
346 }
347 return true
348}
349
350func (r Rule) Name() string {
351 if r.RecordingRule != nil {
352 return r.RecordingRule.Record.Value
353 }
354 if r.AlertingRule != nil {
355 return r.AlertingRule.Alert.Value
356 }
357 return ""
358}
359
360func (r Rule) Expr() PromQLExpr {
361 if r.RecordingRule != nil {
362 return r.RecordingRule.Expr
363 }
364 return r.AlertingRule.Expr
365}
366
367type RuleType string
368
369const (
370 AlertingRuleType RuleType = "alerting"
371 RecordingRuleType RuleType = "recording"
372 InvalidRuleType RuleType = "invalid"
373)
374
375func (r Rule) Type() RuleType {
376 if r.AlertingRule != nil {
377 return AlertingRuleType
378 }
379 if r.RecordingRule != nil {
380 return RecordingRuleType
381 }
382 return InvalidRuleType
383}
384
385type Result struct {
386 Path string
387 Error error
388 Content []byte
389 Rules []Rule
390}