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  }