github.com/wolfd/bazel-gazelle@v0.14.0/internal/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 23 // PlatformStrings contains a set of strings associated with a buildable 24 // target in a package. This is used to store source file names, 25 // import paths, and flags. 26 // 27 // Strings are stored in four sets: generic strings, OS-specific strings, 28 // arch-specific strings, and OS-and-arch-specific strings. A string may not 29 // be duplicated within a list or across sets; however, a string may appear 30 // in more than one list within a set (e.g., in "linux" and "windows" within 31 // the OS set). Strings within each list should be sorted, though this may 32 // not be relied upon. 33 type PlatformStrings struct { 34 // Generic is a list of strings not specific to any platform. 35 Generic []string 36 37 // OS is a map from OS name (anything in KnownOSs) to 38 // OS-specific strings. 39 OS map[string][]string 40 41 // Arch is a map from architecture name (anything in KnownArchs) to 42 // architecture-specific strings. 43 Arch map[string][]string 44 45 // Platform is a map from platforms to OS and architecture-specific strings. 46 Platform map[Platform][]string 47 } 48 49 // HasExt returns whether this set contains a file with the given extension. 50 func (ps *PlatformStrings) HasExt(ext string) bool { 51 return ps.firstExtFile(ext) != "" 52 } 53 54 func (ps *PlatformStrings) IsEmpty() bool { 55 return len(ps.Generic) == 0 && len(ps.OS) == 0 && len(ps.Arch) == 0 && len(ps.Platform) == 0 56 } 57 58 // Flat returns all the strings in the set, sorted and de-duplicated. 59 func (ps *PlatformStrings) Flat() []string { 60 unique := make(map[string]struct{}) 61 for _, s := range ps.Generic { 62 unique[s] = struct{}{} 63 } 64 for _, ss := range ps.OS { 65 for _, s := range ss { 66 unique[s] = struct{}{} 67 } 68 } 69 for _, ss := range ps.Arch { 70 for _, s := range ss { 71 unique[s] = struct{}{} 72 } 73 } 74 for _, ss := range ps.Platform { 75 for _, s := range ss { 76 unique[s] = struct{}{} 77 } 78 } 79 flat := make([]string, 0, len(unique)) 80 for s := range unique { 81 flat = append(flat, s) 82 } 83 sort.Strings(flat) 84 return flat 85 } 86 87 func (ps *PlatformStrings) firstExtFile(ext string) string { 88 for _, f := range ps.Generic { 89 if strings.HasSuffix(f, ext) { 90 return f 91 } 92 } 93 for _, fs := range ps.OS { 94 for _, f := range fs { 95 if strings.HasSuffix(f, ext) { 96 return f 97 } 98 } 99 } 100 for _, fs := range ps.Arch { 101 for _, f := range fs { 102 if strings.HasSuffix(f, ext) { 103 return f 104 } 105 } 106 } 107 for _, fs := range ps.Platform { 108 for _, f := range fs { 109 if strings.HasSuffix(f, ext) { 110 return f 111 } 112 } 113 } 114 return "" 115 } 116 117 // Map applies a function that processes individual strings to the strings 118 // in "ps" and returns a new PlatformStrings with the result. Empty strings 119 // returned by the function are dropped. 120 func (ps *PlatformStrings) Map(f func(s string) (string, error)) (PlatformStrings, []error) { 121 var errors []error 122 mapSlice := func(ss []string) ([]string, error) { 123 rs := make([]string, 0, len(ss)) 124 for _, s := range ss { 125 if r, err := f(s); err != nil { 126 errors = append(errors, err) 127 } else if r != "" { 128 rs = append(rs, r) 129 } 130 } 131 return rs, nil 132 } 133 result, _ := ps.MapSlice(mapSlice) 134 return result, errors 135 } 136 137 // MapSlice applies a function that processes slices of strings to the strings 138 // in "ps" and returns a new PlatformStrings with the results. 139 func (ps *PlatformStrings) MapSlice(f func([]string) ([]string, error)) (PlatformStrings, []error) { 140 var errors []error 141 142 mapSlice := func(ss []string) []string { 143 rs, err := f(ss) 144 if err != nil { 145 errors = append(errors, err) 146 return nil 147 } 148 return rs 149 } 150 151 mapStringMap := func(m map[string][]string) map[string][]string { 152 if m == nil { 153 return nil 154 } 155 rm := make(map[string][]string) 156 for k, ss := range m { 157 ss = mapSlice(ss) 158 if len(ss) > 0 { 159 rm[k] = ss 160 } 161 } 162 if len(rm) == 0 { 163 return nil 164 } 165 return rm 166 } 167 168 mapPlatformMap := func(m map[Platform][]string) map[Platform][]string { 169 if m == nil { 170 return nil 171 } 172 rm := make(map[Platform][]string) 173 for k, ss := range m { 174 ss = mapSlice(ss) 175 if len(ss) > 0 { 176 rm[k] = ss 177 } 178 } 179 if len(rm) == 0 { 180 return nil 181 } 182 return rm 183 } 184 185 result := PlatformStrings{ 186 Generic: mapSlice(ps.Generic), 187 OS: mapStringMap(ps.OS), 188 Arch: mapStringMap(ps.Arch), 189 Platform: mapPlatformMap(ps.Platform), 190 } 191 return result, errors 192 }