44package loader
55
66import (
7+ "cmp"
78 "fmt"
89 "reflect"
10+ "slices"
911 "sort"
1012
1113 "dario.cat/mergo"
@@ -52,10 +54,10 @@ func merge(configs []*types.Config) (*types.Config, error) {
5254}
5355
5456func mergeServices (base , override []types.ServiceConfig ) ([]types.ServiceConfig , error ) {
55- baseServices := mapByName ( base )
56- overrideServices := mapByName ( override )
57- specials := & specials {
58- m : map [reflect.Type ]func (dst , src reflect.Value ) error {
57+ mergeOpts := [] func ( * mergo. Config ){
58+ mergo . WithAppendSlice ,
59+ mergo . WithOverride ,
60+ mergo . WithTransformers ( & specials { m : map [reflect.Type ]func (dst , src reflect.Value ) error {
5961 reflect .PointerTo (reflect .TypeFor [types.LoggingConfig ]()): safelyMerge (mergeLoggingConfig ),
6062 reflect .TypeFor [[]types.ServicePortConfig ](): mergeSlice (toServicePortConfigsMap , toServicePortConfigsSlice ),
6163 reflect .TypeFor [[]types.ServiceSecretConfig ](): mergeSlice (toServiceSecretConfigsMap , toServiceSecretConfigsSlice ),
@@ -65,23 +67,34 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
6567 reflect .TypeFor [types.ShellCommand ](): mergeShellCommand ,
6668 reflect .PointerTo (reflect .TypeFor [types.ServiceNetworkConfig ]()): mergeServiceNetworkConfig ,
6769 reflect .PointerTo (reflect .TypeFor [uint64 ]()): mergeUint64 ,
68- },
70+ }}) ,
6971 }
70- for name , overrideService := range overrideServices {
71- if baseService , ok := baseServices [name ]; ok {
72- if err := mergo .Merge (& baseService , & overrideService , mergo .WithAppendSlice , mergo .WithOverride , mergo .WithTransformers (specials )); err != nil {
73- return base , fmt .Errorf ("cannot merge service %s: %w" , name , err )
72+
73+ baseServices := make (map [string ]types.ServiceConfig , len (base ))
74+ for _ , s := range base {
75+ baseServices [s .Name ] = s
76+ }
77+
78+ for _ , overrideService := range override {
79+ if baseService , ok := baseServices [overrideService .Name ]; ok {
80+ if err := mergo .Merge (& baseService , & overrideService , mergeOpts ... ); err != nil {
81+ return base , fmt .Errorf ("cannot merge service %s: %w" , overrideService .Name , err )
7482 }
75- baseServices [name ] = baseService
83+ baseServices [overrideService . Name ] = baseService
7684 continue
7785 }
78- baseServices [name ] = overrideService
86+ baseServices [overrideService . Name ] = overrideService
7987 }
88+
8089 services := make ([]types.ServiceConfig , 0 , len (baseServices ))
8190 for _ , baseService := range baseServices {
8291 services = append (services , baseService )
8392 }
84- sort .Slice (services , func (i , j int ) bool { return services [i ].Name < services [j ].Name })
93+
94+ slices .SortFunc (services , func (a , b types.ServiceConfig ) int {
95+ return cmp .Compare (a .Name , b .Name )
96+ })
97+
8598 return services , nil
8699}
87100
@@ -217,11 +230,13 @@ func sliceToMap(tomap tomapFn, v reflect.Value) (map[any]any, error) {
217230}
218231
219232func mergeLoggingConfig (dst , src reflect.Value ) error {
233+ dstDriver := dst .Elem ().FieldByName ("Driver" ).String ()
234+ srcDriver := src .Elem ().FieldByName ("Driver" ).String ()
235+
220236 // Same driver, merging options
221- if getLoggingDriver (dst .Elem ()) == getLoggingDriver (src .Elem ()) ||
222- getLoggingDriver (dst .Elem ()) == "" || getLoggingDriver (src .Elem ()) == "" {
223- if getLoggingDriver (dst .Elem ()) == "" {
224- dst .Elem ().FieldByName ("Driver" ).SetString (getLoggingDriver (src .Elem ()))
237+ if dstDriver == srcDriver || dstDriver == "" || srcDriver == "" {
238+ if dstDriver == "" {
239+ dst .Elem ().FieldByName ("Driver" ).SetString (srcDriver )
225240 }
226241 dstOptions := dst .Elem ().FieldByName ("Options" ).Interface ().(map [string ]string )
227242 srcOptions := src .Elem ().FieldByName ("Options" ).Interface ().(map [string ]string )
@@ -270,18 +285,6 @@ func mergeUint64(dst, src reflect.Value) error {
270285 return nil
271286}
272287
273- func getLoggingDriver (v reflect.Value ) string {
274- return v .FieldByName ("Driver" ).String ()
275- }
276-
277- func mapByName (services []types.ServiceConfig ) map [string ]types.ServiceConfig {
278- m := map [string ]types.ServiceConfig {}
279- for _ , service := range services {
280- m [service .Name ] = service
281- }
282- return m
283- }
284-
285288func mergeVolumes (base , override map [string ]types.VolumeConfig ) (map [string ]types.VolumeConfig , error ) {
286289 err := mergo .Map (& base , & override , mergo .WithOverride )
287290 return base , err
0 commit comments