github.com/ali-iotechsys/cli@v20.10.0+incompatible/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 reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig, 61 reflect.TypeOf(&types.ServiceNetworkConfig{}): mergeServiceNetworkConfig, 62 }, 63 } 64 for name, overrideService := range overrideServices { 65 overrideService := overrideService 66 if baseService, ok := baseServices[name]; ok { 67 if err := mergo.Merge(&baseService, &overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(specials)); err != nil { 68 return base, errors.Wrapf(err, "cannot merge service %s", name) 69 } 70 baseServices[name] = baseService 71 continue 72 } 73 baseServices[name] = overrideService 74 } 75 services := []types.ServiceConfig{} 76 for _, baseService := range baseServices { 77 services = append(services, baseService) 78 } 79 sort.Slice(services, func(i, j int) bool { return services[i].Name < services[j].Name }) 80 return services, nil 81 } 82 83 func toServiceSecretConfigsMap(s interface{}) (map[interface{}]interface{}, error) { 84 secrets, ok := s.([]types.ServiceSecretConfig) 85 if !ok { 86 return nil, errors.Errorf("not a serviceSecretConfig: %v", s) 87 } 88 m := map[interface{}]interface{}{} 89 for _, secret := range secrets { 90 m[secret.Source] = secret 91 } 92 return m, nil 93 } 94 95 func toServiceConfigObjConfigsMap(s interface{}) (map[interface{}]interface{}, error) { 96 secrets, ok := s.([]types.ServiceConfigObjConfig) 97 if !ok { 98 return nil, errors.Errorf("not a serviceSecretConfig: %v", s) 99 } 100 m := map[interface{}]interface{}{} 101 for _, secret := range secrets { 102 m[secret.Source] = secret 103 } 104 return m, nil 105 } 106 107 func toServicePortConfigsMap(s interface{}) (map[interface{}]interface{}, error) { 108 ports, ok := s.([]types.ServicePortConfig) 109 if !ok { 110 return nil, errors.Errorf("not a servicePortConfig slice: %v", s) 111 } 112 m := map[interface{}]interface{}{} 113 for _, p := range ports { 114 m[p.Published] = p 115 } 116 return m, nil 117 } 118 119 func toServiceSecretConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error { 120 s := []types.ServiceSecretConfig{} 121 for _, v := range m { 122 s = append(s, v.(types.ServiceSecretConfig)) 123 } 124 sort.Slice(s, func(i, j int) bool { return s[i].Source < s[j].Source }) 125 dst.Set(reflect.ValueOf(s)) 126 return nil 127 } 128 129 func toSServiceConfigObjConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error { 130 s := []types.ServiceConfigObjConfig{} 131 for _, v := range m { 132 s = append(s, v.(types.ServiceConfigObjConfig)) 133 } 134 sort.Slice(s, func(i, j int) bool { return s[i].Source < s[j].Source }) 135 dst.Set(reflect.ValueOf(s)) 136 return nil 137 } 138 139 func toServicePortConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error { 140 s := []types.ServicePortConfig{} 141 for _, v := range m { 142 s = append(s, v.(types.ServicePortConfig)) 143 } 144 sort.Slice(s, func(i, j int) bool { return s[i].Published < s[j].Published }) 145 dst.Set(reflect.ValueOf(s)) 146 return nil 147 } 148 149 type tomapFn func(s interface{}) (map[interface{}]interface{}, error) 150 type writeValueFromMapFn func(reflect.Value, map[interface{}]interface{}) error 151 152 func safelyMerge(mergeFn func(dst, src reflect.Value) error) func(dst, src reflect.Value) error { 153 return func(dst, src reflect.Value) error { 154 if src.IsNil() { 155 return nil 156 } 157 if dst.IsNil() { 158 dst.Set(src) 159 return nil 160 } 161 return mergeFn(dst, src) 162 } 163 } 164 165 func mergeSlice(tomap tomapFn, writeValue writeValueFromMapFn) func(dst, src reflect.Value) error { 166 return func(dst, src reflect.Value) error { 167 dstMap, err := sliceToMap(tomap, dst) 168 if err != nil { 169 return err 170 } 171 srcMap, err := sliceToMap(tomap, src) 172 if err != nil { 173 return err 174 } 175 if err := mergo.Map(&dstMap, srcMap, mergo.WithOverride); err != nil { 176 return err 177 } 178 return writeValue(dst, dstMap) 179 } 180 } 181 182 func sliceToMap(tomap tomapFn, v reflect.Value) (map[interface{}]interface{}, error) { 183 // check if valid 184 if !v.IsValid() { 185 return nil, errors.Errorf("invalid value : %+v", v) 186 } 187 return tomap(v.Interface()) 188 } 189 190 func mergeLoggingConfig(dst, src reflect.Value) error { 191 // Same driver, merging options 192 if getLoggingDriver(dst.Elem()) == getLoggingDriver(src.Elem()) || 193 getLoggingDriver(dst.Elem()) == "" || getLoggingDriver(src.Elem()) == "" { 194 if getLoggingDriver(dst.Elem()) == "" { 195 dst.Elem().FieldByName("Driver").SetString(getLoggingDriver(src.Elem())) 196 } 197 dstOptions := dst.Elem().FieldByName("Options").Interface().(map[string]string) 198 srcOptions := src.Elem().FieldByName("Options").Interface().(map[string]string) 199 return mergo.Merge(&dstOptions, srcOptions, mergo.WithOverride) 200 } 201 // Different driver, override with src 202 dst.Set(src) 203 return nil 204 } 205 206 //nolint: unparam 207 func mergeUlimitsConfig(dst, src reflect.Value) error { 208 if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() { 209 dst.Elem().Set(src.Elem()) 210 } 211 return nil 212 } 213 214 //nolint: unparam 215 func mergeServiceNetworkConfig(dst, src reflect.Value) error { 216 if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() { 217 dst.Elem().FieldByName("Aliases").Set(src.Elem().FieldByName("Aliases")) 218 if ipv4 := src.Elem().FieldByName("Ipv4Address").Interface().(string); ipv4 != "" { 219 dst.Elem().FieldByName("Ipv4Address").SetString(ipv4) 220 } 221 if ipv6 := src.Elem().FieldByName("Ipv6Address").Interface().(string); ipv6 != "" { 222 dst.Elem().FieldByName("Ipv6Address").SetString(ipv6) 223 } 224 } 225 return nil 226 } 227 228 func getLoggingDriver(v reflect.Value) string { 229 return v.FieldByName("Driver").String() 230 } 231 232 func mapByName(services []types.ServiceConfig) map[string]types.ServiceConfig { 233 m := map[string]types.ServiceConfig{} 234 for _, service := range services { 235 m[service.Name] = service 236 } 237 return m 238 } 239 240 func mergeVolumes(base, override map[string]types.VolumeConfig) (map[string]types.VolumeConfig, error) { 241 err := mergo.Map(&base, &override, mergo.WithOverride) 242 return base, err 243 } 244 245 func mergeNetworks(base, override map[string]types.NetworkConfig) (map[string]types.NetworkConfig, error) { 246 err := mergo.Map(&base, &override, mergo.WithOverride) 247 return base, err 248 } 249 250 func mergeSecrets(base, override map[string]types.SecretConfig) (map[string]types.SecretConfig, error) { 251 err := mergo.Map(&base, &override, mergo.WithOverride) 252 return base, err 253 } 254 255 func mergeConfigs(base, override map[string]types.ConfigObjConfig) (map[string]types.ConfigObjConfig, error) { 256 err := mergo.Map(&base, &override, mergo.WithOverride) 257 return base, err 258 }