github.com/djenriquez/nomad-1@v0.8.1/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 == '.':
   267  		case c >= 'a' && c <= 'z':
   268  		case c >= 'A' && c <= 'Z':
   269  		case i > 0 && c >= '0' && c <= '9':
   270  		default:
   271  			// Replace!
   272  			b[i] = r
   273  		}
   274  	}
   275  	return string(b)
   276  }
   277  
   278  func CheckHCLKeys(node ast.Node, valid []string) error {
   279  	var list *ast.ObjectList
   280  	switch n := node.(type) {
   281  	case *ast.ObjectList:
   282  		list = n
   283  	case *ast.ObjectType:
   284  		list = n.List
   285  	default:
   286  		return fmt.Errorf("cannot check HCL keys of type %T", n)
   287  	}
   288  
   289  	validMap := make(map[string]struct{}, len(valid))
   290  	for _, v := range valid {
   291  		validMap[v] = struct{}{}
   292  	}
   293  
   294  	var result error
   295  	for _, item := range list.Items {
   296  		key := item.Keys[0].Token.Value().(string)
   297  		if _, ok := validMap[key]; !ok {
   298  			result = multierror.Append(result, fmt.Errorf(
   299  				"invalid key: %s", key))
   300  		}
   301  	}
   302  
   303  	return result
   304  }