package runconfig import ( "github.com/dotcloud/docker/nat" "github.com/dotcloud/docker/utils" "strings" ) func Merge(userConf, imageConf *Config) error { if userConf.User == "" { userConf.User = imageConf.User } if userConf.Memory == 0 { userConf.Memory = imageConf.Memory } if userConf.MemorySwap == 0 { userConf.MemorySwap = imageConf.MemorySwap } if userConf.CpuShares == 0 { userConf.CpuShares = imageConf.CpuShares } if userConf.ExposedPorts == nil || len(userConf.ExposedPorts) == 0 { userConf.ExposedPorts = imageConf.ExposedPorts } else if imageConf.ExposedPorts != nil { if userConf.ExposedPorts == nil { userConf.ExposedPorts = make(nat.PortSet) } for port := range imageConf.ExposedPorts { if _, exists := userConf.ExposedPorts[port]; !exists { userConf.ExposedPorts[port] = struct{}{} } } } if userConf.PortSpecs != nil && len(userConf.PortSpecs) > 0 { if userConf.ExposedPorts == nil { userConf.ExposedPorts = make(nat.PortSet) } ports, _, err := nat.ParsePortSpecs(userConf.PortSpecs) if err != nil { return err } for port := range ports { if _, exists := userConf.ExposedPorts[port]; !exists { userConf.ExposedPorts[port] = struct{}{} } } userConf.PortSpecs = nil } if imageConf.PortSpecs != nil && len(imageConf.PortSpecs) > 0 { // FIXME: I think we can safely remove this. Leaving it for now for the sake of reverse-compat paranoia. utils.Debugf("Migrating image port specs to containter: %s", strings.Join(imageConf.PortSpecs, ", ")) if userConf.ExposedPorts == nil { userConf.ExposedPorts = make(nat.PortSet) } ports, _, err := nat.ParsePortSpecs(imageConf.PortSpecs) if err != nil { return err } for port := range ports { if _, exists := userConf.ExposedPorts[port]; !exists { userConf.ExposedPorts[port] = struct{}{} } } } if !userConf.Tty { userConf.Tty = imageConf.Tty } if !userConf.OpenStdin { userConf.OpenStdin = imageConf.OpenStdin } if !userConf.StdinOnce { userConf.StdinOnce = imageConf.StdinOnce } if userConf.Env == nil || len(userConf.Env) == 0 { userConf.Env = imageConf.Env } else { for _, imageEnv := range imageConf.Env { found := false imageEnvKey := strings.Split(imageEnv, "=")[0] for _, userEnv := range userConf.Env { userEnvKey := strings.Split(userEnv, "=")[0] if imageEnvKey == userEnvKey { found = true } } if !found { userConf.Env = append(userConf.Env, imageEnv) } } } if userConf.Cmd == nil || len(userConf.Cmd) == 0 { userConf.Cmd = imageConf.Cmd } if userConf.Dns == nil || len(userConf.Dns) == 0 { userConf.Dns = imageConf.Dns } else { dnsSet := make(map[string]struct{}, len(userConf.Dns)) for _, dns := range userConf.Dns { dnsSet[dns] = struct{}{} } for _, dns := range imageConf.Dns { if _, exists := dnsSet[dns]; !exists { userConf.Dns = append(userConf.Dns, dns) } } } if userConf.DnsSearch == nil || len(userConf.DnsSearch) == 0 { userConf.DnsSearch = imageConf.DnsSearch } else { //duplicates aren't an issue here userConf.DnsSearch = append(userConf.DnsSearch, imageConf.DnsSearch...) } if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 { userConf.Entrypoint = imageConf.Entrypoint } if userConf.WorkingDir == "" { userConf.WorkingDir = imageConf.WorkingDir } if userConf.VolumesFrom == "" { userConf.VolumesFrom = imageConf.VolumesFrom } if userConf.Volumes == nil || len(userConf.Volumes) == 0 { userConf.Volumes = imageConf.Volumes } else { for k, v := range imageConf.Volumes { userConf.Volumes[k] = v } } return nil }