github.com/itscaro/cli@v0.0.0-20190705081621-c9db0fe93829/cli/compose/loader/merge.go (about)

     1  package loader
     2  
     3  import (
     4  	"reflect"
     5  	"sort"
     6  
     7  	"github.com/docker/cli/cli/compose/types"
     8  	"github.com/imdario/mergo"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  type specials struct {
    13  	m map[reflect.Type]func(dst, src reflect.Value) error
    14  }
    15  
    16  func (s *specials) Transformer(t reflect.Type) func(dst, src reflect.Value) error {
    17  	if fn, ok := s.m[t]; ok {
    18  		return fn
    19  	}
    20  	return nil
    21  }
    22  
    23  func merge(configs []*types.Config) (*types.Config, error) {
    24  	base := configs[0]
    25  	for _, override := range configs[1:] {
    26  		var err error
    27  		base.Services, err = mergeServices(base.Services, override.Services)
    28  		if err != nil {
    29  			return base, errors.Wrapf(err, "cannot merge services from %s", override.Filename)
    30  		}
    31  		base.Volumes, err = mergeVolumes(base.Volumes, override.Volumes)
    32  		if err != nil {
    33  			return base, errors.Wrapf(err, "cannot merge volumes from %s", override.Filename)
    34  		}
    35  		base.Networks, err = mergeNetworks(base.Networks, override.Networks)
    36  		if err != nil {
    37  			return base, errors.Wrapf(err, "cannot merge networks from %s", override.Filename)
    38  		}
    39  		base.Secrets, err = mergeSecrets(base.Secrets, override.Secrets)
    40  		if err != nil {
    41  			return base, errors.Wrapf(err, "cannot merge secrets from %s", override.Filename)
    42  		}
    43  		base.Configs, err = mergeConfigs(base.Configs, override.Configs)
    44  		if err != nil {
    45  			return base, errors.Wrapf(err, "cannot merge configs from %s", override.Filename)
    46  		}
    47  	}
    48  	return base, nil
    49  }
    50  
    51  func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig, error) {
    52  	baseServices := mapByName(base)
    53  	overrideServices := mapByName(override)
    54  	specials := &specials{
    55  		m: map[reflect.Type]func(dst, src reflect.Value) error{
    56  			reflect.TypeOf(&types.LoggingConfig{}):           safelyMerge(mergeLoggingConfig),
    57  			reflect.TypeOf([]types.ServicePortConfig{}):      mergeSlice(toServicePortConfigsMap, toServicePortConfigsSlice),
    58  			reflect.TypeOf([]types.ServiceSecretConfig{}):    mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
    59  			reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
    60  		},
    61  	}
    62  	for name, overrideService := range overrideServices {
    63  		if baseService, ok := baseServices[name]; ok {
    64  			if err := mergo.Merge(&baseService, &overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(specials)); err != nil {
    65  				return base, errors.Wrapf(err, "cannot merge service %s", name)
    66  			}
    67  			baseServices[name] = baseService
    68  			continue
    69  		}
    70  		baseServices[name] = overrideService
    71  	}
    72  	services := []types.ServiceConfig{}
    73  	for _, baseService := range baseServices {
    74  		services = append(services, baseService)
    75  	}
    76  	sort.Slice(services, func(i, j int) bool { return services[i].Name < services[j].Name })
    77  	return services, nil
    78  }
    79  
    80  func toServiceSecretConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
    81  	secrets, ok := s.([]types.ServiceSecretConfig)
    82  	if !ok {
    83  		return nil, errors.Errorf("not a serviceSecretConfig: %v", s)
    84  	}
    85  	m := map[interface{}]interface{}{}
    86  	for _, secret := range secrets {
    87  		m[secret.Source] = secret
    88  	}
    89  	return m, nil
    90  }
    91  
    92  func toServiceConfigObjConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
    93  	secrets, ok := s.([]types.ServiceConfigObjConfig)
    94  	if !ok {
    95  		return nil, errors.Errorf("not a serviceSecretConfig: %v", s)
    96  	}
    97  	m := map[interface{}]interface{}{}
    98  	for _, secret := range secrets {
    99  		m[secret.Source] = secret
   100  	}
   101  	return m, nil
   102  }
   103  
   104  func toServicePortConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
   105  	ports, ok := s.([]types.ServicePortConfig)
   106  	if !ok {
   107  		return nil, errors.Errorf("not a servicePortConfig slice: %v", s)
   108  	}
   109  	m := map[interface{}]interface{}{}
   110  	for _, p := range ports {
   111  		m[p.Published] = p
   112  	}
   113  	return m, nil
   114  }
   115  
   116  func toServiceSecretConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
   117  	s := []types.ServiceSecretConfig{}
   118  	for _, v := range m {
   119  		s = append(s, v.(types.ServiceSecretConfig))
   120  	}
   121  	sort.Slice(s, func(i, j int) bool { return s[i].Source < s[j].Source })
   122  	dst.Set(reflect.ValueOf(s))
   123  	return nil
   124  }
   125  
   126  func toSServiceConfigObjConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
   127  	s := []types.ServiceConfigObjConfig{}
   128  	for _, v := range m {
   129  		s = append(s, v.(types.ServiceConfigObjConfig))
   130  	}
   131  	sort.Slice(s, func(i, j int) bool { return s[i].Source < s[j].Source })
   132  	dst.Set(reflect.ValueOf(s))
   133  	return nil
   134  }
   135  
   136  func toServicePortConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
   137  	s := []types.ServicePortConfig{}
   138  	for _, v := range m {
   139  		s = append(s, v.(types.ServicePortConfig))
   140  	}
   141  	sort.Slice(s, func(i, j int) bool { return s[i].Published < s[j].Published })
   142  	dst.Set(reflect.ValueOf(s))
   143  	return nil
   144  }
   145  
   146  type tomapFn func(s interface{}) (map[interface{}]interface{}, error)
   147  type writeValueFromMapFn func(reflect.Value, map[interface{}]interface{}) error
   148  
   149  func safelyMerge(mergeFn func(dst, src reflect.Value) error) func(dst, src reflect.Value) error {
   150  	return func(dst, src reflect.Value) error {
   151  		if src.IsNil() {
   152  			return nil
   153  		}
   154  		if dst.IsNil() {
   155  			dst.Set(src)
   156  			return nil
   157  		}
   158  		return mergeFn(dst, src)
   159  	}
   160  }
   161  
   162  func mergeSlice(tomap tomapFn, writeValue writeValueFromMapFn) func(dst, src reflect.Value) error {
   163  	return func(dst, src reflect.Value) error {
   164  		dstMap, err := sliceToMap(tomap, dst)
   165  		if err != nil {
   166  			return err
   167  		}
   168  		srcMap, err := sliceToMap(tomap, src)
   169  		if err != nil {
   170  			return err
   171  		}
   172  		if err := mergo.Map(&dstMap, srcMap, mergo.WithOverride); err != nil {
   173  			return err
   174  		}
   175  		return writeValue(dst, dstMap)
   176  	}
   177  }
   178  
   179  func sliceToMap(tomap tomapFn, v reflect.Value) (map[interface{}]interface{}, error) {
   180  	// check if valid
   181  	if !v.IsValid() {
   182  		return nil, errors.Errorf("invalid value : %+v", v)
   183  	}
   184  	return tomap(v.Interface())
   185  }
   186  
   187  func mergeLoggingConfig(dst, src reflect.Value) error {
   188  	// Same driver, merging options
   189  	if getLoggingDriver(dst.Elem()) == getLoggingDriver(src.Elem()) ||
   190  		getLoggingDriver(dst.Elem()) == "" || getLoggingDriver(src.Elem()) == "" {
   191  		if getLoggingDriver(dst.Elem()) == "" {
   192  			dst.Elem().FieldByName("Driver").SetString(getLoggingDriver(src.Elem()))
   193  		}
   194  		dstOptions := dst.Elem().FieldByName("Options").Interface().(map[string]string)
   195  		srcOptions := src.Elem().FieldByName("Options").Interface().(map[string]string)
   196  		return mergo.Merge(&dstOptions, srcOptions, mergo.WithOverride)
   197  	}
   198  	// Different driver, override with src
   199  	dst.Set(src)
   200  	return nil
   201  }
   202  
   203  func getLoggingDriver(v reflect.Value) string {
   204  	return v.FieldByName("Driver").String()
   205  }
   206  
   207  func mapByName(services []types.ServiceConfig) map[string]types.ServiceConfig {
   208  	m := map[string]types.ServiceConfig{}
   209  	for _, service := range services {
   210  		m[service.Name] = service
   211  	}
   212  	return m
   213  }
   214  
   215  func mergeVolumes(base, override map[string]types.VolumeConfig) (map[string]types.VolumeConfig, error) {
   216  	err := mergo.Map(&base, &override, mergo.WithOverride)
   217  	return base, err
   218  }
   219  
   220  func mergeNetworks(base, override map[string]types.NetworkConfig) (map[string]types.NetworkConfig, error) {
   221  	err := mergo.Map(&base, &override, mergo.WithOverride)
   222  	return base, err
   223  }
   224  
   225  func mergeSecrets(base, override map[string]types.SecretConfig) (map[string]types.SecretConfig, error) {
   226  	err := mergo.Map(&base, &override, mergo.WithOverride)
   227  	return base, err
   228  }
   229  
   230  func mergeConfigs(base, override map[string]types.ConfigObjConfig) (map[string]types.ConfigObjConfig, error) {
   231  	err := mergo.Map(&base, &override, mergo.WithOverride)
   232  	return base, err
   233  }