rule.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*
  2. Copyright 2016 Google Inc. All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Rule-level API for inspecting and modifying a build.File syntax tree.
  14. package build
  15. import (
  16. "path/filepath"
  17. "strings"
  18. )
  19. // A Rule represents a single BUILD rule.
  20. type Rule struct {
  21. Call *CallExpr
  22. ImplicitName string // The name which should be used if the name attribute is not set. See the comment on File.implicitRuleName.
  23. }
  24. // NewRule is a simple constructor for Rule.
  25. func NewRule(call *CallExpr) *Rule {
  26. return &Rule{call, ""}
  27. }
  28. func (f *File) Rule(call *CallExpr) *Rule {
  29. r := &Rule{call, ""}
  30. if r.AttrString("name") == "" {
  31. r.ImplicitName = f.implicitRuleName()
  32. }
  33. return r
  34. }
  35. // Rules returns the rules in the file of the given kind (such as "go_library").
  36. // If kind == "", Rules returns all rules in the file.
  37. func (f *File) Rules(kind string) []*Rule {
  38. var all []*Rule
  39. for _, stmt := range f.Stmt {
  40. Walk(stmt, func(x Expr, stk []Expr) {
  41. call, ok := x.(*CallExpr)
  42. if !ok {
  43. return
  44. }
  45. // Skip nested calls.
  46. for _, frame := range stk {
  47. if _, ok := frame.(*CallExpr); ok {
  48. return
  49. }
  50. }
  51. // Check if the rule kind is correct.
  52. rule := f.Rule(call)
  53. if kind != "" && rule.Kind() != kind {
  54. return
  55. }
  56. all = append(all, rule)
  57. })
  58. }
  59. return all
  60. }
  61. // RuleAt returns the rule in the file that starts at the specified line, or null if no such rule.
  62. func (f *File) RuleAt(linenum int) *Rule {
  63. for _, stmt := range f.Stmt {
  64. call, ok := stmt.(*CallExpr)
  65. if !ok {
  66. continue
  67. }
  68. start, end := call.X.Span()
  69. if start.Line <= linenum && linenum <= end.Line {
  70. return f.Rule(call)
  71. }
  72. }
  73. return nil
  74. }
  75. // DelRules removes rules with the given kind and name from the file.
  76. // An empty kind matches all kinds; an empty name matches all names.
  77. // It returns the number of rules that were deleted.
  78. func (f *File) DelRules(kind, name string) int {
  79. var i int
  80. for _, stmt := range f.Stmt {
  81. if call, ok := stmt.(*CallExpr); ok {
  82. r := f.Rule(call)
  83. if (kind == "" || r.Kind() == kind) &&
  84. (name == "" || r.Name() == name) {
  85. continue
  86. }
  87. }
  88. f.Stmt[i] = stmt
  89. i++
  90. }
  91. n := len(f.Stmt) - i
  92. f.Stmt = f.Stmt[:i]
  93. return n
  94. }
  95. // If a build file contains exactly one unnamed rule, and no rules in the file explicitly have the
  96. // same name as the name of the directory the build file is in, we treat the unnamed rule as if it
  97. // had the name of the directory containing the BUILD file.
  98. // This is following a convention used in the Pants build system to cut down on boilerplate.
  99. func (f *File) implicitRuleName() string {
  100. // We disallow empty names in the top-level BUILD files.
  101. dir := filepath.Dir(f.Path)
  102. if dir == "." {
  103. return ""
  104. }
  105. sawAnonymousRule := false
  106. possibleImplicitName := filepath.Base(dir)
  107. for _, stmt := range f.Stmt {
  108. call, ok := stmt.(*CallExpr)
  109. if !ok {
  110. continue
  111. }
  112. temp := &Rule{call, ""}
  113. if temp.AttrString("name") == possibleImplicitName {
  114. // A target explicitly has the name of the dir, so no implicit targets are allowed.
  115. return ""
  116. }
  117. if temp.Kind() != "" && temp.AttrString("name") == "" {
  118. if sawAnonymousRule {
  119. return ""
  120. }
  121. sawAnonymousRule = true
  122. }
  123. }
  124. if sawAnonymousRule {
  125. return possibleImplicitName
  126. }
  127. return ""
  128. }
  129. // Kind returns the rule's kind (such as "go_library").
  130. // The kind of the rule may be given by a literal or it may be a sequence of dot expressions that
  131. // begins with a literal, if the call expression does not conform to either of these forms, an
  132. // empty string will be returned
  133. func (r *Rule) Kind() string {
  134. var names []string
  135. expr := r.Call.X
  136. for {
  137. x, ok := expr.(*DotExpr)
  138. if !ok {
  139. break
  140. }
  141. names = append(names, x.Name)
  142. expr = x.X
  143. }
  144. x, ok := expr.(*Ident)
  145. if !ok {
  146. return ""
  147. }
  148. names = append(names, x.Name)
  149. // Reverse the elements since the deepest expression contains the leading literal
  150. for l, r := 0, len(names)-1; l < r; l, r = l+1, r-1 {
  151. names[l], names[r] = names[r], names[l]
  152. }
  153. return strings.Join(names, ".")
  154. }
  155. // SetKind changes rule's kind (such as "go_library").
  156. func (r *Rule) SetKind(kind string) {
  157. names := strings.Split(kind, ".")
  158. var expr Expr
  159. expr = &Ident{Name: names[0]}
  160. for _, name := range names[1:] {
  161. expr = &DotExpr{X: expr, Name: name}
  162. }
  163. r.Call.X = expr
  164. }
  165. // ExplicitName returns the rule's target name if it's explicitly provided as a string value, "" otherwise.
  166. func (r *Rule) ExplicitName() string {
  167. return r.AttrString("name")
  168. }
  169. // Name returns the rule's target name.
  170. // If the rule has no explicit target name, Name returns the implicit name if there is one, else the empty string.
  171. func (r *Rule) Name() string {
  172. explicitName := r.ExplicitName()
  173. if explicitName == "" && r.Kind() != "package" {
  174. return r.ImplicitName
  175. }
  176. return explicitName
  177. }
  178. // AttrKeys returns the keys of all the rule's attributes.
  179. func (r *Rule) AttrKeys() []string {
  180. var keys []string
  181. for _, expr := range r.Call.List {
  182. if as, ok := expr.(*AssignExpr); ok {
  183. if keyExpr, ok := as.LHS.(*Ident); ok {
  184. keys = append(keys, keyExpr.Name)
  185. }
  186. }
  187. }
  188. return keys
  189. }
  190. // AttrDefn returns the AssignExpr defining the rule's attribute with the given key.
  191. // If the rule has no such attribute, AttrDefn returns nil.
  192. func (r *Rule) AttrDefn(key string) *AssignExpr {
  193. for _, kv := range r.Call.List {
  194. as, ok := kv.(*AssignExpr)
  195. if !ok {
  196. continue
  197. }
  198. k, ok := as.LHS.(*Ident)
  199. if !ok || k.Name != key {
  200. continue
  201. }
  202. return as
  203. }
  204. return nil
  205. }
  206. // Attr returns the value of the rule's attribute with the given key
  207. // (such as "name" or "deps").
  208. // If the rule has no such attribute, Attr returns nil.
  209. func (r *Rule) Attr(key string) Expr {
  210. as := r.AttrDefn(key)
  211. if as == nil {
  212. return nil
  213. }
  214. return as.RHS
  215. }
  216. // DelAttr deletes the rule's attribute with the named key.
  217. // It returns the old value of the attribute, or nil if the attribute was not found.
  218. func (r *Rule) DelAttr(key string) Expr {
  219. list := r.Call.List
  220. for i, kv := range list {
  221. as, ok := kv.(*AssignExpr)
  222. if !ok {
  223. continue
  224. }
  225. k, ok := as.LHS.(*Ident)
  226. if !ok || k.Name != key {
  227. continue
  228. }
  229. copy(list[i:], list[i+1:])
  230. r.Call.List = list[:len(list)-1]
  231. return as.RHS
  232. }
  233. return nil
  234. }
  235. // SetAttr sets the rule's attribute with the given key to value.
  236. // If the rule has no attribute with the key, SetAttr appends
  237. // one to the end of the rule's attribute list.
  238. func (r *Rule) SetAttr(key string, val Expr) {
  239. as := r.AttrDefn(key)
  240. if as != nil {
  241. as.RHS = val
  242. return
  243. }
  244. r.Call.List = append(r.Call.List,
  245. &AssignExpr{
  246. LHS: &Ident{Name: key},
  247. Op: "=",
  248. RHS: val,
  249. },
  250. )
  251. }
  252. // AttrLiteral returns the literal form of the rule's attribute
  253. // with the given key (such as "cc_api_version"), only when
  254. // that value is an identifier or number.
  255. // If the rule has no such attribute or the attribute is not an identifier or number,
  256. // AttrLiteral returns "".
  257. func (r *Rule) AttrLiteral(key string) string {
  258. value := r.Attr(key)
  259. if ident, ok := value.(*Ident); ok {
  260. return ident.Name
  261. }
  262. if literal, ok := value.(*LiteralExpr); ok {
  263. return literal.Token
  264. }
  265. return ""
  266. }
  267. // AttrString returns the value of the rule's attribute
  268. // with the given key (such as "name"), as a string.
  269. // If the rule has no such attribute or the attribute has a non-string value,
  270. // Attr returns the empty string.
  271. func (r *Rule) AttrString(key string) string {
  272. str, ok := r.Attr(key).(*StringExpr)
  273. if !ok {
  274. return ""
  275. }
  276. return str.Value
  277. }
  278. // AttrStrings returns the value of the rule's attribute
  279. // with the given key (such as "srcs"), as a []string.
  280. // If the rule has no such attribute or the attribute is not
  281. // a list of strings, AttrStrings returns a nil slice.
  282. func (r *Rule) AttrStrings(key string) []string {
  283. return Strings(r.Attr(key))
  284. }
  285. // Strings returns expr as a []string.
  286. // If expr is not a list of string literals,
  287. // Strings returns a nil slice instead.
  288. // If expr is an empty list of string literals,
  289. // returns a non-nil empty slice.
  290. // (this allows differentiating between these two cases)
  291. func Strings(expr Expr) []string {
  292. list, ok := expr.(*ListExpr)
  293. if !ok {
  294. return nil
  295. }
  296. all := []string{} // not nil
  297. for _, l := range list.List {
  298. str, ok := l.(*StringExpr)
  299. if !ok {
  300. return nil
  301. }
  302. all = append(all, str.Value)
  303. }
  304. return all
  305. }