in pkg/loader/compose/v3.go [725:961]
func mergeComposeObject(oldCompose *types.Config, newCompose *types.Config) (*types.Config, error) {
if oldCompose == nil || newCompose == nil {
return nil, fmt.Errorf("merge multiple compose error, compose config is nil")
}
oldComposeServiceNameMap := make(map[string]int, len(oldCompose.Services))
for index, service := range oldCompose.Services {
oldComposeServiceNameMap[service.Name] = index
}
for _, service := range newCompose.Services {
index := 0
if tmpIndex, ok := oldComposeServiceNameMap[service.Name]; !ok {
oldCompose.Services = append(oldCompose.Services, service)
continue
} else {
index = tmpIndex
}
tmpOldService := oldCompose.Services[index]
if service.Build.Dockerfile != "" {
tmpOldService.Build = service.Build
}
if len(service.CapAdd) != 0 {
tmpOldService.CapAdd = service.CapAdd
}
if len(service.CapDrop) != 0 {
tmpOldService.CapDrop = service.CapDrop
}
if service.CgroupParent != "" {
tmpOldService.CgroupParent = service.CgroupParent
}
if len(service.Command) != 0 {
tmpOldService.Command = service.Command
}
if len(service.Configs) != 0 {
tmpOldService.Configs = service.Configs
}
if service.ContainerName != "" {
tmpOldService.ContainerName = service.ContainerName
}
if service.CredentialSpec.File != "" || service.CredentialSpec.Registry != "" {
tmpOldService.CredentialSpec = service.CredentialSpec
}
if len(service.DependsOn) != 0 {
tmpOldService.DependsOn = service.DependsOn
}
if service.Deploy.Mode != "" {
tmpOldService.Deploy = service.Deploy
}
if service.Deploy.Resources.Limits != nil {
tmpOldService.Deploy.Resources.Limits = service.Deploy.Resources.Limits
}
if service.Deploy.Resources.Reservations != nil {
tmpOldService.Deploy.Resources.Reservations = service.Deploy.Resources.Reservations
}
if service.Deploy.Replicas != nil {
tmpOldService.Deploy.Replicas = service.Deploy.Replicas
}
if len(service.Devices) != 0 {
// merge the 2 sets of values
// TODO: need to merge the sets based on target values
// Not implemented yet as we don't convert devices to k8s anyway
tmpOldService.Devices = service.Devices
}
if len(service.DNS) != 0 {
// concat the 2 sets of values
tmpOldService.DNS = append(tmpOldService.DNS, service.DNS...)
}
if len(service.DNSSearch) != 0 {
// concat the 2 sets of values
tmpOldService.DNSSearch = append(tmpOldService.DNSSearch, service.DNSSearch...)
}
if service.DomainName != "" {
tmpOldService.DomainName = service.DomainName
}
if len(service.Entrypoint) != 0 {
tmpOldService.Entrypoint = service.Entrypoint
}
if len(service.Environment) != 0 {
// merge the 2 sets of values
for k, v := range service.Environment {
tmpOldService.Environment[k] = v
}
}
if len(service.EnvFile) != 0 {
tmpOldService.EnvFile = service.EnvFile
}
if len(service.Expose) != 0 {
// concat the 2 sets of values
tmpOldService.Expose = append(tmpOldService.Expose, service.Expose...)
}
if len(service.ExternalLinks) != 0 {
// concat the 2 sets of values
tmpOldService.ExternalLinks = append(tmpOldService.ExternalLinks, service.ExternalLinks...)
}
if len(service.ExtraHosts) != 0 {
tmpOldService.ExtraHosts = service.ExtraHosts
}
if service.Hostname != "" {
tmpOldService.Hostname = service.Hostname
}
if service.HealthCheck != nil {
tmpOldService.HealthCheck = service.HealthCheck
}
if service.Image != "" {
tmpOldService.Image = service.Image
}
if service.Ipc != "" {
tmpOldService.Ipc = service.Ipc
}
if len(service.Labels) != 0 {
// merge the 2 sets of values
if tmpOldService.Labels == nil {
tmpOldService.Labels = make(map[string]string)
}
for k, v := range service.Labels {
tmpOldService.Labels[k] = v
}
}
if len(service.Links) != 0 {
tmpOldService.Links = service.Links
}
if service.Logging != nil {
tmpOldService.Logging = service.Logging
}
if service.MacAddress != "" {
tmpOldService.MacAddress = service.MacAddress
}
if service.NetworkMode != "" {
tmpOldService.NetworkMode = service.NetworkMode
}
if len(service.Networks) != 0 {
tmpOldService.Networks = service.Networks
}
if service.Pid != "" {
tmpOldService.Pid = service.Pid
}
if len(service.Ports) != 0 {
// concat the 2 sets of values
tmpOldService.Ports = append(tmpOldService.Ports, service.Ports...)
}
if service.Privileged != tmpOldService.Privileged {
tmpOldService.Privileged = service.Privileged
}
if service.ReadOnly != tmpOldService.ReadOnly {
tmpOldService.ReadOnly = service.ReadOnly
}
if service.Restart != "" {
tmpOldService.Restart = service.Restart
}
if len(service.Secrets) != 0 {
tmpOldService.Secrets = service.Secrets
}
if len(service.SecurityOpt) != 0 {
tmpOldService.SecurityOpt = service.SecurityOpt
}
if service.StdinOpen != tmpOldService.StdinOpen {
tmpOldService.StdinOpen = service.StdinOpen
}
if service.StopSignal != "" {
tmpOldService.StopSignal = service.StopSignal
}
if len(service.Tmpfs) != 0 {
// concat the 2 sets of values
tmpOldService.Tmpfs = append(tmpOldService.Tmpfs, service.Tmpfs...)
}
if service.Tty != tmpOldService.Tty {
tmpOldService.Tty = service.Tty
}
if len(service.Ulimits) != 0 {
tmpOldService.Ulimits = service.Ulimits
}
if service.User != "" {
tmpOldService.User = service.User
}
if len(service.Volumes) != 0 {
// merge the 2 sets of values
// Store volumes by Target
volumeConfigsMap := make(map[string]types.ServiceVolumeConfig)
// map is not iterated in the same order.
// but why only this code cause test error?
var keys []string
// populate the older values
for _, volConfig := range tmpOldService.Volumes {
volumeConfigsMap[volConfig.Target] = volConfig
keys = append(keys, volConfig.Target)
}
// add the new values, overriding as needed
for _, volConfig := range service.Volumes {
if _, ok := volumeConfigsMap[volConfig.Target]; !ok {
keys = append(keys, volConfig.Target)
}
volumeConfigsMap[volConfig.Target] = volConfig
}
// get the new list of volume configs
var volumes []types.ServiceVolumeConfig
for _, key := range keys {
volumes = append(volumes, volumeConfigsMap[key])
}
tmpOldService.Volumes = volumes
}
if service.WorkingDir != "" {
tmpOldService.WorkingDir = service.WorkingDir
}
oldCompose.Services[index] = tmpOldService
}
// Merge the networks information
for idx, network := range newCompose.Networks {
oldCompose.Networks[idx] = network
}
// Merge the volumes information
for idx, volume := range newCompose.Volumes {
oldCompose.Volumes[idx] = volume
}
// Merge the secrets information
for idx, secret := range newCompose.Secrets {
oldCompose.Secrets[idx] = secret
}
// Merge the configs information
for idx, config := range newCompose.Configs {
oldCompose.Configs[idx] = config
}
return oldCompose, nil
}