platform_strings.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* Copyright 2017 The Bazel Authors. All rights reserved.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package rule
  13. import (
  14. "sort"
  15. "strings"
  16. bzl "github.com/bazelbuild/buildtools/build"
  17. )
  18. // PlatformStrings contains a set of strings associated with a buildable
  19. // target in a package. This is used to store source file names,
  20. // import paths, and flags.
  21. //
  22. // Strings are stored in four sets: generic strings, OS-specific strings,
  23. // arch-specific strings, and OS-and-arch-specific strings. A string may not
  24. // be duplicated within a list or across sets; however, a string may appear
  25. // in more than one list within a set (e.g., in "linux" and "windows" within
  26. // the OS set). Strings within each list should be sorted, though this may
  27. // not be relied upon.
  28. //
  29. // DEPRECATED: do not use outside language/go. This type is Go-specific and
  30. // should be moved to the Go extension.
  31. type PlatformStrings struct {
  32. // Generic is a list of strings not specific to any platform.
  33. Generic []string
  34. // OS is a map from OS name (anything in KnownOSs) to
  35. // OS-specific strings.
  36. OS map[string][]string
  37. // Arch is a map from architecture name (anything in KnownArchs) to
  38. // architecture-specific strings.
  39. Arch map[string][]string
  40. // Platform is a map from platforms to OS and architecture-specific strings.
  41. Platform map[Platform][]string
  42. }
  43. // HasExt returns whether this set contains a file with the given extension.
  44. func (ps *PlatformStrings) HasExt(ext string) bool {
  45. return ps.firstExtFile(ext) != ""
  46. }
  47. func (ps *PlatformStrings) IsEmpty() bool {
  48. return len(ps.Generic) == 0 && len(ps.OS) == 0 && len(ps.Arch) == 0 && len(ps.Platform) == 0
  49. }
  50. // Flat returns all the strings in the set, sorted and de-duplicated.
  51. func (ps *PlatformStrings) Flat() []string {
  52. unique := make(map[string]struct{})
  53. for _, s := range ps.Generic {
  54. unique[s] = struct{}{}
  55. }
  56. for _, ss := range ps.OS {
  57. for _, s := range ss {
  58. unique[s] = struct{}{}
  59. }
  60. }
  61. for _, ss := range ps.Arch {
  62. for _, s := range ss {
  63. unique[s] = struct{}{}
  64. }
  65. }
  66. for _, ss := range ps.Platform {
  67. for _, s := range ss {
  68. unique[s] = struct{}{}
  69. }
  70. }
  71. flat := make([]string, 0, len(unique))
  72. for s := range unique {
  73. flat = append(flat, s)
  74. }
  75. sort.Strings(flat)
  76. return flat
  77. }
  78. func (ps *PlatformStrings) firstExtFile(ext string) string {
  79. for _, f := range ps.Generic {
  80. if strings.HasSuffix(f, ext) {
  81. return f
  82. }
  83. }
  84. for _, fs := range ps.OS {
  85. for _, f := range fs {
  86. if strings.HasSuffix(f, ext) {
  87. return f
  88. }
  89. }
  90. }
  91. for _, fs := range ps.Arch {
  92. for _, f := range fs {
  93. if strings.HasSuffix(f, ext) {
  94. return f
  95. }
  96. }
  97. }
  98. for _, fs := range ps.Platform {
  99. for _, f := range fs {
  100. if strings.HasSuffix(f, ext) {
  101. return f
  102. }
  103. }
  104. }
  105. return ""
  106. }
  107. // Map applies a function that processes individual strings to the strings
  108. // in "ps" and returns a new PlatformStrings with the result. Empty strings
  109. // returned by the function are dropped.
  110. func (ps *PlatformStrings) Map(f func(s string) (string, error)) (PlatformStrings, []error) {
  111. var errors []error
  112. mapSlice := func(ss []string) ([]string, error) {
  113. rs := make([]string, 0, len(ss))
  114. for _, s := range ss {
  115. if r, err := f(s); err != nil {
  116. errors = append(errors, err)
  117. } else if r != "" {
  118. rs = append(rs, r)
  119. }
  120. }
  121. return rs, nil
  122. }
  123. result, _ := ps.MapSlice(mapSlice)
  124. return result, errors
  125. }
  126. // MapSlice applies a function that processes slices of strings to the strings
  127. // in "ps" and returns a new PlatformStrings with the results.
  128. func (ps *PlatformStrings) MapSlice(f func([]string) ([]string, error)) (PlatformStrings, []error) {
  129. var errors []error
  130. mapSlice := func(ss []string) []string {
  131. rs, err := f(ss)
  132. if err != nil {
  133. errors = append(errors, err)
  134. return nil
  135. }
  136. return rs
  137. }
  138. mapStringMap := func(m map[string][]string) map[string][]string {
  139. if m == nil {
  140. return nil
  141. }
  142. rm := make(map[string][]string)
  143. for k, ss := range m {
  144. ss = mapSlice(ss)
  145. if len(ss) > 0 {
  146. rm[k] = ss
  147. }
  148. }
  149. if len(rm) == 0 {
  150. return nil
  151. }
  152. return rm
  153. }
  154. mapPlatformMap := func(m map[Platform][]string) map[Platform][]string {
  155. if m == nil {
  156. return nil
  157. }
  158. rm := make(map[Platform][]string)
  159. for k, ss := range m {
  160. ss = mapSlice(ss)
  161. if len(ss) > 0 {
  162. rm[k] = ss
  163. }
  164. }
  165. if len(rm) == 0 {
  166. return nil
  167. }
  168. return rm
  169. }
  170. result := PlatformStrings{
  171. Generic: mapSlice(ps.Generic),
  172. OS: mapStringMap(ps.OS),
  173. Arch: mapStringMap(ps.Arch),
  174. Platform: mapPlatformMap(ps.Platform),
  175. }
  176. return result, errors
  177. }
  178. func (ps PlatformStrings) BzlExpr() bzl.Expr {
  179. var pieces []bzl.Expr
  180. if len(ps.Generic) > 0 {
  181. pieces = append(pieces, ExprFromValue(ps.Generic))
  182. }
  183. if len(ps.OS) > 0 {
  184. pieces = append(pieces, platformStringsOSArchDictExpr(ps.OS))
  185. }
  186. if len(ps.Arch) > 0 {
  187. pieces = append(pieces, platformStringsOSArchDictExpr(ps.Arch))
  188. }
  189. if len(ps.Platform) > 0 {
  190. pieces = append(pieces, platformStringsPlatformDictExpr(ps.Platform))
  191. }
  192. if len(pieces) == 0 {
  193. return &bzl.ListExpr{}
  194. } else if len(pieces) == 1 {
  195. return pieces[0]
  196. } else {
  197. e := pieces[0]
  198. if list, ok := e.(*bzl.ListExpr); ok {
  199. list.ForceMultiLine = true
  200. }
  201. for _, piece := range pieces[1:] {
  202. e = &bzl.BinaryExpr{X: e, Y: piece, Op: "+"}
  203. }
  204. return e
  205. }
  206. }
  207. func platformStringsOSArchDictExpr(m map[string][]string) bzl.Expr {
  208. s := make(SelectStringListValue)
  209. for key, value := range m {
  210. s["@io_bazel_rules_go//go/platform:"+key] = value
  211. }
  212. s["//conditions:default"] = nil
  213. return s.BzlExpr()
  214. }
  215. func platformStringsPlatformDictExpr(m map[Platform][]string) bzl.Expr {
  216. s := make(SelectStringListValue)
  217. for key, value := range m {
  218. s["@io_bazel_rules_go//go/platform:"+key.String()] = value
  219. }
  220. s["//conditions:default"] = nil
  221. return s.BzlExpr()
  222. }