github.com/please-build/puku@v1.7.3-0.20240516143641-f7d7f4941f57/generate/rule.go (about) 1 package generate 2 3 import ( 4 "github.com/please-build/buildtools/build" 5 6 "github.com/please-build/puku/edit" 7 "github.com/please-build/puku/kinds" 8 ) 9 10 type rule struct { 11 dir string 12 kind *kinds.Kind 13 *build.Rule 14 } 15 16 // setOrDeleteAttr will make sure the attribute with the given name matches the values passed in. It will keep the 17 // existing expressions in the list to maintain things like comments. 18 func (rule *rule) setOrDeleteAttr(name string, values []string) { 19 if len(values) == 0 { 20 rule.DelAttr(name) 21 return 22 } 23 24 valuesMap := make(map[string]struct{}) 25 for _, v := range values { 26 valuesMap[v] = struct{}{} 27 } 28 29 listExpr, _ := rule.Attr(name).(*build.ListExpr) 30 if listExpr == nil { 31 listExpr = &build.ListExpr{} 32 } 33 34 exprs := make([]build.Expr, 0, len(values)) 35 done := map[string]struct{}{} 36 37 // Loop through the existing values, filtering out any that aren't supposed to be there 38 for _, expr := range listExpr.List { 39 val, ok := expr.(*build.StringExpr) 40 if !ok { 41 continue 42 } 43 if _, ok := valuesMap[val.Value]; ok { 44 exprs = append(exprs, val) 45 done[val.Value] = struct{}{} 46 } 47 } 48 49 // Loops through the value adding any new values that didn't used to be there 50 for _, v := range values { 51 if _, done := done[v]; !done { 52 exprs = append(exprs, edit.NewStringExpr(v)) 53 } 54 } 55 56 listExpr.List = exprs 57 rule.SetAttr(name, listExpr) 58 } 59 60 func (rule *rule) isTest() bool { 61 return rule.kind.Type == kinds.Test 62 } 63 64 func (rule *rule) SrcsAttr() string { 65 return rule.kind.SrcsAttr 66 } 67 68 func (rule *rule) addSrc(src string) { 69 srcsAttr := rule.SrcsAttr() 70 srcs := rule.AttrStrings(srcsAttr) 71 rule.setOrDeleteAttr(srcsAttr, append(srcs, src)) 72 } 73 74 func (rule *rule) removeSrc(rem string) { 75 srcsAttr := rule.SrcsAttr() 76 srcs := rule.AttrStrings(srcsAttr) 77 set := make([]string, 0, len(srcs)) 78 for _, src := range srcs { 79 if src != rem { 80 set = append(set, src) 81 } 82 } 83 rule.setOrDeleteAttr(srcsAttr, set) 84 } 85 86 func (rule *rule) setExternal() { 87 rule.SetAttr("external", &build.Ident{Name: "True"}) 88 } 89 90 func (rule *rule) localLabel() string { 91 return ":" + rule.Name() 92 } 93 94 func (rule *rule) label() string { 95 return BuildTarget(rule.Name(), rule.dir, "") 96 } 97 98 func (rule *rule) isExternal() bool { 99 if !rule.isTest() { 100 return false 101 } 102 103 external := rule.Attr("external") 104 if external == nil { 105 return false 106 } 107 108 ident, ok := external.(*build.Ident) 109 if !ok { 110 return false 111 } 112 113 return ident.Name == "True" 114 } 115 116 func newRule(r *build.Rule, kindType *kinds.Kind, pkgDir string) *rule { 117 return &rule{ 118 dir: pkgDir, 119 kind: kindType, 120 Rule: r, 121 } 122 }