cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.55.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models.go

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