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  }