github.com/connyay/libcompose@v0.4.0/utils/util.go (about) 1 package utils 2 3 import ( 4 "encoding/json" 5 "sync" 6 7 "github.com/Sirupsen/logrus" 8 9 "gopkg.in/yaml.v2" 10 ) 11 12 // InParallel holds a pool and a waitgroup to execute tasks in parallel and to be able 13 // to wait for completion of all tasks. 14 type InParallel struct { 15 wg sync.WaitGroup 16 pool sync.Pool 17 } 18 19 // Add runs the specified task in parallel and adds it to the waitGroup. 20 func (i *InParallel) Add(task func() error) { 21 i.wg.Add(1) 22 23 go func() { 24 defer i.wg.Done() 25 err := task() 26 if err != nil { 27 i.pool.Put(err) 28 } 29 }() 30 } 31 32 // Wait waits for all tasks to complete and returns the latest error encountered if any. 33 func (i *InParallel) Wait() error { 34 i.wg.Wait() 35 obj := i.pool.Get() 36 if err, ok := obj.(error); ok { 37 return err 38 } 39 return nil 40 } 41 42 // ConvertByJSON converts a struct (src) to another one (target) using json marshalling/unmarshalling. 43 // If the structure are not compatible, this will throw an error as the unmarshalling will fail. 44 func ConvertByJSON(src, target interface{}) error { 45 newBytes, err := json.Marshal(src) 46 if err != nil { 47 return err 48 } 49 50 err = json.Unmarshal(newBytes, target) 51 if err != nil { 52 logrus.Errorf("Failed to unmarshall: %v\n%s", err, string(newBytes)) 53 } 54 return err 55 } 56 57 // Convert converts a struct (src) to another one (target) using yaml marshalling/unmarshalling. 58 // If the structure are not compatible, this will throw an error as the unmarshalling will fail. 59 func Convert(src, target interface{}) error { 60 newBytes, err := yaml.Marshal(src) 61 if err != nil { 62 return err 63 } 64 65 err = yaml.Unmarshal(newBytes, target) 66 if err != nil { 67 logrus.Errorf("Failed to unmarshall: %v\n%s", err, string(newBytes)) 68 } 69 return err 70 } 71 72 // CopySlice creates an exact copy of the provided string slice 73 func CopySlice(s []string) []string { 74 if s == nil { 75 return nil 76 } 77 r := make([]string, len(s)) 78 copy(r, s) 79 return r 80 } 81 82 // CopyMap creates an exact copy of the provided string-to-string map 83 func CopyMap(m map[string]string) map[string]string { 84 if m == nil { 85 return nil 86 } 87 r := map[string]string{} 88 for k, v := range m { 89 r[k] = v 90 } 91 return r 92 } 93 94 // FilterStringSet accepts a string set `s` (in the form of `map[string]bool`) and a filtering function `f` 95 // and returns a string set containing only the strings `x` for which `f(x) == true` 96 func FilterStringSet(s map[string]bool, f func(x string) bool) map[string]bool { 97 result := map[string]bool{} 98 for k := range s { 99 if f(k) { 100 result[k] = true 101 } 102 } 103 return result 104 } 105 106 // FilterString returns a json representation of the specified map 107 // that is used as filter for docker. 108 func FilterString(data map[string][]string) string { 109 // I can't imagine this would ever fail 110 bytes, _ := json.Marshal(data) 111 return string(bytes) 112 } 113 114 // Contains checks if the specified string (key) is present in the specified collection. 115 func Contains(collection []string, key string) bool { 116 for _, value := range collection { 117 if value == key { 118 return true 119 } 120 } 121 122 return false 123 } 124 125 // Merge performs a union of two string slices: the result is an unordered slice 126 // that includes every item from either argument exactly once 127 func Merge(coll1, coll2 []string) []string { 128 m := map[string]struct{}{} 129 for _, v := range append(coll1, coll2...) { 130 m[v] = struct{}{} 131 } 132 r := make([]string, 0, len(m)) 133 for k := range m { 134 r = append(r, k) 135 } 136 return r 137 } 138 139 // ConvertKeysToStrings converts map[interface{}] to map[string] recursively 140 func ConvertKeysToStrings(item interface{}) interface{} { 141 switch typedDatas := item.(type) { 142 case map[string]interface{}: 143 for key, value := range typedDatas { 144 typedDatas[key] = ConvertKeysToStrings(value) 145 } 146 return typedDatas 147 case map[interface{}]interface{}: 148 newMap := make(map[string]interface{}) 149 for key, value := range typedDatas { 150 stringKey := key.(string) 151 newMap[stringKey] = ConvertKeysToStrings(value) 152 } 153 return newMap 154 case []interface{}: 155 for i, value := range typedDatas { 156 typedDatas[i] = ConvertKeysToStrings(value) 157 } 158 return typedDatas 159 default: 160 return item 161 } 162 }