rule.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. func (f *File) Rule(call *CallExpr) *Rule {
  25. r := &Rule{call, ""}
  26. if r.AttrString("name") == "" {
  27. r.ImplicitName = f.implicitRuleName()
  28. }
  29. return r
  30. }
  31. // Rules returns the rules in the file of the given kind (such as "go_library").
  32. // If kind == "", Rules returns all rules in the file.
  33. func (f *File) Rules(kind string) []*Rule {
  34. var all []*Rule
  35. for _, stmt := range f.Stmt {
  36. call, ok := stmt.(*CallExpr)
  37. if !ok {
  38. continue
  39. }
  40. rule := f.Rule(call)
  41. if kind != "" && rule.Kind() != kind {
  42. continue
  43. }
  44. all = append(all, rule)
  45. }
  46. return all
  47. }
  48. // RuleAt returns the rule in the file that starts at the specified line, or null if no such rule.
  49. func (f *File) RuleAt(linenum int) *Rule {
  50. for _, stmt := range f.Stmt {
  51. call, ok := stmt.(*CallExpr)
  52. if !ok {
  53. continue
  54. }
  55. start, end := call.X.Span()
  56. if start.Line <= linenum && linenum <= end.Line {
  57. return f.Rule(call)
  58. }
  59. }
  60. return nil
  61. }
  62. // DelRules removes rules with the given kind and name from the file.
  63. // An empty kind matches all kinds; an empty name matches all names.
  64. // It returns the number of rules that were deleted.
  65. func (f *File) DelRules(kind, name string) int {
  66. var i int
  67. for _, stmt := range f.Stmt {
  68. if call, ok := stmt.(*CallExpr); ok {
  69. r := f.Rule(call)
  70. if (kind == "" || r.Kind() == kind) &&
  71. (name == "" || r.Name() == name) {
  72. continue
  73. }
  74. }
  75. f.Stmt[i] = stmt
  76. i++
  77. }
  78. n := len(f.Stmt) - i
  79. f.Stmt = f.Stmt[:i]
  80. return n
  81. }
  82. // If a build file contains exactly one unnamed rule, and no rules in the file explicitly have the
  83. // same name as the name of the directory the build file is in, we treat the unnamed rule as if it
  84. // had the name of the directory containing the BUILD file.
  85. // This is following a convention used in the Pants build system to cut down on boilerplate.
  86. func (f *File) implicitRuleName() string {
  87. // We disallow empty names in the top-level BUILD files.
  88. dir := filepath.Dir(f.Path)
  89. if dir == "." {
  90. return ""
  91. }
  92. sawAnonymousRule := false
  93. possibleImplicitName := filepath.Base(dir)
  94. for _, stmt := range f.Stmt {
  95. call, ok := stmt.(*CallExpr)
  96. if !ok {
  97. continue
  98. }
  99. temp := &Rule{call, ""}
  100. if temp.AttrString("name") == possibleImplicitName {
  101. // A target explicitly has the name of the dir, so no implicit targets are allowed.
  102. return ""
  103. }
  104. if temp.Kind() != "" && temp.AttrString("name") == "" {
  105. if sawAnonymousRule {
  106. return ""
  107. }
  108. sawAnonymousRule = true
  109. }
  110. }
  111. if sawAnonymousRule {
  112. return possibleImplicitName
  113. }
  114. return ""
  115. }
  116. // Kind returns the rule's kind (such as "go_library").
  117. // The kind of the rule may be given by a literal or it may be a sequence of dot expressions that
  118. // begins with a literal, if the call expression does not conform to either of these forms, an
  119. // empty string will be returned
  120. func (r *Rule) Kind() string {
  121. var names []string
  122. expr := r.Call.X
  123. for {
  124. x, ok := expr.(*DotExpr)
  125. if !ok {
  126. break
  127. }
  128. names = append(names, x.Name)
  129. expr = x.X
  130. }
  131. x, ok := expr.(*LiteralExpr)
  132. if !ok {
  133. return ""
  134. }
  135. names = append(names, x.Token)
  136. // Reverse the elements since the deepest expression contains the leading literal
  137. for l, r := 0, len(names)-1; l < r; l, r = l+1, r-1 {
  138. names[l], names[r] = names[r], names[l]
  139. }
  140. return strings.Join(names, ".")
  141. }
  142. // SetKind changes rule's kind (such as "go_library").
  143. func (r *Rule) SetKind(kind string) {
  144. names := strings.Split(kind, ".")
  145. var expr Expr
  146. expr = &LiteralExpr{Token: names[0]}
  147. for _, name := range names[1:] {
  148. expr = &DotExpr{X: expr, Name: name}
  149. }
  150. r.Call.X = expr
  151. }
  152. // Name returns the rule's target name.
  153. // If the rule has no explicit target name, Name returns the implicit name if there is one, else the empty string.
  154. func (r *Rule) Name() string {
  155. explicitName := r.AttrString("name")
  156. if explicitName == "" {
  157. return r.ImplicitName
  158. }
  159. return explicitName
  160. }
  161. // AttrKeys returns the keys of all the rule's attributes.
  162. func (r *Rule) AttrKeys() []string {
  163. var keys []string
  164. for _, expr := range r.Call.List {
  165. if binExpr, ok := expr.(*BinaryExpr); ok && binExpr.Op == "=" {
  166. if keyExpr, ok := binExpr.X.(*LiteralExpr); ok {
  167. keys = append(keys, keyExpr.Token)
  168. }
  169. }
  170. }
  171. return keys
  172. }
  173. // AttrDefn returns the BinaryExpr defining the rule's attribute with the given key.
  174. // That is, the result is a *BinaryExpr with Op == "=".
  175. // If the rule has no such attribute, AttrDefn returns nil.
  176. func (r *Rule) AttrDefn(key string) *BinaryExpr {
  177. for _, kv := range r.Call.List {
  178. as, ok := kv.(*BinaryExpr)
  179. if !ok || as.Op != "=" {
  180. continue
  181. }
  182. k, ok := as.X.(*LiteralExpr)
  183. if !ok || k.Token != key {
  184. continue
  185. }
  186. return as
  187. }
  188. return nil
  189. }
  190. // Attr returns the value of the rule's attribute with the given key
  191. // (such as "name" or "deps").
  192. // If the rule has no such attribute, Attr returns nil.
  193. func (r *Rule) Attr(key string) Expr {
  194. as := r.AttrDefn(key)
  195. if as == nil {
  196. return nil
  197. }
  198. return as.Y
  199. }
  200. // DelAttr deletes the rule's attribute with the named key.
  201. // It returns the old value of the attribute, or nil if the attribute was not found.
  202. func (r *Rule) DelAttr(key string) Expr {
  203. list := r.Call.List
  204. for i, kv := range list {
  205. as, ok := kv.(*BinaryExpr)
  206. if !ok || as.Op != "=" {
  207. continue
  208. }
  209. k, ok := as.X.(*LiteralExpr)
  210. if !ok || k.Token != key {
  211. continue
  212. }
  213. copy(list[i:], list[i+1:])
  214. r.Call.List = list[:len(list)-1]
  215. return as.Y
  216. }
  217. return nil
  218. }
  219. // SetAttr sets the rule's attribute with the given key to value.
  220. // If the rule has no attribute with the key, SetAttr appends
  221. // one to the end of the rule's attribute list.
  222. func (r *Rule) SetAttr(key string, val Expr) {
  223. as := r.AttrDefn(key)
  224. if as != nil {
  225. as.Y = val
  226. return
  227. }
  228. r.Call.List = append(r.Call.List,
  229. &BinaryExpr{
  230. X: &LiteralExpr{Token: key},
  231. Op: "=",
  232. Y: val,
  233. },
  234. )
  235. }
  236. // AttrLiteral returns the literal form of the rule's attribute
  237. // with the given key (such as "cc_api_version"), only when
  238. // that value is an identifier or number.
  239. // If the rule has no such attribute or the attribute is not an identifier or number,
  240. // AttrLiteral returns "".
  241. func (r *Rule) AttrLiteral(key string) string {
  242. lit, ok := r.Attr(key).(*LiteralExpr)
  243. if !ok {
  244. return ""
  245. }
  246. return lit.Token
  247. }
  248. // AttrString returns the value of the rule's attribute
  249. // with the given key (such as "name"), as a string.
  250. // If the rule has no such attribute or the attribute has a non-string value,
  251. // Attr returns the empty string.
  252. func (r *Rule) AttrString(key string) string {
  253. str, ok := r.Attr(key).(*StringExpr)
  254. if !ok {
  255. return ""
  256. }
  257. return str.Value
  258. }
  259. // AttrStrings returns the value of the rule's attribute
  260. // with the given key (such as "srcs"), as a []string.
  261. // If the rule has no such attribute or the attribute is not
  262. // a list of strings, AttrStrings returns a nil slice.
  263. func (r *Rule) AttrStrings(key string) []string {
  264. return Strings(r.Attr(key))
  265. }
  266. // Strings returns expr as a []string.
  267. // If expr is not a list of string literals,
  268. // Strings returns a nil slice instead.
  269. // If expr is an empty list of string literals,
  270. // returns a non-nil empty slice.
  271. // (this allows differentiating between these two cases)
  272. func Strings(expr Expr) []string {
  273. list, ok := expr.(*ListExpr)
  274. if !ok {
  275. return nil
  276. }
  277. all := []string{} // not nil
  278. for _, l := range list.List {
  279. str, ok := l.(*StringExpr)
  280. if !ok {
  281. return nil
  282. }
  283. all = append(all, str.Value)
  284. }
  285. return all
  286. }