1
15
16
17
18
19
20
21
22
23
24
25
26 package rule
27
28 import (
29 "fmt"
30 "io/fs"
31 "os"
32 "path/filepath"
33 "sort"
34 "strings"
35
36 bzl "github.com/bazelbuild/buildtools/build"
37 bt "github.com/bazelbuild/buildtools/tables"
38 )
39
40
41
42
43 type File struct {
44
45
46 File *bzl.File
47
48
49
50
51 function *function
52
53
54 Pkg string
55
56
57 Path string
58
59
60
61 DefName string
62
63
64
65 Directives []Directive
66
67
68
69 Loads []*Load
70
71
72
73 Rules []*Rule
74
75
76
77
78
79 Content []byte
80 }
81
82
83 func EmptyFile(path, pkg string) *File {
84 return &File{
85 File: &bzl.File{Path: path, Type: bzl.TypeBuild},
86 Path: path,
87 Pkg: pkg,
88 }
89 }
90
91
92
93
94
95
96
97 func LoadFile(path, pkg string) (*File, error) {
98 data, err := os.ReadFile(path)
99 if err != nil {
100 return nil, err
101 }
102 return LoadData(path, pkg, data)
103 }
104
105
106
107 func LoadWorkspaceFile(path, pkg string) (*File, error) {
108 data, err := os.ReadFile(path)
109 if err != nil {
110 return nil, err
111 }
112 return LoadWorkspaceData(path, pkg, data)
113 }
114
115
116
117
118
119
120 func LoadMacroFile(path, pkg, defName string) (*File, error) {
121 data, err := os.ReadFile(path)
122 if err != nil {
123 return nil, err
124 }
125 return LoadMacroData(path, pkg, defName, data)
126 }
127
128
129
130
131 func EmptyMacroFile(path, pkg, defName string) (*File, error) {
132 _, err := os.Create(path)
133 if err != nil {
134 return nil, err
135 }
136 return LoadMacroData(path, pkg, defName, nil)
137 }
138
139
140
141
142 func LoadData(path, pkg string, data []byte) (*File, error) {
143 ast, err := bzl.ParseBuild(path, data)
144 if err != nil {
145 return nil, err
146 }
147 f := ScanAST(pkg, ast)
148 if err := checkFile(f); err != nil {
149 return nil, err
150 }
151 f.Content = data
152 return f, nil
153 }
154
155
156
157 func LoadWorkspaceData(path, pkg string, data []byte) (*File, error) {
158 ast, err := bzl.ParseWorkspace(path, data)
159 if err != nil {
160 return nil, err
161 }
162 f := ScanAST(pkg, ast)
163 if err := checkFile(f); err != nil {
164 return nil, err
165 }
166 f.Content = data
167 return f, nil
168 }
169
170
171
172
173
174
175 func LoadMacroData(path, pkg, defName string, data []byte) (*File, error) {
176 ast, err := bzl.ParseBzl(path, data)
177 if err != nil {
178 return nil, err
179 }
180 f := ScanASTBody(pkg, defName, ast)
181 if err := checkFile(f); err != nil {
182 return nil, err
183 }
184 f.Content = data
185 return f, nil
186 }
187
188
189
190 func ScanAST(pkg string, bzlFile *bzl.File) *File {
191 return ScanASTBody(pkg, "", bzlFile)
192 }
193
194 type function struct {
195 stmt *bzl.DefStmt
196 inserted, hasPass bool
197 }
198
199
200
201
202
203 func ScanASTBody(pkg, defName string, bzlFile *bzl.File) *File {
204 f := &File{
205 File: bzlFile,
206 Pkg: pkg,
207 Path: bzlFile.Path,
208 DefName: defName,
209 }
210 var defStmt *bzl.DefStmt
211 f.Rules, f.Loads, defStmt = scanExprs(defName, bzlFile.Stmt)
212 if defStmt != nil {
213 f.Rules, _, _ = scanExprs("", defStmt.Body)
214 f.function = &function{
215 stmt: defStmt,
216 inserted: true,
217 }
218 if len(defStmt.Body) == 1 {
219 if v, ok := defStmt.Body[0].(*bzl.BranchStmt); ok && v.Token == "pass" {
220 f.function.hasPass = true
221 }
222 }
223 } else if defName != "" {
224 f.function = &function{
225 stmt: &bzl.DefStmt{Name: defName},
226 inserted: false,
227 }
228 }
229 if f.function != nil {
230 f.Directives = ParseDirectivesFromMacro(f.function.stmt)
231 } else {
232 f.Directives = ParseDirectives(bzlFile)
233 }
234 return f
235 }
236
237 func scanExprs(defName string, stmt []bzl.Expr) (rules []*Rule, loads []*Load, fn *bzl.DefStmt) {
238 for i, expr := range stmt {
239 switch expr := expr.(type) {
240 case *bzl.LoadStmt:
241 l := loadFromExpr(i, expr)
242 loads = append(loads, l)
243 case *bzl.CallExpr:
244 if r := ruleFromExpr(i, expr); r != nil {
245 rules = append(rules, r)
246 }
247 case *bzl.DefStmt:
248 if expr.Name == defName {
249 fn = expr
250 }
251 }
252 }
253 return rules, loads, fn
254 }
255
256
257
258
259
260 func MatchBuildFile(dir string, names []string, ents []fs.DirEntry) string {
261 for _, name := range names {
262 for _, ent := range ents {
263 if ent.Name() == name && !ent.IsDir() {
264 return filepath.Join(dir, name)
265 }
266 }
267 }
268 return ""
269 }
270
271
272 func MatchBuildFileName(dir string, names []string, files []os.FileInfo) string {
273 for _, name := range names {
274 for _, fi := range files {
275 if fi.Name() == name && !fi.IsDir() {
276 return filepath.Join(dir, name)
277 }
278 }
279 }
280 return ""
281 }
282
283
284
285 func (f *File) SyncMacroFile(from *File) {
286 fromFunc := *from.function.stmt
287 _, _, toFunc := scanExprs(from.function.stmt.Name, f.File.Stmt)
288 if toFunc != nil {
289 *toFunc = fromFunc
290 } else {
291 f.File.Stmt = append(f.File.Stmt, &fromFunc)
292 }
293 }
294
295
296
297 func (f *File) MacroName() string {
298 if f.function != nil && f.function.stmt != nil {
299 return f.function.stmt.Name
300 }
301 return ""
302 }
303
304
305
306 func (f *File) Sync() {
307 var loadInserts, loadDeletes, loadStmts []*stmt
308 var r, w int
309 for r, w = 0, 0; r < len(f.Loads); r++ {
310 s := f.Loads[r]
311 s.sync()
312 if s.deleted {
313 loadDeletes = append(loadDeletes, &s.stmt)
314 continue
315 }
316 if s.inserted {
317 loadInserts = append(loadInserts, &s.stmt)
318 s.inserted = false
319 } else {
320 loadStmts = append(loadStmts, &s.stmt)
321 }
322 f.Loads[w] = s
323 w++
324 }
325 f.Loads = f.Loads[:w]
326 var ruleInserts, ruleDeletes, ruleStmts []*stmt
327 for r, w = 0, 0; r < len(f.Rules); r++ {
328 s := f.Rules[r]
329 s.sync()
330 if s.deleted {
331 ruleDeletes = append(ruleDeletes, &s.stmt)
332 continue
333 }
334 if s.inserted {
335 ruleInserts = append(ruleInserts, &s.stmt)
336 s.inserted = false
337 } else {
338 ruleStmts = append(ruleStmts, &s.stmt)
339 }
340 f.Rules[w] = s
341 w++
342 }
343 f.Rules = f.Rules[:w]
344
345 if f.function == nil {
346 deletes := append(loadDeletes, ruleDeletes...)
347 inserts := append(loadInserts, ruleInserts...)
348 stmts := append(loadStmts, ruleStmts...)
349 updateStmt(&f.File.Stmt, inserts, deletes, stmts)
350 } else {
351 updateStmt(&f.File.Stmt, loadInserts, loadDeletes, loadStmts)
352 if f.function.hasPass && len(ruleInserts) > 0 {
353 f.function.stmt.Body = []bzl.Expr{}
354 f.function.hasPass = false
355 }
356 updateStmt(&f.function.stmt.Body, ruleInserts, ruleDeletes, ruleStmts)
357 if len(f.function.stmt.Body) == 0 {
358 f.function.stmt.Body = append(f.function.stmt.Body, &bzl.BranchStmt{Token: "pass"})
359 f.function.hasPass = true
360 }
361 if !f.function.inserted {
362 f.File.Stmt = append(f.File.Stmt, f.function.stmt)
363 f.function.inserted = true
364 }
365 }
366 }
367
368 func updateStmt(oldStmt *[]bzl.Expr, inserts, deletes, stmts []*stmt) {
369 sort.Stable(byIndex(deletes))
370 sort.Stable(byIndex(inserts))
371 sort.Stable(byIndex(stmts))
372 cap := len(*oldStmt) - len(deletes) + len(inserts)
373 if cap < 0 {
374 cap = 0
375 }
376 newStmt := make([]bzl.Expr, 0, cap)
377 var ii, di, si int
378 for i, stmt := range *oldStmt {
379 for ii < len(inserts) && inserts[ii].index == i {
380 inserts[ii].index = len(newStmt)
381 newStmt = append(newStmt, inserts[ii].expr)
382 ii++
383 }
384 if di < len(deletes) && deletes[di].index == i {
385 di++
386 continue
387 }
388 if si < len(stmts) && stmts[si].expr == stmt {
389 stmts[si].index = len(newStmt)
390 si++
391 }
392 newStmt = append(newStmt, stmt)
393 }
394 for ii < len(inserts) {
395 inserts[ii].index = len(newStmt)
396 newStmt = append(newStmt, inserts[ii].expr)
397 ii++
398 }
399 *oldStmt = newStmt
400 }
401
402
403
404 func (f *File) Format() []byte {
405 f.Sync()
406 return bzl.Format(f.File)
407 }
408
409
410
411
412 func (f *File) SortMacro() {
413 f.Sync()
414
415 if f.function == nil {
416 panic(fmt.Sprintf("%s: not loaded as macro file", f.Path))
417 }
418
419 sort.Stable(loadsByName{f.Loads, f.File.Stmt})
420 sort.Stable(rulesByKindAndName{f.Rules, f.function.stmt.Body})
421 }
422
423
424 func (f *File) Save(path string) error {
425 f.Sync()
426 f.Content = bzl.Format(f.File)
427 return os.WriteFile(path, f.Content, 0o666)
428 }
429
430
431
432
433 func (f *File) HasDefaultVisibility() bool {
434 for _, r := range f.Rules {
435 if r.Kind() == "package" && r.Attr("default_visibility") != nil {
436 return true
437 }
438 }
439 return false
440 }
441
442 type stmt struct {
443 index int
444 deleted, inserted, updated bool
445 comments []string
446 commentsUpdated bool
447 expr bzl.Expr
448 }
449
450
451
452
453
454 func (s *stmt) Index() int { return s.index }
455
456
457
458 func (s *stmt) Delete() { s.deleted = true }
459
460
461
462 func (s *stmt) Comments() []string {
463 return s.comments
464 }
465
466
467
468 func (s *stmt) AddComment(token string) {
469 if !strings.HasPrefix(token, "#") {
470 panic(fmt.Sprintf("comment must start with '#': got %q", token))
471 }
472 s.comments = append(s.comments, token)
473 s.commentsUpdated = true
474 }
475
476 func commentsFromExpr(e bzl.Expr) []string {
477 before := e.Comment().Before
478 tokens := make([]string, len(before))
479 for i, c := range before {
480 tokens[i] = c.Token
481 }
482 return tokens
483 }
484
485 func (s *stmt) syncComments() {
486 if !s.commentsUpdated {
487 return
488 }
489 s.commentsUpdated = false
490 before := make([]bzl.Comment, len(s.comments))
491 for i, token := range s.comments {
492 before[i].Token = token
493 }
494 s.expr.Comment().Before = before
495 }
496
497 type byIndex []*stmt
498
499 func (s byIndex) Len() int {
500 return len(s)
501 }
502
503 func (s byIndex) Less(i, j int) bool {
504 return s[i].index < s[j].index
505 }
506
507 func (s byIndex) Swap(i, j int) {
508 s[i], s[j] = s[j], s[i]
509 }
510
511 type rulesByKindAndName struct {
512 rules []*Rule
513 exprs []bzl.Expr
514 }
515
516
517 var _ sort.Interface = rulesByKindAndName{}
518
519 func (s rulesByKindAndName) Len() int {
520 return len(s.rules)
521 }
522
523 func (s rulesByKindAndName) Less(i, j int) bool {
524 if s.rules[i].Kind() == s.rules[j].Kind() {
525 return s.rules[i].Name() < s.rules[j].Name()
526 }
527 return s.rules[i].Kind() < s.rules[j].Kind()
528 }
529
530 func (s rulesByKindAndName) Swap(i, j int) {
531 s.exprs[s.rules[i].index], s.exprs[s.rules[j].index] = s.exprs[s.rules[j].index], s.exprs[s.rules[i].index]
532 s.rules[i].index, s.rules[j].index = s.rules[j].index, s.rules[i].index
533 s.rules[i], s.rules[j] = s.rules[j], s.rules[i]
534 }
535
536 type loadsByName struct {
537 loads []*Load
538 exprs []bzl.Expr
539 }
540
541
542 var _ sort.Interface = loadsByName{}
543
544 func (s loadsByName) Len() int {
545 return len(s.loads)
546 }
547
548 func (s loadsByName) Less(i, j int) bool {
549 return s.loads[i].Name() < s.loads[j].Name()
550 }
551
552 func (s loadsByName) Swap(i, j int) {
553 s.exprs[s.loads[i].index], s.exprs[s.loads[j].index] = s.exprs[s.loads[j].index], s.exprs[s.loads[i].index]
554 s.loads[i].index, s.loads[j].index = s.loads[j].index, s.loads[i].index
555 s.loads[i], s.loads[j] = s.loads[j], s.loads[i]
556 }
557
558
559
560 type identPair struct {
561 to, from *bzl.Ident
562 }
563
564
565 type Load struct {
566 stmt
567 name string
568 symbols map[string]identPair
569 }
570
571
572 func NewLoad(name string) *Load {
573 return &Load{
574 stmt: stmt{
575 expr: &bzl.LoadStmt{
576 Module: &bzl.StringExpr{Value: name},
577 ForceCompact: true,
578 },
579 },
580 name: name,
581 symbols: make(map[string]identPair),
582 }
583 }
584
585 func loadFromExpr(index int, loadStmt *bzl.LoadStmt) *Load {
586 l := &Load{
587 stmt: stmt{
588 index: index,
589 expr: loadStmt,
590 comments: commentsFromExpr(loadStmt),
591 },
592 name: loadStmt.Module.Value,
593 symbols: make(map[string]identPair),
594 }
595 for i := range loadStmt.From {
596 to, from := loadStmt.To[i], loadStmt.From[i]
597 l.symbols[to.Name] = identPair{to: to, from: from}
598 }
599 return l
600 }
601
602
603 func (l *Load) Name() string {
604 return l.name
605 }
606
607
608
609
610 func (l *Load) Symbols() []string {
611 syms := make([]string, 0, len(l.symbols))
612 for sym := range l.symbols {
613 syms = append(syms, sym)
614 }
615 sort.Strings(syms)
616 return syms
617 }
618
619
620
621
622
623 func (l *Load) SymbolPairs() []struct{ From, To string } {
624 toSyms := l.Symbols()
625 pairs := make([]struct{ From, To string }, 0, len(toSyms))
626 for _, toSym := range toSyms {
627 pairs = append(pairs, struct{ From, To string }{l.symbols[toSym].from.Name, toSym})
628 }
629 return pairs
630 }
631
632
633 func (l *Load) Has(sym string) bool {
634 _, ok := l.symbols[sym]
635 return ok
636 }
637
638
639 func (l *Load) Unalias(sym string) string {
640 return l.symbols[sym].from.Name
641 }
642
643
644
645
646 func (l *Load) Add(sym string) {
647 if _, ok := l.symbols[sym]; !ok {
648 i := &bzl.Ident{Name: sym}
649 l.symbols[sym] = identPair{to: i, from: i}
650 l.updated = true
651 }
652 }
653
654
655
656
657 func (l *Load) AddAlias(sym, to string) {
658 if _, ok := l.symbols[sym]; !ok {
659 l.symbols[sym] = identPair{
660 to: &bzl.Ident{Name: to},
661 from: &bzl.Ident{Name: sym},
662 }
663 l.updated = true
664 }
665 }
666
667
668
669 func (l *Load) Remove(sym string) {
670 if _, ok := l.symbols[sym]; ok {
671 delete(l.symbols, sym)
672 l.updated = true
673 }
674 }
675
676
677 func (l *Load) IsEmpty() bool {
678 return len(l.symbols) == 0
679 }
680
681
682
683
684 func (l *Load) Insert(f *File, index int) {
685 l.index = index
686 l.inserted = true
687 f.Loads = append(f.Loads, l)
688 }
689
690 func (l *Load) sync() {
691 l.syncComments()
692 if !l.updated {
693 return
694 }
695 l.updated = false
696
697
698 var args1, args2, args []string
699 for sym, pair := range l.symbols {
700 if pair.from.Name == pair.to.Name {
701 args1 = append(args1, sym)
702 } else {
703 args2 = append(args2, sym)
704 }
705 }
706 sort.Strings(args1)
707 sort.Strings(args2)
708 args = append(args, args1...)
709 args = append(args, args2...)
710
711 loadStmt := l.expr.(*bzl.LoadStmt)
712 loadStmt.Module.Value = l.name
713 loadStmt.From = make([]*bzl.Ident, 0, len(args))
714 loadStmt.To = make([]*bzl.Ident, 0, len(args))
715 for _, sym := range args {
716 pair := l.symbols[sym]
717 loadStmt.From = append(loadStmt.From, pair.from)
718 loadStmt.To = append(loadStmt.To, pair.to)
719 if pair.from.Name != pair.to.Name {
720 loadStmt.ForceCompact = false
721 }
722 }
723 }
724
725
726 type Rule struct {
727 stmt
728 kind bzl.Expr
729 args []bzl.Expr
730 attrs map[string]attrValue
731 private map[string]interface{}
732 sortedAttrs []string
733 }
734
735 type attrValue struct {
736
737
738 expr *bzl.AssignExpr
739
740
741 val interface{}
742 }
743
744
745 func NewRule(kind, name string) *Rule {
746 kindIdent := createDotExpr(kind)
747 call := &bzl.CallExpr{X: kindIdent}
748
749 r := &Rule{
750 stmt: stmt{expr: call},
751 kind: kindIdent,
752 attrs: map[string]attrValue{},
753 private: map[string]interface{}{},
754 sortedAttrs: []string{"deps", "srcs"},
755 }
756 if name != "" {
757 nameAttr := attrValue{
758 expr: &bzl.AssignExpr{
759 LHS: &bzl.Ident{Name: "name"},
760 RHS: &bzl.StringExpr{Value: name},
761 Op: "=",
762 },
763 val: name}
764 call.List = []bzl.Expr{nameAttr.expr}
765 r.attrs["name"] = nameAttr
766 }
767 return r
768 }
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787 func createDotExpr(kind string) bzl.Expr {
788 var expr bzl.Expr
789 parts := strings.Split(kind, ".")
790
791 if len(parts) > 1 {
792
793 var dotExpr *bzl.DotExpr = &bzl.DotExpr{Name: parts[len(parts)-1]}
794
795 _pDot := dotExpr
796
797 for idx := len(parts) - 2; idx > 0; idx-- {
798 d := &bzl.DotExpr{Name: parts[idx]}
799 _pDot.X = d
800 _pDot = d
801 }
802
803
804 _pDot.X = &bzl.Ident{Name: parts[0]}
805 expr = dotExpr
806 } else {
807 expr = &bzl.Ident{Name: kind}
808 }
809
810 return expr
811 }
812
813 func isNestedDotOrIdent(expr bzl.Expr) bool {
814 if _, ok := expr.(*bzl.Ident); ok {
815 return true
816 }
817
818 dot, ok := expr.(*bzl.DotExpr)
819 if !ok {
820 return false
821 }
822
823 return isNestedDotOrIdent(dot.X)
824 }
825
826 func ruleFromExpr(index int, expr bzl.Expr) *Rule {
827 call, ok := expr.(*bzl.CallExpr)
828 if !ok {
829 return nil
830 }
831
832 kind := call.X
833 if !isNestedDotOrIdent(kind) {
834 return nil
835 }
836
837 var args []bzl.Expr
838 attrs := make(map[string]attrValue, len(call.List))
839 for _, arg := range call.List {
840 if attr, ok := arg.(*bzl.AssignExpr); ok {
841 key := attr.LHS.(*bzl.Ident)
842 attrs[key.Name] = attrValue{expr: attr}
843 } else {
844 args = append(args, arg)
845 }
846 }
847 return &Rule{
848 stmt: stmt{
849 index: index,
850 expr: call,
851 comments: commentsFromExpr(expr),
852 },
853 kind: kind,
854 args: args,
855 attrs: attrs,
856 private: map[string]interface{}{},
857 }
858 }
859
860
861
862
863 func (r *Rule) ShouldKeep() bool {
864 return ShouldKeep(r.expr)
865 }
866
867
868 func (r *Rule) Kind() string {
869 return bzl.FormatString(r.kind)
870 }
871
872
873 func (r *Rule) SetKind(kind string) {
874 r.kind = &bzl.Ident{Name: kind}
875 r.updated = true
876 }
877
878
879
880 func (r *Rule) Name() string {
881 return r.AttrString("name")
882 }
883
884
885 func (r *Rule) SetName(name string) {
886 r.SetAttr("name", name)
887 }
888
889
890 func (r *Rule) AttrKeys() []string {
891 keys := make([]string, 0, len(r.attrs))
892 for k := range r.attrs {
893 keys = append(keys, k)
894 }
895 sort.SliceStable(keys, func(i, j int) bool {
896 if cmp := bt.NamePriority[keys[i]] - bt.NamePriority[keys[j]]; cmp != 0 {
897 return cmp < 0
898 }
899 return keys[i] < keys[j]
900 })
901 return keys
902 }
903
904
905
906 func (r *Rule) Attr(key string) bzl.Expr {
907 attr, ok := r.attrs[key]
908 if !ok {
909 return nil
910 }
911 return attr.expr.RHS
912 }
913
914
915
916 func (r *Rule) AttrString(key string) string {
917 attr, ok := r.attrs[key]
918 if !ok {
919 return ""
920 }
921 str, ok := attr.expr.RHS.(*bzl.StringExpr)
922 if !ok {
923 return ""
924 }
925 return str.Value
926 }
927
928
929
930
931 func (r *Rule) AttrStrings(key string) []string {
932 attr, ok := r.attrs[key]
933 if !ok {
934 return nil
935 }
936 list, ok := attr.expr.RHS.(*bzl.ListExpr)
937 if !ok {
938 return nil
939 }
940 strs := make([]string, 0, len(list.List))
941 for _, e := range list.List {
942 if str, ok := e.(*bzl.StringExpr); ok {
943 strs = append(strs, str.Value)
944 }
945 }
946 return strs
947 }
948
949
950 func (r *Rule) DelAttr(key string) {
951 delete(r.attrs, key)
952 r.updated = true
953 }
954
955
956
957
958 func (r *Rule) SetAttr(key string, value interface{}) {
959 rhs := ExprFromValue(value)
960 if attr, ok := r.attrs[key]; ok {
961 attr.expr.RHS = rhs
962 attr.val = value
963 } else {
964 r.attrs[key] = attrValue{
965 expr: &bzl.AssignExpr{
966 LHS: &bzl.Ident{Name: key},
967 RHS: rhs,
968 Op: "=",
969 },
970 val: value,
971 }
972 }
973 r.updated = true
974 }
975
976
977
978 func (r *Rule) AttrComments(key string) *bzl.Comments {
979 attr, ok := r.attrs[key]
980 if !ok {
981 return nil
982 }
983 return attr.expr.Comment()
984 }
985
986
987 func (r *Rule) PrivateAttrKeys() []string {
988 keys := make([]string, 0, len(r.private))
989 for k := range r.private {
990 keys = append(keys, k)
991 }
992 sort.Strings(keys)
993 return keys
994 }
995
996
997 func (r *Rule) PrivateAttr(key string) interface{} {
998 return r.private[key]
999 }
1000
1001
1002
1003
1004 func (r *Rule) SetPrivateAttr(key string, value interface{}) {
1005 r.private[key] = value
1006 }
1007
1008
1009 func (r *Rule) Args() []bzl.Expr {
1010 return r.args
1011 }
1012
1013
1014 func (r *Rule) AddArg(value bzl.Expr) {
1015 r.args = append(r.args, value)
1016 r.updated = true
1017 }
1018
1019
1020 func (r *Rule) SortedAttrs() []string {
1021 return r.sortedAttrs
1022 }
1023
1024
1025 func (r *Rule) SetSortedAttrs(keys []string) {
1026 r.sortedAttrs = keys
1027 r.updated = true
1028 }
1029
1030
1031
1032 func (r *Rule) Insert(f *File) {
1033 var stmt []bzl.Expr
1034 if f.function == nil {
1035 stmt = f.File.Stmt
1036 } else {
1037 stmt = f.function.stmt.Body
1038 }
1039 r.InsertAt(f, len(stmt))
1040 }
1041
1042
1043
1044
1045 func (r *Rule) InsertAt(f *File, index int) {
1046 r.index = index
1047 r.inserted = true
1048 f.Rules = append(f.Rules, r)
1049 }
1050
1051
1052
1053
1054 func (r *Rule) IsEmpty(info KindInfo) bool {
1055 if info.NonEmptyAttrs == nil {
1056 return false
1057 }
1058 for k := range info.NonEmptyAttrs {
1059 if _, ok := r.attrs[k]; ok {
1060 return false
1061 }
1062 }
1063 return true
1064 }
1065
1066 func (r *Rule) sync() {
1067 r.syncComments()
1068 if !r.updated {
1069 return
1070 }
1071 r.updated = false
1072
1073 for _, k := range r.sortedAttrs {
1074 attr, ok := r.attrs[k]
1075 _, isUnsorted := attr.val.(UnsortedStrings)
1076 if ok && !isUnsorted {
1077 bzl.Walk(attr.expr.RHS, sortExprLabels)
1078 }
1079 }
1080
1081 call := r.expr.(*bzl.CallExpr)
1082
1083
1084 call.X = createDotExpr(r.Kind())
1085
1086 if len(r.attrs) > 1 {
1087 call.ForceMultiLine = true
1088 }
1089
1090 list := make([]bzl.Expr, 0, len(r.args)+len(r.attrs))
1091 list = append(list, r.args...)
1092 for _, attr := range r.attrs {
1093 list = append(list, attr.expr)
1094 }
1095 sortedAttrs := list[len(r.args):]
1096 key := func(e bzl.Expr) string { return e.(*bzl.AssignExpr).LHS.(*bzl.Ident).Name }
1097 sort.SliceStable(sortedAttrs, func(i, j int) bool {
1098 ki := key(sortedAttrs[i])
1099 kj := key(sortedAttrs[j])
1100 if cmp := bt.NamePriority[ki] - bt.NamePriority[kj]; cmp != 0 {
1101 return cmp < 0
1102 }
1103 return ki < kj
1104 })
1105
1106 call.List = list
1107 r.updated = false
1108 }
1109
1110
1111
1112 func ShouldKeep(e bzl.Expr) bool {
1113 for _, c := range append(e.Comment().Before, e.Comment().Suffix...) {
1114 text := strings.TrimSpace(strings.TrimPrefix(c.Token, "#"))
1115 if text == "keep" || strings.HasPrefix(text, "keep: ") {
1116 return true
1117 }
1118 }
1119 return false
1120 }
1121
1122
1123
1124 func CheckInternalVisibility(rel, visibility string) string {
1125 if strings.HasSuffix(rel, "/internal") {
1126 visibility = fmt.Sprintf("//%s:__subpackages__", rel[:len(rel)-len("/internal")])
1127 } else if i := strings.LastIndex(rel, "/internal/"); i >= 0 {
1128 visibility = fmt.Sprintf("//%s:__subpackages__", rel[:i])
1129 } else if strings.HasPrefix(rel, "internal/") || rel == "internal" {
1130 visibility = "//:__subpackages__"
1131 }
1132 return visibility
1133 }
1134
1135 type byAttrName []KeyValue
1136
1137 var _ sort.Interface = byAttrName{}
1138
1139 func (s byAttrName) Len() int {
1140 return len(s)
1141 }
1142
1143 func (s byAttrName) Less(i, j int) bool {
1144 if cmp := bt.NamePriority[s[i].Key] - bt.NamePriority[s[j].Key]; cmp != 0 {
1145 return cmp < 0
1146 }
1147 return s[i].Key < s[j].Key
1148 }
1149
1150 func (s byAttrName) Swap(i, j int) {
1151 s[i], s[j] = s[j], s[i]
1152 }
1153
1154 func checkFile(f *File) error {
1155 names := make(map[string]bool)
1156 for _, r := range f.Rules {
1157 name := r.Name()
1158 if name == "" {
1159 continue
1160 }
1161 if names[name] {
1162 return fmt.Errorf("%s: multiple rules have the name %q", f.Path, name)
1163 }
1164 names[name] = true
1165 }
1166 return nil
1167 }
1168
View as plain text