github.com/vektra/tachyon@v0.0.0-20150921164542-0da4f3861aef/util.go (about) 1 package tachyon 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "github.com/flynn/go-shlex" 8 "gopkg.in/yaml.v1" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "os/user" 13 "reflect" 14 "sort" 15 "strconv" 16 "strings" 17 ) 18 19 func HomeDir() (string, error) { 20 u, err := user.Current() 21 if err != nil { 22 su := os.Getenv("SUDO_USER") 23 24 var out []byte 25 var nerr error 26 27 if su != "" { 28 out, nerr = exec.Command("sh", "-c", "getent passwd "+su).Output() 29 } else { 30 out, nerr = exec.Command("sh", "-c", "getent passwd `id -u`").Output() 31 } 32 33 if nerr != nil { 34 return "", err 35 } 36 37 fields := bytes.Split(out, []byte(`:`)) 38 if len(fields) >= 6 { 39 return string(fields[5]), nil 40 } 41 42 return "", fmt.Errorf("Unable to figure out the home dir") 43 } 44 45 return u.HomeDir, nil 46 } 47 func dbg(format string, args ...interface{}) { 48 fmt.Printf("[DBG] "+format+"\n", args...) 49 } 50 51 func yamlFile(path string, v interface{}) error { 52 data, err := ioutil.ReadFile(path) 53 54 if err != nil { 55 return err 56 } 57 58 return yaml.Unmarshal(data, v) 59 } 60 61 func mapToStruct(m map[string]interface{}, tag string, v interface{}) error { 62 e := reflect.ValueOf(v).Elem() 63 64 t := e.Type() 65 66 for i := 0; i < t.NumField(); i++ { 67 f := t.Field(i) 68 69 name := strings.ToLower(f.Name) 70 required := false 71 72 parts := strings.Split(f.Tag.Get(tag), ",") 73 74 switch len(parts) { 75 case 0: 76 // nothing 77 case 1: 78 name = parts[0] 79 case 2: 80 name = parts[0] 81 switch parts[1] { 82 case "required": 83 required = true 84 default: 85 return fmt.Errorf("Unsupported tag flag: %s", parts[1]) 86 } 87 } 88 89 if val, ok := m[name]; ok { 90 e.Field(i).Set(reflect.ValueOf(val)) 91 } else if required { 92 return fmt.Errorf("Missing value for %s", f.Name) 93 } 94 } 95 96 return nil 97 } 98 99 func ParseSimpleMap(s Scope, args string) (Vars, error) { 100 args, err := ExpandVars(s, args) 101 102 if err != nil { 103 return nil, err 104 } 105 106 sm := make(Vars) 107 108 parts, err := shlex.Split(args) 109 110 if err != nil { 111 return nil, err 112 } 113 114 for _, part := range parts { 115 ec := strings.SplitN(part, "=", 2) 116 117 if len(ec) == 2 { 118 sm[ec[0]] = Any(inferString(ec[1])) 119 } else { 120 sm[part] = Any(true) 121 } 122 } 123 124 return sm, nil 125 } 126 127 func split2(s, sep string) (string, string, bool) { 128 parts := strings.SplitN(s, sep, 2) 129 130 if len(parts) == 0 { 131 return "", "", false 132 } else if len(parts) == 1 { 133 return parts[0], "", false 134 } else { 135 return parts[0], parts[1], true 136 } 137 } 138 139 func inferString(s string) interface{} { 140 switch strings.ToLower(s) { 141 case "true", "yes": 142 return true 143 case "false", "no": 144 return false 145 } 146 147 if i, err := strconv.ParseInt(s, 0, 0); err == nil { 148 return i 149 } 150 151 return s 152 } 153 154 func indentedYAML(v interface{}, indent string) (string, error) { 155 str, err := yaml.Marshal(v) 156 if err != nil { 157 return "", err 158 } 159 160 lines := strings.Split(string(str), "\n") 161 162 out := make([]string, len(lines)) 163 164 for idx, l := range lines { 165 if l == "" { 166 out[idx] = l 167 } else { 168 out[idx] = indent + l 169 } 170 } 171 172 return strings.Join(out, "\n"), nil 173 } 174 175 func arrayVal(v interface{}, indent string) string { 176 switch sv := v.(type) { 177 case string: 178 var out string 179 180 if strings.Index(sv, "\n") != -1 { 181 sub := strings.Split(sv, "\n") 182 out = strings.Join(sub, "\n"+indent+" | ") 183 return fmt.Sprintf("%s-\\\n%s | %s", indent, indent, out) 184 } else { 185 return fmt.Sprintf("%s- \"%s\"", indent, sv) 186 } 187 case int, uint, int32, uint32, int64, uint64: 188 return fmt.Sprintf("%s- %d", indent, sv) 189 case bool: 190 return fmt.Sprintf("%s- %t", indent, sv) 191 case map[string]interface{}: 192 mv := indentedMap(sv, indent+" ") 193 return fmt.Sprintf("%s-\n%s", indent, mv) 194 } 195 196 return fmt.Sprintf("%s- %v", indent, v) 197 } 198 199 func indentedMap(m map[string]interface{}, indent string) string { 200 var keys []string 201 202 for k, _ := range m { 203 keys = append(keys, k) 204 } 205 206 sort.Strings(keys) 207 208 var lines []string 209 210 for _, k := range keys { 211 v := m[k] 212 213 switch sv := v.(type) { 214 case string: 215 var out string 216 217 if strings.Index(sv, "\n") != -1 { 218 sub := strings.Split(sv, "\n") 219 out = strings.Join(sub, "\n"+indent+" | ") 220 lines = append(lines, fmt.Sprintf("%s%s:\n%s | %s", 221 indent, k, indent, out)) 222 } else { 223 lines = append(lines, fmt.Sprintf("%s%s: \"%s\"", indent, k, sv)) 224 } 225 case int, uint, int32, uint32, int64, uint64: 226 lines = append(lines, fmt.Sprintf("%s%s: %d", indent, k, sv)) 227 case bool: 228 lines = append(lines, fmt.Sprintf("%s%s: %t", indent, k, sv)) 229 case map[string]interface{}: 230 mv := indentedMap(sv, indent+" ") 231 lines = append(lines, fmt.Sprintf("%s%s:\n%s", indent, k, mv)) 232 default: 233 lines = append(lines, fmt.Sprintf("%s%s: %v", indent, k, sv)) 234 } 235 } 236 237 return strings.Join(lines, "\n") 238 } 239 240 func indentedVars(m Vars, indent string) string { 241 var keys []string 242 243 for k, _ := range m { 244 keys = append(keys, k) 245 } 246 247 sort.Strings(keys) 248 249 var lines []string 250 251 for _, k := range keys { 252 v := m[k] 253 254 switch sv := v.Read().(type) { 255 case string: 256 var out string 257 258 if strings.Index(sv, "\n") != -1 { 259 sub := strings.Split(sv, "\n") 260 out = strings.Join(sub, "\n"+indent+" | ") 261 lines = append(lines, fmt.Sprintf("%s%s:\n%s | %s", 262 indent, k, indent, out)) 263 } else { 264 lines = append(lines, fmt.Sprintf("%s%s: \"%s\"", indent, k, sv)) 265 } 266 case int, uint, int32, uint32, int64, uint64: 267 lines = append(lines, fmt.Sprintf("%s%s: %d", indent, k, sv)) 268 case bool: 269 lines = append(lines, fmt.Sprintf("%s%s: %t", indent, k, sv)) 270 case map[string]interface{}: 271 mv := indentedMap(sv, indent+" ") 272 lines = append(lines, fmt.Sprintf("%s%s:\n%s", indent, k, mv)) 273 default: 274 lines = append(lines, fmt.Sprintf("%s%s: %v", indent, k, sv)) 275 } 276 } 277 278 return strings.Join(lines, "\n") 279 } 280 281 func inlineMap(m map[string]interface{}) string { 282 var keys []string 283 284 for k, _ := range m { 285 keys = append(keys, k) 286 } 287 288 // Minor special case. If there is only one key and it's 289 // named "command", just return the value. 290 if len(keys) == 1 && keys[0] == "command" { 291 for _, v := range m { 292 if sv, ok := v.(string); ok { 293 return sv 294 } 295 } 296 } 297 298 sort.Strings(keys) 299 300 var lines []string 301 302 for _, k := range keys { 303 v := m[k] 304 305 switch sv := v.(type) { 306 case string: 307 lines = append(lines, fmt.Sprintf("%s=%s", k, strconv.Quote(sv))) 308 case int, uint, int32, uint32, int64, uint64: 309 lines = append(lines, fmt.Sprintf("%s=%d", k, sv)) 310 case bool: 311 lines = append(lines, fmt.Sprintf("%s=%t", k, sv)) 312 case map[string]interface{}: 313 lines = append(lines, fmt.Sprintf("%s=(%s)", k, inlineMap(sv))) 314 default: 315 lines = append(lines, fmt.Sprintf("%s=`%v`", k, sv)) 316 } 317 } 318 319 return strings.Join(lines, " ") 320 } 321 322 func inlineVars(m Vars) string { 323 var keys []string 324 325 for k, _ := range m { 326 keys = append(keys, k) 327 } 328 329 // Minor special case. If there is only one key and it's 330 // named "command", just return the value. 331 if len(keys) == 1 && keys[0] == "command" { 332 for _, v := range m { 333 if sv, ok := v.Read().(string); ok { 334 return sv 335 } 336 } 337 } 338 339 sort.Strings(keys) 340 341 var lines []string 342 343 for _, k := range keys { 344 v := m[k] 345 346 switch sv := v.Read().(type) { 347 case string: 348 lines = append(lines, fmt.Sprintf("%s=%s", k, strconv.Quote(sv))) 349 case int, uint, int32, uint32, int64, uint64: 350 lines = append(lines, fmt.Sprintf("%s=%d", k, sv)) 351 case bool: 352 lines = append(lines, fmt.Sprintf("%s=%t", k, sv)) 353 case map[string]interface{}: 354 lines = append(lines, fmt.Sprintf("%s=(%s)", k, inlineMap(sv))) 355 default: 356 lines = append(lines, fmt.Sprintf("%s=`%v`", k, sv)) 357 } 358 } 359 360 return strings.Join(lines, " ") 361 } 362 363 func fileExist(path string) bool { 364 fi, err := os.Stat(path) 365 if err != nil { 366 return false 367 } 368 369 return !fi.IsDir() 370 } 371 372 func gmap(args ...interface{}) map[string]interface{} { 373 m := make(map[string]interface{}) 374 375 if len(args)%2 != 0 { 376 panic(fmt.Sprintf("Specify an even number of args: %d", len(args))) 377 } 378 379 i := 0 380 381 for i < len(args) { 382 m[args[i].(string)] = args[i+1] 383 i += 2 384 } 385 386 return m 387 } 388 389 func ijson(args ...interface{}) []byte { 390 b, err := json.Marshal(gmap(args...)) 391 if err != nil { 392 panic(err) 393 } 394 395 return b 396 }