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