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