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  }