1
15
16 package rule
17
18 import (
19 "errors"
20 "fmt"
21 "log"
22 "sort"
23
24 bzl "github.com/bazelbuild/buildtools/build"
25 )
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 func MergeRules(src, dst *Rule, mergeable map[string]bool, filename string) {
45 if dst.ShouldKeep() {
46 return
47 }
48
49
50 for key, dstAttr := range dst.attrs {
51 if _, ok := src.attrs[key]; ok || !mergeable[key] || ShouldKeep(dstAttr.expr) {
52 continue
53 }
54 if mergedValue, err := mergeAttrValues(nil, &dstAttr); err != nil {
55 start, end := dstAttr.expr.RHS.Span()
56 log.Printf("%s:%d.%d-%d.%d: could not merge expression", filename, start.Line, start.LineRune, end.Line, end.LineRune)
57 } else if mergedValue == nil {
58 dst.DelAttr(key)
59 } else {
60 dst.SetAttr(key, mergedValue)
61 }
62 }
63
64
65 for key, srcAttr := range src.attrs {
66 if dstAttr, ok := dst.attrs[key]; !ok {
67 dst.SetAttr(key, srcAttr.expr.RHS)
68 } else if mergeable[key] && !ShouldKeep(dstAttr.expr) {
69 if mergedValue, err := mergeAttrValues(&srcAttr, &dstAttr); err != nil {
70 start, end := dstAttr.expr.RHS.Span()
71 log.Printf("%s:%d.%d-%d.%d: could not merge expression", filename, start.Line, start.LineRune, end.Line, end.LineRune)
72 } else if mergedValue == nil {
73 dst.DelAttr(key)
74 } else {
75 dst.SetAttr(key, mergedValue)
76 }
77 }
78 }
79
80 dst.private = src.private
81 }
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 func mergeAttrValues(srcAttr, dstAttr *attrValue) (bzl.Expr, error) {
101 if ShouldKeep(dstAttr.expr.RHS) {
102 return nil, nil
103 }
104 dst := dstAttr.expr.RHS
105 if srcAttr == nil && (dst == nil || isScalar(dst)) {
106 return nil, nil
107 }
108 if srcAttr != nil && isScalar(srcAttr.expr.RHS) {
109 return srcAttr.expr.RHS, nil
110 }
111
112 if _, ok := dstAttr.val.(Merger); srcAttr == nil && ok {
113 return nil, nil
114 }
115
116 if srcAttr != nil {
117 if srcMerger, ok := srcAttr.val.(Merger); ok {
118 return srcMerger.Merge(dst), nil
119 }
120 }
121 var srcExprs platformStringsExprs
122 var err error
123 if srcAttr != nil {
124 srcExprs, err = extractPlatformStringsExprs(srcAttr.expr.RHS)
125 if err != nil {
126 return nil, err
127 }
128 }
129
130 dstExprs, err := extractPlatformStringsExprs(dst)
131 if err != nil {
132 return nil, err
133 }
134 mergedExprs, err := mergePlatformStringsExprs(srcExprs, dstExprs)
135 if err != nil {
136 return nil, err
137 }
138 return makePlatformStringsExpr(mergedExprs), nil
139 }
140
141 func mergePlatformStringsExprs(src, dst platformStringsExprs) (platformStringsExprs, error) {
142 var ps platformStringsExprs
143 var err error
144 ps.generic = MergeList(src.generic, dst.generic)
145 if ps.os, err = MergeDict(src.os, dst.os); err != nil {
146 return platformStringsExprs{}, err
147 }
148 if ps.arch, err = MergeDict(src.arch, dst.arch); err != nil {
149 return platformStringsExprs{}, err
150 }
151 if ps.platform, err = MergeDict(src.platform, dst.platform); err != nil {
152 return platformStringsExprs{}, err
153 }
154 return ps, nil
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 func MergeList(srcExpr, dstExpr bzl.Expr) *bzl.ListExpr {
171 src, isSrcLis := srcExpr.(*bzl.ListExpr)
172 dst, isDstLis := dstExpr.(*bzl.ListExpr)
173 if !isSrcLis && !isDstLis {
174 return nil
175 }
176 if dst == nil {
177 return src
178 }
179 if src == nil {
180 src = &bzl.ListExpr{List: []bzl.Expr{}}
181 }
182
183
184
185
186 srcSet := make(map[string]bool)
187 for _, v := range src.List {
188 if s := stringValue(v); s != "" {
189 srcSet[s] = true
190 }
191 }
192
193 var merged []bzl.Expr
194 kept := make(map[string]bool)
195 keepComment := false
196 for _, v := range dst.List {
197 s := stringValue(v)
198 if keep := ShouldKeep(v); keep || srcSet[s] {
199 keepComment = keepComment || keep
200 merged = append(merged, v)
201 if s != "" {
202 kept[s] = true
203 }
204 }
205 }
206
207
208 for _, v := range src.List {
209 if s := stringValue(v); kept[s] {
210 continue
211 }
212 merged = append(merged, v)
213 }
214
215 if len(merged) == 0 {
216 return nil
217 }
218 return &bzl.ListExpr{
219 List: merged,
220 ForceMultiLine: src.ForceMultiLine || dst.ForceMultiLine || keepComment,
221 }
222 }
223
224
225
226
227
228
229
230
231 func MergeDict(srcExpr, dstExpr bzl.Expr) (*bzl.DictExpr, error) {
232 src, isSrcDict := srcExpr.(*bzl.DictExpr)
233 dst, isDstDict := dstExpr.(*bzl.DictExpr)
234 if !isSrcDict && !isDstDict {
235 return nil, fmt.Errorf("expected dict, got %s and %s", srcExpr, dstExpr)
236 }
237 if dst == nil {
238 return src, nil
239 }
240 if src == nil {
241 src = &bzl.DictExpr{List: []*bzl.KeyValueExpr{}}
242 }
243
244 var entries []*dictEntry
245 entryMap := make(map[string]*dictEntry)
246
247 for _, kv := range dst.List {
248 k, v, err := dictEntryKeyValue(kv)
249 if err != nil {
250 return nil, err
251 }
252 if _, ok := entryMap[k]; ok {
253 return nil, fmt.Errorf("dst dict contains more than one case named %q", k)
254 }
255 e := &dictEntry{key: k, dstValue: v}
256 entries = append(entries, e)
257 entryMap[k] = e
258 }
259
260 for _, kv := range src.List {
261 k, v, err := dictEntryKeyValue(kv)
262 if err != nil {
263 return nil, err
264 }
265 e, ok := entryMap[k]
266 if !ok {
267 e = &dictEntry{key: k}
268 entries = append(entries, e)
269 entryMap[k] = e
270 }
271 e.srcValue = v
272 }
273
274 keys := make([]string, 0, len(entries))
275 haveDefault := false
276 for _, e := range entries {
277 e.mergedValue = MergeList(e.srcValue, e.dstValue)
278 if e.key == "//conditions:default" {
279
280 haveDefault = true
281 if e.mergedValue == nil {
282 e.mergedValue = &bzl.ListExpr{}
283 }
284 } else if e.mergedValue != nil {
285 keys = append(keys, e.key)
286 }
287 }
288 if len(keys) == 0 && (!haveDefault || len(entryMap["//conditions:default"].mergedValue.List) == 0) {
289 return nil, nil
290 }
291 sort.Strings(keys)
292
293 if haveDefault {
294 keys = append(keys, "//conditions:default")
295 }
296
297 mergedEntries := make([]*bzl.KeyValueExpr, len(keys))
298 for i, k := range keys {
299 e := entryMap[k]
300 mergedEntries[i] = &bzl.KeyValueExpr{
301 Key: &bzl.StringExpr{Value: e.key},
302 Value: e.mergedValue,
303 }
304 }
305
306 return &bzl.DictExpr{List: mergedEntries, ForceMultiLine: true}, nil
307 }
308
309 type dictEntry struct {
310 key string
311 dstValue, srcValue, mergedValue *bzl.ListExpr
312 }
313
314
315
316
317
318
319 func SquashRules(src, dst *Rule, filename string) error {
320 if dst.ShouldKeep() {
321 return nil
322 }
323
324 for key, srcAttr := range src.attrs {
325 srcValue := srcAttr.expr.RHS
326 if dstAttr, ok := dst.attrs[key]; !ok {
327 dst.SetAttr(key, srcValue)
328 } else if !ShouldKeep(dstAttr.expr) {
329 dstValue := dstAttr.expr.RHS
330 if squashedValue, err := squashExprs(srcValue, dstValue); err != nil {
331 start, end := dstValue.Span()
332 return fmt.Errorf("%s:%d.%d-%d.%d: could not squash expression", filename, start.Line, start.LineRune, end.Line, end.LineRune)
333 } else {
334 dst.SetAttr(key, squashedValue)
335 }
336 }
337 }
338 dst.expr.Comment().Before = append(dst.expr.Comment().Before, src.expr.Comment().Before...)
339 dst.expr.Comment().Suffix = append(dst.expr.Comment().Suffix, src.expr.Comment().Suffix...)
340 dst.expr.Comment().After = append(dst.expr.Comment().After, src.expr.Comment().After...)
341 return nil
342 }
343
344 func squashExprs(src, dst bzl.Expr) (bzl.Expr, error) {
345 if ShouldKeep(dst) {
346 return dst, nil
347 }
348 if isScalar(dst) {
349
350 return dst, nil
351 }
352 srcExprs, err := extractPlatformStringsExprs(src)
353 if err != nil {
354 return nil, err
355 }
356 dstExprs, err := extractPlatformStringsExprs(dst)
357 if err != nil {
358 return nil, err
359 }
360 squashedExprs, err := squashPlatformStringsExprs(srcExprs, dstExprs)
361 if err != nil {
362 return nil, err
363 }
364 return makePlatformStringsExpr(squashedExprs), nil
365 }
366
367 func squashPlatformStringsExprs(x, y platformStringsExprs) (platformStringsExprs, error) {
368 var ps platformStringsExprs
369 var err error
370 if ps.generic, err = squashList(x.generic, y.generic); err != nil {
371 return platformStringsExprs{}, err
372 }
373 if ps.os, err = squashDict(x.os, y.os); err != nil {
374 return platformStringsExprs{}, err
375 }
376 if ps.arch, err = squashDict(x.arch, y.arch); err != nil {
377 return platformStringsExprs{}, err
378 }
379 if ps.platform, err = squashDict(x.platform, y.platform); err != nil {
380 return platformStringsExprs{}, err
381 }
382 return ps, nil
383 }
384
385 func squashList(x, y *bzl.ListExpr) (*bzl.ListExpr, error) {
386 if x == nil {
387 return y, nil
388 }
389 if y == nil {
390 return x, nil
391 }
392
393 ls := makeListSquasher()
394 for _, e := range x.List {
395 s, ok := e.(*bzl.StringExpr)
396 if !ok {
397 return nil, errors.New("could not squash non-string")
398 }
399 ls.add(s)
400 }
401 for _, e := range y.List {
402 s, ok := e.(*bzl.StringExpr)
403 if !ok {
404 return nil, errors.New("could not squash non-string")
405 }
406 ls.add(s)
407 }
408 squashed := ls.list()
409 squashed.Comments.Before = append(x.Comments.Before, y.Comments.Before...)
410 squashed.Comments.Suffix = append(x.Comments.Suffix, y.Comments.Suffix...)
411 squashed.Comments.After = append(x.Comments.After, y.Comments.After...)
412 return squashed, nil
413 }
414
415 func squashDict(x, y *bzl.DictExpr) (*bzl.DictExpr, error) {
416 if x == nil {
417 return y, nil
418 }
419 if y == nil {
420 return x, nil
421 }
422
423 cases := make(map[string]*bzl.KeyValueExpr)
424 addCase := func(e bzl.Expr) error {
425 kv := e.(*bzl.KeyValueExpr)
426 key, ok := kv.Key.(*bzl.StringExpr)
427 if !ok {
428 return errors.New("could not squash non-string dict key")
429 }
430 if _, ok := kv.Value.(*bzl.ListExpr); !ok {
431 return errors.New("could not squash non-list dict value")
432 }
433 if c, ok := cases[key.Value]; ok {
434 if sq, err := squashList(kv.Value.(*bzl.ListExpr), c.Value.(*bzl.ListExpr)); err != nil {
435 return err
436 } else {
437 c.Value = sq
438 }
439 } else {
440 kvCopy := *kv
441 cases[key.Value] = &kvCopy
442 }
443 return nil
444 }
445
446 for _, e := range x.List {
447 if err := addCase(e); err != nil {
448 return nil, err
449 }
450 }
451 for _, e := range y.List {
452 if err := addCase(e); err != nil {
453 return nil, err
454 }
455 }
456
457 keys := make([]string, 0, len(cases))
458 haveDefault := false
459 for k := range cases {
460 if k == "//conditions:default" {
461 haveDefault = true
462 continue
463 }
464 keys = append(keys, k)
465 }
466 sort.Strings(keys)
467 if haveDefault {
468 keys = append(keys, "//conditions:default")
469 }
470
471 squashed := *x
472 squashed.Comments.Before = append(x.Comments.Before, y.Comments.Before...)
473 squashed.Comments.Suffix = append(x.Comments.Suffix, y.Comments.Suffix...)
474 squashed.Comments.After = append(x.Comments.After, y.Comments.After...)
475 squashed.List = make([]*bzl.KeyValueExpr, 0, len(cases))
476 for _, k := range keys {
477 squashed.List = append(squashed.List, cases[k])
478 }
479 return &squashed, nil
480 }
481
482
483
484
485 type listSquasher struct {
486 unique map[string]*bzl.StringExpr
487 seenComments map[elemComment]bool
488 }
489
490 type elemComment struct {
491 elem, com string
492 }
493
494 func makeListSquasher() listSquasher {
495 return listSquasher{
496 unique: make(map[string]*bzl.StringExpr),
497 seenComments: make(map[elemComment]bool),
498 }
499 }
500
501 func (ls *listSquasher) add(s *bzl.StringExpr) {
502 sCopy, ok := ls.unique[s.Value]
503 if !ok {
504
505
506
507 sCopy = new(bzl.StringExpr)
508 *sCopy = *s
509 sCopy.Comments.Before = make([]bzl.Comment, 0, len(s.Comments.Before))
510 sCopy.Comments.Suffix = make([]bzl.Comment, 0, len(s.Comments.Suffix))
511 ls.unique[s.Value] = sCopy
512 }
513 for _, c := range s.Comment().Before {
514 if key := (elemComment{s.Value, c.Token}); !ls.seenComments[key] {
515 sCopy.Comments.Before = append(sCopy.Comments.Before, c)
516 ls.seenComments[key] = true
517 }
518 }
519 for _, c := range s.Comment().Suffix {
520 if key := (elemComment{s.Value, c.Token}); !ls.seenComments[key] {
521 sCopy.Comments.Suffix = append(sCopy.Comments.Suffix, c)
522 ls.seenComments[key] = true
523 }
524 }
525 }
526
527 func (ls *listSquasher) list() *bzl.ListExpr {
528 sortedExprs := make([]bzl.Expr, 0, len(ls.unique))
529 for _, e := range ls.unique {
530 sortedExprs = append(sortedExprs, e)
531 }
532 sort.Slice(sortedExprs, func(i, j int) bool {
533 return sortedExprs[i].(*bzl.StringExpr).Value < sortedExprs[j].(*bzl.StringExpr).Value
534 })
535 return &bzl.ListExpr{List: sortedExprs}
536 }
537
View as plain text