github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/helper/funcs.go (about) 1 package helper 2 3 import ( 4 "crypto/sha512" 5 "fmt" 6 "regexp" 7 "time" 8 9 multierror "github.com/hashicorp/go-multierror" 10 "github.com/hashicorp/hcl/hcl/ast" 11 ) 12 13 // validUUID is used to check if a given string looks like a UUID 14 var validUUID = regexp.MustCompile(`(?i)^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$`) 15 16 // IsUUID returns true if the given string is a valid UUID. 17 func IsUUID(str string) bool { 18 const uuidLen = 36 19 if len(str) != uuidLen { 20 return false 21 } 22 23 return validUUID.MatchString(str) 24 } 25 26 // HashUUID takes an input UUID and returns a hashed version of the UUID to 27 // ensure it is well distributed. 28 func HashUUID(input string) (output string, hashed bool) { 29 if !IsUUID(input) { 30 return "", false 31 } 32 33 // Hash the input 34 buf := sha512.Sum512([]byte(input)) 35 output = fmt.Sprintf("%08x-%04x-%04x-%04x-%12x", 36 buf[0:4], 37 buf[4:6], 38 buf[6:8], 39 buf[8:10], 40 buf[10:16]) 41 42 return output, true 43 } 44 45 // boolToPtr returns the pointer to a boolean 46 func BoolToPtr(b bool) *bool { 47 return &b 48 } 49 50 // IntToPtr returns the pointer to an int 51 func IntToPtr(i int) *int { 52 return &i 53 } 54 55 // Int64ToPtr returns the pointer to an int 56 func Int64ToPtr(i int64) *int64 { 57 return &i 58 } 59 60 // UintToPtr returns the pointer to an uint 61 func Uint64ToPtr(u uint64) *uint64 { 62 return &u 63 } 64 65 // StringToPtr returns the pointer to a string 66 func StringToPtr(str string) *string { 67 return &str 68 } 69 70 // TimeToPtr returns the pointer to a time stamp 71 func TimeToPtr(t time.Duration) *time.Duration { 72 return &t 73 } 74 75 func IntMin(a, b int) int { 76 if a < b { 77 return a 78 } 79 return b 80 } 81 82 func IntMax(a, b int) int { 83 if a > b { 84 return a 85 } 86 return b 87 } 88 89 func Uint64Max(a, b uint64) uint64 { 90 if a > b { 91 return a 92 } 93 return b 94 } 95 96 // MapStringStringSliceValueSet returns the set of values in a map[string][]string 97 func MapStringStringSliceValueSet(m map[string][]string) []string { 98 set := make(map[string]struct{}) 99 for _, slice := range m { 100 for _, v := range slice { 101 set[v] = struct{}{} 102 } 103 } 104 105 flat := make([]string, 0, len(set)) 106 for k := range set { 107 flat = append(flat, k) 108 } 109 return flat 110 } 111 112 func SliceStringToSet(s []string) map[string]struct{} { 113 m := make(map[string]struct{}, (len(s)+1)/2) 114 for _, k := range s { 115 m[k] = struct{}{} 116 } 117 return m 118 } 119 120 // SliceStringIsSubset returns whether the smaller set of strings is a subset of 121 // the larger. If the smaller slice is not a subset, the offending elements are 122 // returned. 123 func SliceStringIsSubset(larger, smaller []string) (bool, []string) { 124 largerSet := make(map[string]struct{}, len(larger)) 125 for _, l := range larger { 126 largerSet[l] = struct{}{} 127 } 128 129 subset := true 130 var offending []string 131 for _, s := range smaller { 132 if _, ok := largerSet[s]; !ok { 133 subset = false 134 offending = append(offending, s) 135 } 136 } 137 138 return subset, offending 139 } 140 141 func SliceSetDisjoint(first, second []string) (bool, []string) { 142 contained := make(map[string]struct{}, len(first)) 143 for _, k := range first { 144 contained[k] = struct{}{} 145 } 146 147 offending := make(map[string]struct{}) 148 for _, k := range second { 149 if _, ok := contained[k]; ok { 150 offending[k] = struct{}{} 151 } 152 } 153 154 if len(offending) == 0 { 155 return true, nil 156 } 157 158 flattened := make([]string, 0, len(offending)) 159 for k := range offending { 160 flattened = append(flattened, k) 161 } 162 return false, flattened 163 } 164 165 // Helpers for copying generic structures. 166 func CopyMapStringString(m map[string]string) map[string]string { 167 l := len(m) 168 if l == 0 { 169 return nil 170 } 171 172 c := make(map[string]string, l) 173 for k, v := range m { 174 c[k] = v 175 } 176 return c 177 } 178 179 func CopyMapStringStruct(m map[string]struct{}) map[string]struct{} { 180 l := len(m) 181 if l == 0 { 182 return nil 183 } 184 185 c := make(map[string]struct{}, l) 186 for k := range m { 187 c[k] = struct{}{} 188 } 189 return c 190 } 191 192 func CopyMapStringInt(m map[string]int) map[string]int { 193 l := len(m) 194 if l == 0 { 195 return nil 196 } 197 198 c := make(map[string]int, l) 199 for k, v := range m { 200 c[k] = v 201 } 202 return c 203 } 204 205 func CopyMapStringFloat64(m map[string]float64) map[string]float64 { 206 l := len(m) 207 if l == 0 { 208 return nil 209 } 210 211 c := make(map[string]float64, l) 212 for k, v := range m { 213 c[k] = v 214 } 215 return c 216 } 217 218 // CopyMapStringSliceString copies a map of strings to string slices such as 219 // http.Header 220 func CopyMapStringSliceString(m map[string][]string) map[string][]string { 221 l := len(m) 222 if l == 0 { 223 return nil 224 } 225 226 c := make(map[string][]string, l) 227 for k, v := range m { 228 c[k] = CopySliceString(v) 229 } 230 return c 231 } 232 233 func CopySliceString(s []string) []string { 234 l := len(s) 235 if l == 0 { 236 return nil 237 } 238 239 c := make([]string, l) 240 for i, v := range s { 241 c[i] = v 242 } 243 return c 244 } 245 246 func CopySliceInt(s []int) []int { 247 l := len(s) 248 if l == 0 { 249 return nil 250 } 251 252 c := make([]int, l) 253 for i, v := range s { 254 c[i] = v 255 } 256 return c 257 } 258 259 // CleanEnvVar replaces all occurrences of illegal characters in an environment 260 // variable with the specified byte. 261 func CleanEnvVar(s string, r byte) string { 262 b := []byte(s) 263 for i, c := range b { 264 switch { 265 case c == '_': 266 case c >= 'a' && c <= 'z': 267 case c >= 'A' && c <= 'Z': 268 case i > 0 && c >= '0' && c <= '9': 269 default: 270 // Replace! 271 b[i] = r 272 } 273 } 274 return string(b) 275 } 276 277 func CheckHCLKeys(node ast.Node, valid []string) error { 278 var list *ast.ObjectList 279 switch n := node.(type) { 280 case *ast.ObjectList: 281 list = n 282 case *ast.ObjectType: 283 list = n.List 284 default: 285 return fmt.Errorf("cannot check HCL keys of type %T", n) 286 } 287 288 validMap := make(map[string]struct{}, len(valid)) 289 for _, v := range valid { 290 validMap[v] = struct{}{} 291 } 292 293 var result error 294 for _, item := range list.Items { 295 key := item.Keys[0].Token.Value().(string) 296 if _, ok := validMap[key]; !ok { 297 result = multierror.Append(result, fmt.Errorf( 298 "invalid key: %s", key)) 299 } 300 } 301 302 return result 303 }