You've already forked dcmerge
							
							
		
			All checks were successful
		
		
	
	Golang Tests / unittest (push) Successful in 28s
				
			Markdown linter / markdown-lint (push) Successful in 3s
				
			Golang CI lint / golangci (stable, ubuntu-latest-amd64) (push) Successful in 1m49s
				
			Golang CI lint / golangci (stable, ubuntu-latest-arm64) (push) Successful in 2m13s
				
			
		
			
				
	
	
		
			2301 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			2301 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package dockerCompose
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"regexp"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"gopkg.in/yaml.v3"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	environmentDelimiter  string = "="
 | 
						|
	labelDelimiter        string = "="
 | 
						|
	volumeDelimiter       string = ":"
 | 
						|
	portDelimiter         string = ":"
 | 
						|
	portProtocolDelimiter string = "/"
 | 
						|
)
 | 
						|
 | 
						|
type Config struct {
 | 
						|
	Networks map[string]*Network `json:"networks,omitempty" yaml:"networks,omitempty"`
 | 
						|
	Secrets  map[string]*Secret  `json:"secrets,omitempty" yaml:"secrets,omitempty"`
 | 
						|
	Services map[string]*Service `json:"services,omitempty" yaml:"services,omitempty"`
 | 
						|
	Version  string              `json:"version,omitempty" yaml:"version,omitempty"`
 | 
						|
	Volumes  map[string]*Volume  `json:"volumes,omitempty" yaml:"volumes,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (c *Config) Equal(equalable Equalable) bool {
 | 
						|
	config, ok := equalable.(*Config)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case c == nil && config == nil:
 | 
						|
		return true
 | 
						|
	case c != nil && config == nil:
 | 
						|
		fallthrough
 | 
						|
	case c == nil && config != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return EqualStringMap(c.Networks, config.Networks) &&
 | 
						|
			EqualStringMap(c.Secrets, config.Secrets) &&
 | 
						|
			EqualStringMap(c.Services, config.Services) &&
 | 
						|
			c.Version == config.Version &&
 | 
						|
			EqualStringMap(c.Volumes, config.Volumes)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ExistsNetwork returns true if a network with the passed named exists.
 | 
						|
func (c *Config) ExistsNetwork(name string) bool {
 | 
						|
	return ExistsInMap(c.Networks, name)
 | 
						|
}
 | 
						|
 | 
						|
// ExistsSecret returns true if a secret with the passed named exists.
 | 
						|
func (c *Config) ExistsSecret(name string) bool {
 | 
						|
	return ExistsInMap(c.Secrets, name)
 | 
						|
}
 | 
						|
 | 
						|
// ExistsService returns true if a service with the passed named exists.
 | 
						|
func (c *Config) ExistsService(name string) bool {
 | 
						|
	return ExistsInMap(c.Services, name)
 | 
						|
}
 | 
						|
 | 
						|
// ExistsVolumes returns true if a volume with the passed named exists.
 | 
						|
func (c *Config) ExistsVolume(name string) bool {
 | 
						|
	return ExistsInMap(c.Volumes, name)
 | 
						|
}
 | 
						|
 | 
						|
// Merge adds only a missing network, secret, service and volume.
 | 
						|
func (c *Config) Merge(config *Config) {
 | 
						|
	for name, network := range config.Networks {
 | 
						|
		if !c.ExistsNetwork(name) {
 | 
						|
			if c.Networks == nil {
 | 
						|
				c.Networks = make(map[string]*Network)
 | 
						|
			}
 | 
						|
			c.Networks[name] = network
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for name, secret := range config.Secrets {
 | 
						|
		if !c.ExistsSecret(name) {
 | 
						|
			if c.Secrets == nil {
 | 
						|
				c.Secrets = make(map[string]*Secret)
 | 
						|
			}
 | 
						|
			c.Secrets[name] = secret
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for name, service := range config.Services {
 | 
						|
		if !c.ExistsService(name) {
 | 
						|
			if c.Services == nil {
 | 
						|
				c.Services = make(map[string]*Service)
 | 
						|
			}
 | 
						|
			c.Services[name] = service
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for name, volume := range config.Volumes {
 | 
						|
		if !c.ExistsVolume(name) {
 | 
						|
			if c.Volumes == nil {
 | 
						|
				c.Volumes = make(map[string]*Volume)
 | 
						|
			}
 | 
						|
			c.Volumes[name] = volume
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges a config and overwrite already existing properties
 | 
						|
func (c *Config) MergeExistingWin(config *Config) {
 | 
						|
	switch {
 | 
						|
	case c == nil && config == nil:
 | 
						|
		fallthrough
 | 
						|
	case c != nil && config == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer c *Config
 | 
						|
	// to a new initialized config without returning the Config
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case c == nil && config != nil:
 | 
						|
	// 	c = NewConfig()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		c.mergeExistingWinNetworks(config.Networks)
 | 
						|
		c.mergeExistingWinSecrets(config.Secrets)
 | 
						|
		c.mergeExistingWinServices(config.Services)
 | 
						|
		c.mergeExistingWinVersion(config.Version)
 | 
						|
		c.mergeExistingWinVolumes(config.Volumes)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges a config and overwrite already existing properties
 | 
						|
func (c *Config) MergeLastWin(config *Config) {
 | 
						|
	switch {
 | 
						|
	case c == nil && config == nil:
 | 
						|
		fallthrough
 | 
						|
	case c != nil && config == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer c *Config
 | 
						|
	// to a new initialized config without returning the Config
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case c == nil && config != nil:
 | 
						|
	// 	c = NewConfig()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		c.mergeLastWinNetworks(config.Networks)
 | 
						|
		c.mergeLastWinSecrets(config.Secrets)
 | 
						|
		c.mergeLastWinServices(config.Services)
 | 
						|
		c.mergeLastWinVersion(config.Version)
 | 
						|
		c.mergeLastWinVolumes(config.Volumes)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeExistingWinVersion(version string) {
 | 
						|
	if len(c.Version) <= 0 {
 | 
						|
		c.Version = version
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeExistingWinNetworks(networks map[string]*Network) {
 | 
						|
	for networkName, network := range networks {
 | 
						|
		if network == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsNetwork(networkName) {
 | 
						|
			c.Networks[networkName].MergeExistingWin(network)
 | 
						|
		} else {
 | 
						|
			c.Networks[networkName] = network
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeExistingWinSecrets(secrets map[string]*Secret) {
 | 
						|
	for secretName, secret := range secrets {
 | 
						|
		if secret == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsNetwork(secretName) {
 | 
						|
			c.Secrets[secretName].MergeExistingWin(secret)
 | 
						|
		} else {
 | 
						|
			c.Secrets[secretName] = secret
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeExistingWinServices(services map[string]*Service) {
 | 
						|
	for serviceName, service := range services {
 | 
						|
		if service == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsService(serviceName) {
 | 
						|
			c.Services[serviceName].MergeExistingWin(service)
 | 
						|
		} else {
 | 
						|
			c.Services[serviceName] = service
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeExistingWinVolumes(volumes map[string]*Volume) {
 | 
						|
	for volumeName, volume := range volumes {
 | 
						|
		if volume == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsNetwork(volumeName) {
 | 
						|
			c.Volumes[volumeName].MergeExistingWin(volume)
 | 
						|
		} else {
 | 
						|
			c.Volumes[volumeName] = volume
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeLastWinVersion(version string) {
 | 
						|
	if c.Version != version {
 | 
						|
		c.Version = version
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeLastWinNetworks(networks map[string]*Network) {
 | 
						|
	for networkName, network := range networks {
 | 
						|
		if network == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsNetwork(networkName) {
 | 
						|
			c.Networks[networkName].MergeLastWin(network)
 | 
						|
		} else {
 | 
						|
			c.Networks[networkName] = network
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeLastWinSecrets(secrets map[string]*Secret) {
 | 
						|
	for secretName, secret := range secrets {
 | 
						|
		if secret == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsNetwork(secretName) {
 | 
						|
			c.Secrets[secretName].MergeLastWin(secret)
 | 
						|
		} else {
 | 
						|
			c.Secrets[secretName] = secret
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeLastWinServices(services map[string]*Service) {
 | 
						|
	for serviceName, service := range services {
 | 
						|
		if service == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsService(serviceName) {
 | 
						|
			c.Services[serviceName].MergeLastWin(service)
 | 
						|
		} else {
 | 
						|
			c.Services[serviceName] = service
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Config) mergeLastWinVolumes(volumes map[string]*Volume) {
 | 
						|
	for volumeName, volume := range volumes {
 | 
						|
		if volume == nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c.ExistsNetwork(volumeName) {
 | 
						|
			c.Volumes[volumeName].MergeLastWin(volume)
 | 
						|
		} else {
 | 
						|
			c.Volumes[volumeName] = volume
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewConfig() *Config {
 | 
						|
	return &Config{
 | 
						|
		Services: make(map[string]*Service),
 | 
						|
		Networks: make(map[string]*Network),
 | 
						|
		Secrets:  make(map[string]*Secret),
 | 
						|
		Volumes:  make(map[string]*Volume),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type Network struct {
 | 
						|
	External bool         `json:"external,omitempty" yaml:"external,omitempty"`
 | 
						|
	Driver   string       `json:"driver,omitempty" yaml:"driver,omitempty"`
 | 
						|
	IPAM     *NetworkIPAM `json:"ipam,omitempty" yaml:"ipam,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (n *Network) Equal(equalable Equalable) bool {
 | 
						|
	network, ok := equalable.(*Network)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case n == nil && network == nil:
 | 
						|
		return true
 | 
						|
	case n != nil && network == nil:
 | 
						|
		fallthrough
 | 
						|
	case n == nil && network != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return n.External == network.External &&
 | 
						|
			n.Driver == network.Driver &&
 | 
						|
			n.IPAM.Equal(network.IPAM)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Network) MergeExistingWin(network *Network) {
 | 
						|
	switch {
 | 
						|
	case n == nil && network == nil:
 | 
						|
		fallthrough
 | 
						|
	case n != nil && network == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer n *Network
 | 
						|
	// to a new initialized network without returning the Network
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case n == nil && network != nil:
 | 
						|
	// 	c = NewCNetwork()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		n.mergeExistingWinIPAM(network.IPAM)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Network) MergeLastWin(network *Network) {
 | 
						|
	switch {
 | 
						|
	case n == nil && network == nil:
 | 
						|
		fallthrough
 | 
						|
	case n != nil && network == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer n *Network
 | 
						|
	// to a new initialized network without returning the Network
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case n == nil && network != nil:
 | 
						|
	// 	c = NewCNetwork()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		n.mergeLastWinIPAM(network.IPAM)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Network) mergeExistingWinIPAM(networkIPAM *NetworkIPAM) {
 | 
						|
	if !n.IPAM.Equal(networkIPAM) {
 | 
						|
		n.IPAM.MergeExistingWin(networkIPAM)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Network) mergeLastWinIPAM(networkIPAM *NetworkIPAM) {
 | 
						|
	if !n.IPAM.Equal(networkIPAM) {
 | 
						|
		n.IPAM.MergeLastWin(networkIPAM)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewNetwork() *Network {
 | 
						|
	return &Network{
 | 
						|
		External: false,
 | 
						|
		IPAM:     new(NetworkIPAM),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type NetworkIPAM struct {
 | 
						|
	Configs []*NetworkIPAMConfig `json:"config,omitempty" yaml:"config,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (nIPAM *NetworkIPAM) Equal(equalable Equalable) bool {
 | 
						|
	networkIPAM, ok := equalable.(*NetworkIPAM)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case nIPAM == nil && networkIPAM == nil:
 | 
						|
		return true
 | 
						|
	case nIPAM != nil && networkIPAM == nil:
 | 
						|
		fallthrough
 | 
						|
	case nIPAM == nil && networkIPAM != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return Equal(nIPAM.Configs, networkIPAM.Configs)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (nIPAM *NetworkIPAM) MergeExistingWin(networkIPAM *NetworkIPAM) {
 | 
						|
	switch {
 | 
						|
	case nIPAM == nil && networkIPAM == nil:
 | 
						|
		fallthrough
 | 
						|
	case nIPAM != nil && networkIPAM == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer n *NetworkIPAM
 | 
						|
	// to a new initialized networkIPAM without returning the NetworkIPAM
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case nIPAM == nil && networkIPAM != nil:
 | 
						|
	// 	c = NewNetworkIPAM()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		nIPAM.mergeExistingWinConfig(networkIPAM.Configs)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (nIPAM *NetworkIPAM) MergeLastWin(networkIPAM *NetworkIPAM) {
 | 
						|
	switch {
 | 
						|
	case nIPAM == nil && networkIPAM == nil:
 | 
						|
		fallthrough
 | 
						|
	case nIPAM != nil && networkIPAM == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer n *NetworkIPAM
 | 
						|
	// to a new initialized networkIPAM without returning the NetworkIPAM
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case nIPAM == nil && networkIPAM != nil:
 | 
						|
	// 	c = NewNetworkIPAM()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		nIPAM.mergeLastWinConfig(networkIPAM.Configs)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (nIPAM *NetworkIPAM) mergeExistingWinConfig(networkIPAMConfigs []*NetworkIPAMConfig) {
 | 
						|
	for _, networkIPAMConfig := range networkIPAMConfigs {
 | 
						|
		if !existsInSlice(nIPAM.Configs, networkIPAMConfig) {
 | 
						|
			nIPAM.Configs = append(nIPAM.Configs, networkIPAMConfig)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (nIPAM *NetworkIPAM) mergeLastWinConfig(networkIPAMConfigs []*NetworkIPAMConfig) {
 | 
						|
	for _, networkIPAMConfig := range networkIPAMConfigs {
 | 
						|
		if !existsInSlice(nIPAM.Configs, networkIPAMConfig) {
 | 
						|
			nIPAM.Configs = append(nIPAM.Configs, networkIPAMConfig)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewNetworkIPAM() *NetworkIPAM {
 | 
						|
	return &NetworkIPAM{
 | 
						|
		Configs: make([]*NetworkIPAMConfig, 0),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type NetworkIPAMConfig struct {
 | 
						|
	Subnet string `json:"subnet,omitempty" yaml:"subnet,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (nIPAMConfig *NetworkIPAMConfig) Equal(equalable Equalable) bool {
 | 
						|
	networkIPAMConfig, ok := equalable.(*NetworkIPAMConfig)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case nIPAMConfig == nil && networkIPAMConfig == nil:
 | 
						|
		return true
 | 
						|
	case nIPAMConfig != nil && networkIPAMConfig == nil:
 | 
						|
		fallthrough
 | 
						|
	case nIPAMConfig == nil && networkIPAMConfig != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return nIPAMConfig.Subnet == networkIPAMConfig.Subnet
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewNetworkIPAMConfig() *NetworkIPAMConfig {
 | 
						|
	return &NetworkIPAMConfig{}
 | 
						|
}
 | 
						|
 | 
						|
type Secret struct {
 | 
						|
	File string `json:"file,omitempty" yaml:"file,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (s *Secret) Equal(equalable Equalable) bool {
 | 
						|
	secret, ok := equalable.(*Secret)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case s == nil && secret == nil:
 | 
						|
		return true
 | 
						|
	case s != nil && secret == nil:
 | 
						|
		fallthrough
 | 
						|
	case s == nil && secret != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return s.File == secret.File
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin merges adds or overwrite the attributes of the passed secret
 | 
						|
// with the existing one.
 | 
						|
func (s *Secret) MergeExistingWin(secret *Secret) {
 | 
						|
	if len(s.File) <= 0 {
 | 
						|
		s.File = secret.File
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed secret
 | 
						|
// with the existing one.
 | 
						|
func (s *Secret) MergeLastWin(secret *Secret) {
 | 
						|
	if !s.Equal(secret) {
 | 
						|
		s.File = secret.File
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewSecret() *Secret {
 | 
						|
	return &Secret{}
 | 
						|
}
 | 
						|
 | 
						|
type Service struct {
 | 
						|
	Command            []string                   `json:"command,omitempty" yaml:"command,omitempty"`
 | 
						|
	CapabilitiesAdd    []string                   `json:"cap_add,omitempty" yaml:"cap_add,omitempty"`
 | 
						|
	CapabilitiesDrop   []string                   `json:"cap_drop,omitempty" yaml:"cap_drop,omitempty"`
 | 
						|
	DependsOnContainer *DependsOnContainer        `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
 | 
						|
	Deploy             *ServiceDeploy             `json:"deploy,omitempty" yaml:"deploy,omitempty"`
 | 
						|
	Environments       []string                   `json:"environment,omitempty" yaml:"environment,omitempty"`
 | 
						|
	ExtraHosts         []string                   `json:"extra_hosts,omitempty" yaml:"extra_hosts,omitempty"`
 | 
						|
	Image              string                     `json:"image,omitempty" yaml:"image,omitempty"`
 | 
						|
	Labels             []string                   `json:"labels,omitempty" yaml:"labels,omitempty"`
 | 
						|
	Networks           map[string]*ServiceNetwork `json:"networks,omitempty" yaml:"networks,omitempty"`
 | 
						|
	Ports              []Port                     `json:"ports,omitempty" yaml:"ports,omitempty"`
 | 
						|
	Secrets            []string                   `json:"secrets,omitempty" yaml:"secrets,omitempty"`
 | 
						|
	ULimits            *ServiceULimits            `json:"ulimits,omitempty" yaml:"ulimits,omitempty"`
 | 
						|
	Volumes            []string                   `json:"volumes,omitempty" yaml:"volumes,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// ExistsEnvironment returns true if the passed name of environment variable is
 | 
						|
// already present.
 | 
						|
func (s *Service) ExistsEnvironment(name string) bool {
 | 
						|
	for _, environment := range s.Environments {
 | 
						|
		key, _ := splitStringInKeyValue(environment, environmentDelimiter)
 | 
						|
		if key == name {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// ExistsLabel returns true if the passed label name is already present.
 | 
						|
func (s *Service) ExistsLabel(name string) bool {
 | 
						|
	for _, label := range s.Labels {
 | 
						|
		key, _ := splitStringInKeyValue(label, labelDelimiter)
 | 
						|
		if key == name {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// ExistsPort returns true if the port definition is already present. The port defines a mapping between the host system
 | 
						|
// port and the container port. It is also possible to specify the individual ip address of the host system or the
 | 
						|
// container. Additionally, the protocol can be specified as suffix.
 | 
						|
//
 | 
						|
//	// Example
 | 
						|
//	s := new(Service)
 | 
						|
//	b := s.ExistsPort("80:80")
 | 
						|
//	b = s.ExistsPort("0.0.0.0:80:80/tcp")
 | 
						|
//	b = s.ExistsPort("0.0.0.0:80:80/tcp")
 | 
						|
//	b = s.ExistsPort("192.168.178.10:80:172.25.18.20:80/tcp")
 | 
						|
func (s *Service) ExistsPort(port string) bool {
 | 
						|
	for _, p := range s.Ports {
 | 
						|
		if string(p) == port {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// ExistsVolume returns true if the volume definition is already present.
 | 
						|
func (s *Service) ExistsVolume(src string, dest string, perm string) bool {
 | 
						|
	for _, volume := range s.Volumes {
 | 
						|
		s, d, p := splitStringInVolume(volume)
 | 
						|
		if s == src && d == dest && p == perm {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// ExistsDestinationVolume returns true if the volume definition is already present.
 | 
						|
func (s *Service) ExistsDestinationVolume(dest string) bool {
 | 
						|
	for _, volume := range s.Volumes {
 | 
						|
		_, d, _ := splitStringInVolume(volume)
 | 
						|
		if d == dest {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// ExistsSourceVolume returns true if the volume definition is already present.
 | 
						|
func (s *Service) ExistsSourceVolume(src string) bool {
 | 
						|
	for _, volume := range s.Volumes {
 | 
						|
		s, _, _ := splitStringInVolume(volume)
 | 
						|
		if s == src {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (s *Service) Equal(equalable Equalable) bool {
 | 
						|
	service, ok := equalable.(*Service)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case s == nil && service == nil:
 | 
						|
		return true
 | 
						|
	case s != nil && service == nil:
 | 
						|
		fallthrough
 | 
						|
	case s == nil && service != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return equalSlice(s.Command, service.Command) &&
 | 
						|
			equalSlice(s.CapabilitiesAdd, service.CapabilitiesAdd) &&
 | 
						|
			equalSlice(s.CapabilitiesDrop, service.CapabilitiesDrop) &&
 | 
						|
			s.DependsOnContainer.Equal(service.DependsOnContainer) &&
 | 
						|
			s.Deploy.Equal(service.Deploy) &&
 | 
						|
			equalSlice(s.Environments, service.Environments) &&
 | 
						|
			equalSlice(s.ExtraHosts, service.ExtraHosts) &&
 | 
						|
			s.Image == service.Image &&
 | 
						|
			equalSlice(s.Labels, service.Labels) &&
 | 
						|
			EqualStringMap(s.Networks, service.Networks) &&
 | 
						|
			equalSlice(s.Ports, service.Ports) &&
 | 
						|
			equalSlice(s.Secrets, service.Secrets) &&
 | 
						|
			s.ULimits.Equal(service.ULimits) &&
 | 
						|
			equalSlice(s.Volumes, service.Volumes)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) MergeExistingWin(service *Service) {
 | 
						|
	switch {
 | 
						|
	case s == nil && service == nil:
 | 
						|
		fallthrough
 | 
						|
	case s != nil && service == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer s *Service
 | 
						|
	// to a new initialized service without returning the Service
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case s == nil && service != nil:
 | 
						|
	// 	s = NewService()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		s.mergeExistingWinCommand(service.Command)
 | 
						|
		s.mergeExistingWinCapabilitiesAdd(service.CapabilitiesAdd)
 | 
						|
		s.mergeExistingWinCapabilitiesDrop(service.CapabilitiesDrop)
 | 
						|
		s.mergeExistingWinDependsOnContainer(service.DependsOnContainer)
 | 
						|
		s.mergeExistingWinDeploy(service.Deploy)
 | 
						|
		s.mergeExistingWinEnvironments(service.Environments)
 | 
						|
		s.mergeExistingWinExtraHosts(service.ExtraHosts)
 | 
						|
		s.mergeExistingWinImage(service.Image)
 | 
						|
		s.mergeExistingWinLabels(service.Labels)
 | 
						|
		s.mergeExistingWinNetworks(service.Networks)
 | 
						|
		s.mergeExistingWinPorts(service.Ports)
 | 
						|
		s.mergeExistingWinSecrets(service.Secrets)
 | 
						|
		s.mergeExistingWinULimits(service.ULimits)
 | 
						|
		s.mergeExistingWinVolumes(service.Volumes)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed secret
 | 
						|
// with the existing one.
 | 
						|
func (s *Service) MergeLastWin(service *Service) {
 | 
						|
	switch {
 | 
						|
	case s == nil && service == nil:
 | 
						|
		fallthrough
 | 
						|
	case s != nil && service == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer s *Service
 | 
						|
	// to a new initialized service without returning the Service
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case s == nil && service != nil:
 | 
						|
	// 	s = NewService()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		s.mergeLastWinCommand(service.Command)
 | 
						|
		s.mergeLastWinCapabilitiesAdd(service.CapabilitiesAdd)
 | 
						|
		s.mergeLastWinCapabilitiesDrop(service.CapabilitiesDrop)
 | 
						|
		s.mergeLastWinDependsOnContainer(service.DependsOnContainer)
 | 
						|
		s.mergeLastWinDeploy(service.Deploy)
 | 
						|
		s.mergeLastWinEnvironments(service.Environments)
 | 
						|
		s.mergeLastWinExtraHosts(service.ExtraHosts)
 | 
						|
		s.mergeLastWinImage(service.Image)
 | 
						|
		s.mergeLastWinLabels(service.Labels)
 | 
						|
		s.mergeLastWinNetworks(service.Networks)
 | 
						|
		s.mergeLastWinPorts(service.Ports)
 | 
						|
		s.mergeLastWinSecrets(service.Secrets)
 | 
						|
		s.mergeLastWinULimits(service.ULimits)
 | 
						|
		s.mergeLastWinVolumes(service.Volumes)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinCommand(command []string) {
 | 
						|
	if len(s.Command) > 0 {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	s.Command = command
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinCapabilitiesAdd(capabilitiesAdd []string) {
 | 
						|
	for _, capabilityAdd := range capabilitiesAdd {
 | 
						|
		if !existsInSlice(s.CapabilitiesAdd, capabilityAdd) && len(capabilityAdd) > 0 {
 | 
						|
			s.CapabilitiesAdd = append(s.CapabilitiesAdd, capabilityAdd)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinCapabilitiesDrop(capabilitiesDrop []string) {
 | 
						|
	for _, capabilityDrop := range capabilitiesDrop {
 | 
						|
		if !existsInSlice(s.CapabilitiesAdd, capabilityDrop) && len(capabilityDrop) > 0 {
 | 
						|
			s.CapabilitiesDrop = append(s.CapabilitiesDrop, capabilityDrop)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinDependsOnContainer(dependsOnContainer *DependsOnContainer) {
 | 
						|
	switch {
 | 
						|
	case s.DependsOnContainer != nil && dependsOnContainer == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.DependsOnContainer == nil && dependsOnContainer == nil:
 | 
						|
		return
 | 
						|
	case s.DependsOnContainer == nil && dependsOnContainer != nil:
 | 
						|
		s.DependsOnContainer = dependsOnContainer
 | 
						|
	default:
 | 
						|
		for name, depOn := range dependsOnContainer.DependsOn {
 | 
						|
			if !ExistsInMap(s.DependsOnContainer.DependsOn, name) && depOn != nil {
 | 
						|
				if s.DependsOnContainer.DependsOn == nil {
 | 
						|
					s.DependsOnContainer.DependsOn = make(map[string]*ServiceDependsOn)
 | 
						|
				}
 | 
						|
				s.DependsOnContainer.DependsOn[name] = depOn
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinDeploy(deploy *ServiceDeploy) {
 | 
						|
	switch {
 | 
						|
	case s.Deploy == nil && deploy != nil:
 | 
						|
		s.Deploy = deploy
 | 
						|
	case s.Deploy != nil && deploy == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Deploy == nil && deploy == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		s.Deploy.MergeExistingWin(deploy)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinEnvironments(environments []string) {
 | 
						|
	switch {
 | 
						|
	case s.Environments == nil && environments != nil:
 | 
						|
		s.Environments = environments
 | 
						|
	case s.Environments != nil && environments == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Environments == nil && environments == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for _, environment := range environments {
 | 
						|
			if len(environment) <= 0 {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			key, value := splitStringInKeyValue(environment, environmentDelimiter)
 | 
						|
			if !s.ExistsEnvironment(key) {
 | 
						|
				s.SetEnvironment(key, value)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinImage(image string) {
 | 
						|
	switch {
 | 
						|
	case len(s.Image) == 0 && len(image) != 0:
 | 
						|
		s.Image = image
 | 
						|
	case len(s.Image) != 0 && len(image) == 0:
 | 
						|
		fallthrough
 | 
						|
	case len(s.Image) == 0 && len(image) == 0:
 | 
						|
		fallthrough
 | 
						|
	default:
 | 
						|
		return
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinExtraHosts(extraHosts []string) {
 | 
						|
	for _, extraHost := range extraHosts {
 | 
						|
		if !existsInSlice(s.ExtraHosts, extraHost) && len(extraHost) > 0 {
 | 
						|
			s.ExtraHosts = append(s.ExtraHosts, extraHost)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinLabels(labels []string) {
 | 
						|
	switch {
 | 
						|
	case s.Labels == nil && labels != nil:
 | 
						|
		s.Labels = labels
 | 
						|
	case s.Labels != nil && labels == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Labels == nil && labels == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for _, label := range labels {
 | 
						|
			if len(label) <= 0 {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			key, value := splitStringInKeyValue(label, labelDelimiter)
 | 
						|
			if !s.ExistsLabel(key) {
 | 
						|
				s.SetLabel(key, value)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinNetworks(networks map[string]*ServiceNetwork) {
 | 
						|
	switch {
 | 
						|
	case s.Networks == nil && networks != nil:
 | 
						|
		s.Networks = networks
 | 
						|
	case s.Networks != nil && networks == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Networks == nil && networks == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for name, network := range networks {
 | 
						|
			if _, exists := s.Networks[name]; exists {
 | 
						|
				s.Networks[name].MergeExistingWin(network)
 | 
						|
			} else {
 | 
						|
				s.Networks[name] = network
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinPorts(ports []Port) {
 | 
						|
	switch {
 | 
						|
	case s.Ports == nil && ports != nil:
 | 
						|
		s.Ports = ports
 | 
						|
	case s.Ports != nil && ports == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Ports == nil && ports == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
	LOOP:
 | 
						|
		for i := range ports {
 | 
						|
			if len(ports[i]) <= 0 {
 | 
						|
				continue LOOP
 | 
						|
			}
 | 
						|
 | 
						|
			newPort := Port(ports[i])
 | 
						|
 | 
						|
			for j := range s.Ports {
 | 
						|
				existingPort := Port(s.Ports[j])
 | 
						|
				switch {
 | 
						|
				case newPort.existsSrcIP() && existingPort.existsSrcIP() &&
 | 
						|
					newPort.getSrc() == existingPort.getSrc():
 | 
						|
					continue LOOP
 | 
						|
				case !newPort.existsSrcIP() && existingPort.existsSrcIP() &&
 | 
						|
					newPort.getSrcPort() == existingPort.getSrcPort():
 | 
						|
					continue LOOP
 | 
						|
				case newPort.existsSrcIP() && !existingPort.existsSrcIP() &&
 | 
						|
					newPort.getSrcPort() == existingPort.getSrcPort():
 | 
						|
					continue LOOP
 | 
						|
				case !newPort.existsSrcIP() && !existingPort.existsSrcIP() &&
 | 
						|
					newPort.getSrcPort() == existingPort.getSrcPort():
 | 
						|
					continue LOOP
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			s.Ports = append(s.Ports, ports[i])
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinSecrets(secrets []string) {
 | 
						|
	for _, secret := range secrets {
 | 
						|
		if !existsInSlice(s.Secrets, secret) && len(secret) > 0 {
 | 
						|
			s.Secrets = append(s.Secrets, secret)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinULimits(uLimits *ServiceULimits) {
 | 
						|
	switch {
 | 
						|
	case s.ULimits == nil && uLimits != nil:
 | 
						|
		s.ULimits = uLimits
 | 
						|
	case s.ULimits != nil && uLimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.ULimits == nil && uLimits == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		s.ULimits.MergeExistingWin(uLimits)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeExistingWinVolumes(volumes []string) {
 | 
						|
	switch {
 | 
						|
	case s.Volumes == nil && volumes != nil:
 | 
						|
		s.Volumes = volumes
 | 
						|
	case s.Volumes != nil && volumes == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Volumes == nil && volumes == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for _, volume := range volumes {
 | 
						|
			src, dest, perm := splitStringInVolume(volume)
 | 
						|
			if !s.ExistsDestinationVolume(dest) {
 | 
						|
				s.SetVolume(src, dest, perm)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinCommand(command []string) {
 | 
						|
	if len(command) > 0 {
 | 
						|
		s.Command = command
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinCapabilitiesAdd(capabilitiesAdd []string) {
 | 
						|
	for _, capabilityAdd := range capabilitiesAdd {
 | 
						|
		if len(capabilityAdd) <= 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if !existsInSlice(s.CapabilitiesAdd, capabilityAdd) {
 | 
						|
			s.CapabilitiesAdd = append(s.CapabilitiesAdd, capabilityAdd)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinCapabilitiesDrop(capabilitiesDrop []string) {
 | 
						|
	for _, capabilityDrop := range capabilitiesDrop {
 | 
						|
		if len(capabilityDrop) <= 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if !existsInSlice(s.CapabilitiesDrop, capabilityDrop) {
 | 
						|
			s.CapabilitiesDrop = append(s.CapabilitiesDrop, capabilityDrop)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinDependsOnContainer(dependsOnContainer *DependsOnContainer) {
 | 
						|
	switch {
 | 
						|
	case s.DependsOnContainer != nil && dependsOnContainer == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.DependsOnContainer == nil && dependsOnContainer == nil:
 | 
						|
		return
 | 
						|
	case s.DependsOnContainer == nil && dependsOnContainer != nil:
 | 
						|
		s.DependsOnContainer = dependsOnContainer
 | 
						|
	default:
 | 
						|
		for name, depOn := range dependsOnContainer.DependsOn {
 | 
						|
			if s.DependsOnContainer.DependsOn == nil {
 | 
						|
				s.DependsOnContainer.DependsOn = make(map[string]*ServiceDependsOn)
 | 
						|
			}
 | 
						|
			s.DependsOnContainer.DependsOn[name] = depOn
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinDeploy(deploy *ServiceDeploy) {
 | 
						|
	switch {
 | 
						|
	case s.Deploy == nil && deploy != nil:
 | 
						|
		s.Deploy = deploy
 | 
						|
	case s.Deploy != nil && deploy == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Deploy == nil && deploy == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		s.Deploy.MergeLastWin(deploy)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinEnvironments(environments []string) {
 | 
						|
	switch {
 | 
						|
	case s.Environments == nil && environments != nil:
 | 
						|
		s.Environments = environments
 | 
						|
	case s.Environments != nil && environments == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Environments == nil && environments == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for _, environment := range environments {
 | 
						|
			if len(environment) <= 0 {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			key, value := splitStringInKeyValue(environment, environmentDelimiter)
 | 
						|
			s.SetEnvironment(key, value)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinImage(image string) {
 | 
						|
	switch {
 | 
						|
	case len(s.Image) == 0 && len(image) != 0:
 | 
						|
		s.Image = image
 | 
						|
	case len(s.Image) != 0 && len(image) == 0:
 | 
						|
		fallthrough
 | 
						|
	case len(s.Image) == 0 && len(image) == 0:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		if s.Image != image {
 | 
						|
			s.Image = image
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinExtraHosts(extraHosts []string) {
 | 
						|
	for _, extraHost := range extraHosts {
 | 
						|
		if len(extraHost) <= 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if !existsInSlice(s.ExtraHosts, extraHost) {
 | 
						|
			s.ExtraHosts = append(s.ExtraHosts, extraHost)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinLabels(labels []string) {
 | 
						|
	switch {
 | 
						|
	case s.Labels == nil && labels != nil:
 | 
						|
		s.Labels = labels
 | 
						|
	case s.Labels != nil && labels == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Labels == nil && labels == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for _, label := range labels {
 | 
						|
			if len(label) <= 0 {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			key, value := splitStringInKeyValue(label, labelDelimiter)
 | 
						|
			s.SetLabel(key, value)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinNetworks(networks map[string]*ServiceNetwork) {
 | 
						|
	switch {
 | 
						|
	case s.Networks == nil && networks != nil:
 | 
						|
		s.Networks = networks
 | 
						|
	case s.Networks != nil && networks == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Networks == nil && networks == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for name, network := range networks {
 | 
						|
			if _, exists := s.Networks[name]; exists {
 | 
						|
				s.Networks[name].MergeLastWin(network)
 | 
						|
			} else {
 | 
						|
				s.Networks[name] = network
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinPorts(ports []Port) {
 | 
						|
	switch {
 | 
						|
	case s.Ports == nil && ports != nil:
 | 
						|
		s.Ports = ports
 | 
						|
	case s.Ports != nil && ports == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Ports == nil && ports == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for i := range ports {
 | 
						|
			if len(ports[i]) <= 0 {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			s.SetPort(string(ports[i]))
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinSecrets(secrets []string) {
 | 
						|
	for _, secret := range secrets {
 | 
						|
		if len(secret) <= 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if !existsInSlice(s.Secrets, secret) {
 | 
						|
			s.Secrets = append(s.Secrets, secret)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinULimits(uLimits *ServiceULimits) {
 | 
						|
	switch {
 | 
						|
	case s.ULimits == nil && uLimits != nil:
 | 
						|
		s.ULimits = uLimits
 | 
						|
	case s.ULimits != nil && uLimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.ULimits == nil && uLimits == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		s.ULimits.MergeLastWin(uLimits)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (s *Service) mergeLastWinVolumes(volumes []string) {
 | 
						|
	switch {
 | 
						|
	case s.Volumes == nil && volumes != nil:
 | 
						|
		s.Volumes = volumes
 | 
						|
	case s.Volumes != nil && volumes == nil:
 | 
						|
		fallthrough
 | 
						|
	case s.Volumes == nil && volumes == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		for _, volume := range volumes {
 | 
						|
			if len(volume) <= 0 {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			src, dest, perm := splitStringInVolume(volume)
 | 
						|
			s.SetVolume(src, dest, perm)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// RemoveEnvironment remove all found environment variable from the internal
 | 
						|
// slice matching by the passed name.
 | 
						|
func (s *Service) RemoveEnvironment(name string) {
 | 
						|
	environments := make([]string, 0)
 | 
						|
	for _, environment := range s.Environments {
 | 
						|
		key, value := splitStringInKeyValue(environment, environmentDelimiter)
 | 
						|
		if key != name {
 | 
						|
			environments = append(environments, fmt.Sprintf("%s%s%s", key, environmentDelimiter, value))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	s.Environments = environments
 | 
						|
}
 | 
						|
 | 
						|
// RemoveLabel remove all found labels from the internal slice matching by the passed name.
 | 
						|
func (s *Service) RemoveLabel(name string) {
 | 
						|
	labels := make([]string, 0)
 | 
						|
	for _, label := range s.Labels {
 | 
						|
		key, value := splitStringInKeyValue(label, labelDelimiter)
 | 
						|
		if key != name {
 | 
						|
			labels = append(labels, fmt.Sprintf("%s%s%s", key, labelDelimiter, value))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	s.Labels = labels
 | 
						|
}
 | 
						|
 | 
						|
// RemovePortByDst remove all found ports from the internal slice matching by the passed destination. The destination
 | 
						|
// can contains only the destination port, but also the destination ip address.
 | 
						|
//
 | 
						|
//	// Example
 | 
						|
//	s := new(Service)
 | 
						|
//	s.RemovePortByDst("8080")
 | 
						|
//	s.RemovePortByDst("172.25.18.20:8080")
 | 
						|
func (s *Service) RemovePortByDst(dest string) {
 | 
						|
	ports := make([]Port, 0)
 | 
						|
	for _, port := range s.Ports {
 | 
						|
		switch {
 | 
						|
		case port.getDst() == dest:
 | 
						|
			continue
 | 
						|
		default:
 | 
						|
			ports = append(ports, port)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	s.Ports = ports
 | 
						|
}
 | 
						|
 | 
						|
// RemovePortBySrc remove all found ports from the internal slice matching by the passed source. The source can contains
 | 
						|
// only the source port, but also the source ip address.
 | 
						|
//
 | 
						|
//	// Example
 | 
						|
//	s := new(Service)
 | 
						|
//	s.RemovePortBySrc("8080")
 | 
						|
//	s.RemovePortBySrc("192.168.178.10:8080")
 | 
						|
func (s *Service) RemovePortBySrc(src string) {
 | 
						|
	ports := make([]Port, 0)
 | 
						|
	for _, port := range s.Ports {
 | 
						|
		switch {
 | 
						|
		case port.getSrc() == src:
 | 
						|
			continue
 | 
						|
		default:
 | 
						|
			ports = append(ports, port)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	s.Ports = ports
 | 
						|
}
 | 
						|
 | 
						|
// RemoveVolume remove all found volumes from the internal slice matching by the dest path.
 | 
						|
func (s *Service) RemoveVolume(dest string) {
 | 
						|
	volumes := make([]string, 0)
 | 
						|
	for _, volume := range s.Volumes {
 | 
						|
		srcPath, destPath, perm := splitStringInVolume(volume)
 | 
						|
 | 
						|
		switch {
 | 
						|
		case destPath == dest && len(perm) <= 0:
 | 
						|
			s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s", srcPath, volumeDelimiter, destPath))
 | 
						|
		case destPath == dest && len(perm) > 0:
 | 
						|
			s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s%s%s", srcPath, volumeDelimiter, destPath, volumeDelimiter, perm))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	s.Volumes = volumes
 | 
						|
}
 | 
						|
 | 
						|
// SetEnvironment add or overwrite an existing environment variable.
 | 
						|
func (s *Service) SetEnvironment(name string, value string) {
 | 
						|
	s.RemoveEnvironment(name)
 | 
						|
	s.Environments = append(s.Environments, fmt.Sprintf("%s%s%s", name, environmentDelimiter, value))
 | 
						|
}
 | 
						|
 | 
						|
// SetLabel add or overwrite an existing label.
 | 
						|
func (s *Service) SetLabel(name string, value string) {
 | 
						|
	s.RemoveLabel(name)
 | 
						|
	s.Labels = append(s.Labels, fmt.Sprintf("%s%s%s", name, labelDelimiter, value))
 | 
						|
}
 | 
						|
 | 
						|
// SetPort add or overwrite an existing source port.
 | 
						|
//
 | 
						|
//	// Example
 | 
						|
//	s := new(Service)
 | 
						|
//	s.SetPort("0.0.0.0:443:172.25.18.20:8443/tcp")	// Add new port
 | 
						|
//	s.SetPort("0.0.0.0:443:10.254.611.66:443/tcp")	// Overwrite port determined by source port
 | 
						|
func (s *Service) SetPort(port string) {
 | 
						|
	newPort := Port(port)
 | 
						|
	s.RemovePortBySrc(newPort.getSrc())
 | 
						|
	s.Ports = append(s.Ports, newPort)
 | 
						|
}
 | 
						|
 | 
						|
// SetVolume add or overwrite an existing volume.
 | 
						|
func (s *Service) SetVolume(src string, dest string, perm string) {
 | 
						|
	s.RemoveVolume(dest)
 | 
						|
	if len(perm) <= 0 {
 | 
						|
		s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s", src, volumeDelimiter, dest))
 | 
						|
	} else {
 | 
						|
		s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s%s%s", src, volumeDelimiter, dest, volumeDelimiter, perm))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	ServiceDependsOnConditionServiceCompletedSuccessfully string = "service_completed_successfully"
 | 
						|
	ServiceDependsOnConditionServiceHealthy               string = "service_healthy"
 | 
						|
	ServiceDependsOnConditionServiceStarted               string = "service_started"
 | 
						|
)
 | 
						|
 | 
						|
// DependsOnContainer is a wrapper to handle different YAML type formats of DependsOn.
 | 
						|
type DependsOnContainer struct {
 | 
						|
	Slice     []string
 | 
						|
	DependsOn map[string]*ServiceDependsOn
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (sdoc *DependsOnContainer) Equal(equalable Equalable) bool {
 | 
						|
	serviceDependsOnContainer, ok := equalable.(*DependsOnContainer)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case sdoc == nil && serviceDependsOnContainer == nil:
 | 
						|
		return true
 | 
						|
	case sdoc != nil && serviceDependsOnContainer == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdoc == nil && serviceDependsOnContainer != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return equalSlice(sdoc.Slice, serviceDependsOnContainer.Slice) &&
 | 
						|
			EqualStringMap(sdoc.DependsOn, serviceDependsOnContainer.DependsOn)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MarshalYAML implements the MarshalYAML interface to customize the behavior when being marshaled into a YAML document.
 | 
						|
func (sdoc *DependsOnContainer) MarshalYAML() (interface{}, error) {
 | 
						|
	var foundAnotherCondition = false
 | 
						|
	var dependencyNames = make([]string, 0)
 | 
						|
 | 
						|
	for dependencyName, dependencyDefinition := range sdoc.DependsOn {
 | 
						|
		if dependencyDefinition.Condition == ServiceDependsOnConditionServiceStarted {
 | 
						|
			dependencyNames = append(dependencyNames, dependencyName)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		foundAnotherCondition = true
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case foundAnotherCondition:
 | 
						|
		return sdoc.DependsOn, nil
 | 
						|
	case !foundAnotherCondition && len(dependencyNames) > 0:
 | 
						|
		return dependencyNames, nil
 | 
						|
	default:
 | 
						|
		return nil, nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// UnmarshalYAML implements the UnmarshalYAML interface to customize the behavior when being unmarshaled into a YAML
 | 
						|
// document.
 | 
						|
func (sdoc *DependsOnContainer) UnmarshalYAML(value *yaml.Node) error {
 | 
						|
	if sdoc.DependsOn == nil {
 | 
						|
		sdoc.DependsOn = make(map[string]*ServiceDependsOn)
 | 
						|
	}
 | 
						|
 | 
						|
	if sdoc.Slice == nil {
 | 
						|
		sdoc.Slice = make([]string, 0)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := value.Decode(&sdoc.Slice); err == nil {
 | 
						|
		for _, s := range sdoc.Slice {
 | 
						|
			sdoc.DependsOn[s] = &ServiceDependsOn{
 | 
						|
				Condition: ServiceDependsOnConditionServiceStarted,
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	if err := value.Decode(sdoc.DependsOn); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// NewService returns an empty initialized Service.
 | 
						|
func NewService() *Service {
 | 
						|
	return &Service{
 | 
						|
		CapabilitiesAdd:  make([]string, 0),
 | 
						|
		CapabilitiesDrop: make([]string, 0),
 | 
						|
		Deploy:           new(ServiceDeploy),
 | 
						|
		Environments:     make([]string, 0),
 | 
						|
		ExtraHosts:       make([]string, 0),
 | 
						|
		Labels:           make([]string, 0),
 | 
						|
		Networks:         make(map[string]*ServiceNetwork),
 | 
						|
		Ports:            make([]Port, 0),
 | 
						|
		Secrets:          make([]string, 0),
 | 
						|
		ULimits:          new(ServiceULimits),
 | 
						|
		Volumes:          make([]string, 0),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type ServiceDependsOn struct {
 | 
						|
	Condition string `yaml:"condition,omitempty"`
 | 
						|
	Restart   string `yaml:"restart,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (sdo *ServiceDependsOn) Equal(equalable Equalable) bool {
 | 
						|
	serviceDependsOn, ok := equalable.(*ServiceDependsOn)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case sdo == nil && serviceDependsOn == nil:
 | 
						|
		return true
 | 
						|
	case sdo != nil && serviceDependsOn == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdo == nil && serviceDependsOn != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return sdo.Condition == serviceDependsOn.Condition &&
 | 
						|
			sdo.Restart == serviceDependsOn.Restart
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type ServiceDeploy struct {
 | 
						|
	Resources *ServiceDeployResources `json:"resources" yaml:"resources"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (sd *ServiceDeploy) Equal(equalable Equalable) bool {
 | 
						|
	serviceDeploy, ok := equalable.(*ServiceDeploy)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case sd == nil && serviceDeploy == nil:
 | 
						|
		return true
 | 
						|
	case sd != nil && serviceDeploy == nil:
 | 
						|
		fallthrough
 | 
						|
	case sd == nil && serviceDeploy != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return sd.Resources.Equal(serviceDeploy.Resources)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin merges adds or overwrite the attributes of the passed
 | 
						|
// serviceDeploy with the existing one.
 | 
						|
func (sd *ServiceDeploy) MergeExistingWin(serviceDeploy *ServiceDeploy) {
 | 
						|
	switch {
 | 
						|
	case sd == nil && serviceDeploy == nil:
 | 
						|
		fallthrough
 | 
						|
	case sd != nil && serviceDeploy == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sd *ServiceDeploy
 | 
						|
	// to a new initialized serviceDeploy without returning the ServiceDeploy
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case sd == nil && serviceDeploy != nil:
 | 
						|
	// 	sd = NewServiceDeploy()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		sd.mergeExistingWinDeployResources(serviceDeploy.Resources)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed
 | 
						|
// serviceDeploy with the existing one.
 | 
						|
func (sd *ServiceDeploy) MergeLastWin(serviceDeploy *ServiceDeploy) {
 | 
						|
	switch {
 | 
						|
	case sd == nil && serviceDeploy == nil:
 | 
						|
		fallthrough
 | 
						|
	case sd != nil && serviceDeploy == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sd *ServiceDeploy
 | 
						|
	// to a new initialized serviceDeploy without returning the ServiceDeploy
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case sd == nil && serviceDeploy != nil:
 | 
						|
	// 	sd = NewServiceDeploy()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		sd.mergeLastWinDeployResources(serviceDeploy.Resources)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sd *ServiceDeploy) mergeExistingWinDeployResources(resources *ServiceDeployResources) {
 | 
						|
	switch {
 | 
						|
	case sd.Resources == nil && resources != nil:
 | 
						|
		sd.Resources = resources
 | 
						|
	case sd.Resources != nil && resources == nil:
 | 
						|
		fallthrough
 | 
						|
	case sd.Resources == nil && resources == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		sd.Resources.MergeExistingWin(resources)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sd *ServiceDeploy) mergeLastWinDeployResources(resources *ServiceDeployResources) {
 | 
						|
	switch {
 | 
						|
	case sd.Resources == nil && resources != nil:
 | 
						|
		sd.Resources = resources
 | 
						|
	case sd.Resources != nil && resources == nil:
 | 
						|
		fallthrough
 | 
						|
	case sd.Resources == nil && resources == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		sd.Resources.MergeLastWin(resources)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewServiceDeploy() *ServiceDeploy {
 | 
						|
	return &ServiceDeploy{
 | 
						|
		Resources: new(ServiceDeployResources),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type ServiceDeployResources struct {
 | 
						|
	Limits       *ServiceDeployResourcesLimits `json:"limits,omitempty" yaml:"limits,omitempty"`
 | 
						|
	Reservations *ServiceDeployResourcesLimits `json:"reservations,omitempty" yaml:"reservations,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (sdr *ServiceDeployResources) Equal(equalable Equalable) bool {
 | 
						|
	serviceDeployResources, ok := equalable.(*ServiceDeployResources)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case sdr == nil && serviceDeployResources == nil:
 | 
						|
		return true
 | 
						|
	case sdr != nil && serviceDeployResources == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdr == nil && serviceDeployResources != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return sdr.Limits.Equal(serviceDeployResources.Limits) &&
 | 
						|
			sdr.Reservations.Equal(serviceDeployResources.Reservations)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin adds only attributes of the passed serviceDeployResources if
 | 
						|
// they are not already exists.
 | 
						|
func (sdr *ServiceDeployResources) MergeExistingWin(serviceDeployResources *ServiceDeployResources) {
 | 
						|
	switch {
 | 
						|
	case sdr == nil && serviceDeployResources == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdr != nil && serviceDeployResources == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sdr *ServiceDeployResources
 | 
						|
	// to a new initialized serviceDeployResources without returning the
 | 
						|
	// serviceDeployResources it self.
 | 
						|
	case sdr == nil && serviceDeployResources != nil:
 | 
						|
		sdr = NewServiceDeployResources()
 | 
						|
		fallthrough
 | 
						|
	default:
 | 
						|
		sdr.mergeExistingWinLimits(serviceDeployResources.Limits)
 | 
						|
		sdr.mergeExistingWinReservations(serviceDeployResources.Reservations)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed
 | 
						|
// serviceDeployResources with the existing one.
 | 
						|
func (sdr *ServiceDeployResources) MergeLastWin(serviceDeployResources *ServiceDeployResources) {
 | 
						|
	switch {
 | 
						|
	case sdr == nil && serviceDeployResources == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdr != nil && serviceDeployResources == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sdr *ServiceDeployResources
 | 
						|
	// to a new initialized serviceDeployResources without returning the
 | 
						|
	// serviceDeployResources it self.
 | 
						|
	case sdr == nil && serviceDeployResources != nil:
 | 
						|
		sdr = NewServiceDeployResources()
 | 
						|
		fallthrough
 | 
						|
	default:
 | 
						|
		sdr.mergeLastWinLimits(serviceDeployResources.Limits)
 | 
						|
		sdr.mergeLastWinReservations(serviceDeployResources.Reservations)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdr *ServiceDeployResources) mergeExistingWinLimits(limits *ServiceDeployResourcesLimits) {
 | 
						|
	switch {
 | 
						|
	case sdr.Limits == nil && limits != nil:
 | 
						|
		sdr.Limits = limits
 | 
						|
	case sdr.Limits != nil && limits == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdr.Limits == nil && limits == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		sdr.Limits.MergeExistingWin(limits)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdr *ServiceDeployResources) mergeExistingWinReservations(reservations *ServiceDeployResourcesLimits) {
 | 
						|
	switch {
 | 
						|
	case sdr.Reservations == nil && reservations != nil:
 | 
						|
		sdr.Reservations = reservations
 | 
						|
	case sdr.Reservations != nil && reservations == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdr.Reservations == nil && reservations == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		sdr.Reservations.MergeExistingWin(reservations)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdr *ServiceDeployResources) mergeLastWinLimits(limits *ServiceDeployResourcesLimits) {
 | 
						|
	switch {
 | 
						|
	case sdr.Limits == nil && limits != nil:
 | 
						|
		sdr.Limits = limits
 | 
						|
	case sdr.Limits != nil && limits == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdr.Limits == nil && limits == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		sdr.Limits.MergeLastWin(limits)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdr *ServiceDeployResources) mergeLastWinReservations(reservations *ServiceDeployResourcesLimits) {
 | 
						|
	switch {
 | 
						|
	case sdr.Reservations == nil && reservations != nil:
 | 
						|
		sdr.Reservations = reservations
 | 
						|
	case sdr.Reservations != nil && reservations == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdr.Reservations == nil && reservations == nil:
 | 
						|
		return
 | 
						|
	default:
 | 
						|
		sdr.Reservations.MergeLastWin(reservations)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewServiceDeployResources() *ServiceDeployResources {
 | 
						|
	return &ServiceDeployResources{
 | 
						|
		Limits:       new(ServiceDeployResourcesLimits),
 | 
						|
		Reservations: new(ServiceDeployResourcesLimits),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type ServiceDeployResourcesLimits struct {
 | 
						|
	CPUs   string `json:"cpus,omitempty" yaml:"cpus,omitempty"`
 | 
						|
	Memory string `json:"memory,omitempty" yaml:"memory,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (sdrl *ServiceDeployResourcesLimits) Equal(equalable Equalable) bool {
 | 
						|
	serviceDeployResourcesLimits, ok := equalable.(*ServiceDeployResourcesLimits)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case sdrl == nil && serviceDeployResourcesLimits == nil:
 | 
						|
		return true
 | 
						|
	case sdrl != nil && serviceDeployResourcesLimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdrl == nil && serviceDeployResourcesLimits != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return sdrl.CPUs == serviceDeployResourcesLimits.CPUs &&
 | 
						|
			sdrl.Memory == serviceDeployResourcesLimits.Memory
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin adds only attributes of the passed serviceDeployResourcesLimits
 | 
						|
// if they are not already exists.
 | 
						|
func (sdrl *ServiceDeployResourcesLimits) MergeExistingWin(serviceDeployResourcesLimits *ServiceDeployResourcesLimits) {
 | 
						|
	switch {
 | 
						|
	case sdrl == nil && serviceDeployResourcesLimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdrl != nil && serviceDeployResourcesLimits == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sdrl *ServiceDeployResourcesLimits
 | 
						|
	// to a new initialized serviceDeployResourcesLimits without returning the
 | 
						|
	// serviceDeployResourcesLimits it self.
 | 
						|
	//
 | 
						|
	// case sdrl == nil && serviceDeployResourcesLimits != nil:
 | 
						|
	// 	sdrl = NewServiceDeployResourcesLimits()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		sdrl.mergeExistingWinCPUs(serviceDeployResourcesLimits.CPUs)
 | 
						|
		sdrl.mergeExistingWinMemory(serviceDeployResourcesLimits.Memory)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed
 | 
						|
// serviceDeployResourcesLimits with the existing one.
 | 
						|
func (sdrl *ServiceDeployResourcesLimits) MergeLastWin(serviceDeployResourcesLimits *ServiceDeployResourcesLimits) {
 | 
						|
	switch {
 | 
						|
	case sdrl == nil && serviceDeployResourcesLimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case sdrl != nil && serviceDeployResourcesLimits == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sdrl *ServiceDeployResourcesLimits
 | 
						|
	// to a new initialized serviceDeployResourcesLimits without returning the
 | 
						|
	// serviceDeployResourcesLimits it self.
 | 
						|
	//
 | 
						|
	// case sdrl == nil && serviceDeployResourcesLimits != nil:
 | 
						|
	// 	sdrl = NewServiceDeployResourcesLimits()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		sdrl.mergeLastWinCPUs(serviceDeployResourcesLimits.CPUs)
 | 
						|
		sdrl.mergeLastWinMemory(serviceDeployResourcesLimits.Memory)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdrl *ServiceDeployResourcesLimits) mergeExistingWinCPUs(cpus string) {
 | 
						|
	if len(sdrl.CPUs) <= 0 {
 | 
						|
		sdrl.CPUs = cpus
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdrl *ServiceDeployResourcesLimits) mergeExistingWinMemory(memory string) {
 | 
						|
	if len(sdrl.Memory) <= 0 {
 | 
						|
		sdrl.Memory = memory
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdrl *ServiceDeployResourcesLimits) mergeLastWinCPUs(cpus string) {
 | 
						|
	if sdrl.CPUs != cpus {
 | 
						|
		sdrl.CPUs = cpus
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sdrl *ServiceDeployResourcesLimits) mergeLastWinMemory(memory string) {
 | 
						|
	if sdrl.Memory != memory {
 | 
						|
		sdrl.Memory = memory
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewServiceDeployResourcesLimits() *ServiceDeployResourcesLimits {
 | 
						|
	return &ServiceDeployResourcesLimits{}
 | 
						|
}
 | 
						|
 | 
						|
type ServiceNetwork struct {
 | 
						|
	Aliases []string `json:"aliases,omitempty" yaml:"aliases,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (sn *ServiceNetwork) Equal(equalable Equalable) bool {
 | 
						|
	serviceNetwork, ok := equalable.(*ServiceNetwork)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case sn == nil && serviceNetwork == nil:
 | 
						|
		return true
 | 
						|
	case sn != nil && serviceNetwork == nil:
 | 
						|
		fallthrough
 | 
						|
	case sn == nil && serviceNetwork != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return equalSlice(sn.Aliases, serviceNetwork.Aliases)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin adds only attributes of the passed
 | 
						|
// serviceNetwork if they are undefined.
 | 
						|
func (sn *ServiceNetwork) MergeExistingWin(serviceNetwork *ServiceNetwork) {
 | 
						|
	switch {
 | 
						|
	case sn == nil && serviceNetwork == nil:
 | 
						|
		fallthrough
 | 
						|
	case sn != nil && serviceNetwork == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sn *ServiceNetwork to a new
 | 
						|
	// initialized ServiceNetwork without returning the serviceNetwork it self.
 | 
						|
	//
 | 
						|
	// case l == nil && serviceULimits != nil:
 | 
						|
	// 	l = NewServiceULimits()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	case sn == nil && serviceNetwork != nil:
 | 
						|
		sn = NewServiceNetwork()
 | 
						|
		fallthrough
 | 
						|
	default:
 | 
						|
		sn.mergeExistingWinAliases(serviceNetwork.Aliases)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed
 | 
						|
// serviceNetwork with the existing one.
 | 
						|
func (sn *ServiceNetwork) MergeLastWin(serviceNetwork *ServiceNetwork) {
 | 
						|
	switch {
 | 
						|
	case sn == nil && serviceNetwork == nil:
 | 
						|
		fallthrough
 | 
						|
	case sn != nil && serviceNetwork == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer sn *ServiceNetwork to a new
 | 
						|
	// initialized ServiceNetwork without returning the serviceNetwork it self.
 | 
						|
	//
 | 
						|
	// case l == nil && serviceULimits != nil:
 | 
						|
	// 	l = NewServiceULimits()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	case sn == nil && serviceNetwork != nil:
 | 
						|
		sn = NewServiceNetwork()
 | 
						|
		fallthrough
 | 
						|
	default:
 | 
						|
		sn.mergeLastWinAliases(serviceNetwork.Aliases)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sn *ServiceNetwork) mergeExistingWinAliases(aliases []string) {
 | 
						|
	for _, alias := range aliases {
 | 
						|
		if !existsInSlice(sn.Aliases, alias) && len(alias) > 0 {
 | 
						|
			sn.Aliases = append(sn.Aliases, alias)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (sn *ServiceNetwork) mergeLastWinAliases(aliases []string) {
 | 
						|
	for _, alias := range aliases {
 | 
						|
		if !existsInSlice(sn.Aliases, alias) && len(alias) > 0 {
 | 
						|
			sn.Aliases = append(sn.Aliases, alias)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewServiceNetwork() *ServiceNetwork {
 | 
						|
	return &ServiceNetwork{
 | 
						|
		Aliases: make([]string, 0),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type ServiceULimits struct {
 | 
						|
	NProc  uint                  `json:"nproc,omitempty" yaml:"nproc,omitempty"`
 | 
						|
	NoFile *ServiceULimitsNoFile `json:"nofile,omitempty" yaml:"nofile,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (l *ServiceULimits) Equal(equalable Equalable) bool {
 | 
						|
	serviceULimits, ok := equalable.(*ServiceULimits)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case l == nil && serviceULimits == nil:
 | 
						|
		return true
 | 
						|
	case l != nil && serviceULimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case l == nil && serviceULimits != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return l.NProc == serviceULimits.NProc &&
 | 
						|
			l.NoFile.Equal(serviceULimits.NoFile)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin adds only the attributes of the passed ServiceULimits they are
 | 
						|
// undefined.
 | 
						|
func (l *ServiceULimits) MergeExistingWin(serviceULimits *ServiceULimits) {
 | 
						|
	switch {
 | 
						|
	case l == nil && serviceULimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case l != nil && serviceULimits == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer l *ServiceULimits to a new
 | 
						|
	// initialized ServiceULimits without returning the serviceULimits it self.
 | 
						|
	//
 | 
						|
	// case l == nil && serviceULimits != nil:
 | 
						|
	// 	l = NewServiceULimits()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		l.mergeExistingWinNProc(serviceULimits.NProc)
 | 
						|
		l.mergeExistingWinNoFile(serviceULimits.NoFile)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed
 | 
						|
// ServiceULimits with the existing one.
 | 
						|
func (l *ServiceULimits) MergeLastWin(serviceULimits *ServiceULimits) {
 | 
						|
	switch {
 | 
						|
	case l == nil && serviceULimits == nil:
 | 
						|
		fallthrough
 | 
						|
	case l != nil && serviceULimits == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer l *ServiceULimits to a new
 | 
						|
	// initialized ServiceULimits without returning the serviceULimits it self.
 | 
						|
	//
 | 
						|
	// case l == nil && serviceULimits != nil:
 | 
						|
	// 	l = NewServiceULimits()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		l.mergeLastWinNProc(serviceULimits.NProc)
 | 
						|
		l.mergeLastWinNoFile(serviceULimits.NoFile)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (l *ServiceULimits) mergeExistingWinNProc(nproc uint) {
 | 
						|
	if l.NProc != nproc {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	l.NProc = nproc
 | 
						|
}
 | 
						|
 | 
						|
func (l *ServiceULimits) mergeExistingWinNoFile(noFile *ServiceULimitsNoFile) {
 | 
						|
	if !l.NoFile.Equal(noFile) {
 | 
						|
		l.NoFile.MergeExistingWin(noFile)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (l *ServiceULimits) mergeLastWinNProc(nproc uint) {
 | 
						|
	if l.NProc != nproc {
 | 
						|
		l.NProc = nproc
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (l *ServiceULimits) mergeLastWinNoFile(noFile *ServiceULimitsNoFile) {
 | 
						|
	if !l.NoFile.Equal(noFile) {
 | 
						|
		l.NoFile.MergeLastWin(noFile)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewServiceULimits() *ServiceULimits {
 | 
						|
	return &ServiceULimits{
 | 
						|
		NoFile: new(ServiceULimitsNoFile),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type ServiceULimitsNoFile struct {
 | 
						|
	Hard uint `json:"hard" yaml:"hard"`
 | 
						|
	Soft uint `json:"soft" yaml:"soft"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (nf *ServiceULimitsNoFile) Equal(equalable Equalable) bool {
 | 
						|
	serviceULimitsNoFile, ok := equalable.(*ServiceULimitsNoFile)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case nf == nil && serviceULimitsNoFile == nil:
 | 
						|
		return true
 | 
						|
	case nf != nil && serviceULimitsNoFile == nil:
 | 
						|
		fallthrough
 | 
						|
	case nf == nil && serviceULimitsNoFile != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return nf.Hard == serviceULimitsNoFile.Hard &&
 | 
						|
			nf.Soft == serviceULimitsNoFile.Soft
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin adds only the attributes of the passed ServiceULimits they are
 | 
						|
// undefined.
 | 
						|
func (nf *ServiceULimitsNoFile) MergeExistingWin(serviceULimitsNoFile *ServiceULimitsNoFile) {
 | 
						|
	switch {
 | 
						|
	case nf == nil && serviceULimitsNoFile == nil:
 | 
						|
		fallthrough
 | 
						|
	case nf != nil && serviceULimitsNoFile == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer nf *ServiceULimitsNoFile
 | 
						|
	// to a new initialized ServiceULimitsNoFile without returning the serviceULimitsNoFile
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case nf == nil && serviceULimitsNoFile != nil:
 | 
						|
	// 	nf = NewServiceULimitsNoFile()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		nf.mergeExistingWinHard(serviceULimitsNoFile.Hard)
 | 
						|
		nf.mergeExistingWinSoft(serviceULimitsNoFile.Soft)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeLastWin merges adds or overwrite the attributes of the passed
 | 
						|
// ServiceULimitsNoFile with the existing one.
 | 
						|
func (nf *ServiceULimitsNoFile) MergeLastWin(serviceULimitsNoFile *ServiceULimitsNoFile) {
 | 
						|
	switch {
 | 
						|
	case nf == nil && serviceULimitsNoFile == nil:
 | 
						|
		fallthrough
 | 
						|
	case nf != nil && serviceULimitsNoFile == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer nf *ServiceULimitsNoFile
 | 
						|
	// to a new initialized ServiceULimitsNoFile without returning the serviceULimitsNoFile
 | 
						|
	// it self.
 | 
						|
	//
 | 
						|
	// case nf == nil && serviceULimitsNoFile != nil:
 | 
						|
	// 	nf = NewServiceULimitsNoFile()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		nf.mergeLastWinHard(serviceULimitsNoFile.Hard)
 | 
						|
		nf.mergeLastWinSoft(serviceULimitsNoFile.Soft)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (nf *ServiceULimitsNoFile) mergeExistingWinHard(hard uint) {
 | 
						|
	if nf.Hard != hard {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	nf.Hard = hard
 | 
						|
}
 | 
						|
 | 
						|
func (nf *ServiceULimitsNoFile) mergeExistingWinSoft(soft uint) {
 | 
						|
	if nf.Soft != soft {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	nf.Soft = soft
 | 
						|
}
 | 
						|
 | 
						|
func (nf *ServiceULimitsNoFile) mergeLastWinHard(hard uint) {
 | 
						|
	if nf.Hard != hard {
 | 
						|
		nf.Hard = hard
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (nf *ServiceULimitsNoFile) mergeLastWinSoft(soft uint) {
 | 
						|
	if nf.Soft != soft {
 | 
						|
		nf.Soft = soft
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewServiceULimitsNoFile() *ServiceULimitsNoFile {
 | 
						|
	return &ServiceULimitsNoFile{}
 | 
						|
}
 | 
						|
 | 
						|
type Volume struct {
 | 
						|
	External bool `json:"external,omitempty" yaml:"external,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if the passed equalable is equal
 | 
						|
func (v *Volume) Equal(equalable Equalable) bool {
 | 
						|
	volume, ok := equalable.(*Volume)
 | 
						|
	if !ok {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case v == nil && volume == nil:
 | 
						|
		return true
 | 
						|
	case v != nil && volume == nil:
 | 
						|
		fallthrough
 | 
						|
	case v == nil && volume != nil:
 | 
						|
		return false
 | 
						|
	default:
 | 
						|
		return v.External == volume.External
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// MergeExistingWin adds only the attributes of the passed Volume they are
 | 
						|
// undefined.
 | 
						|
func (v *Volume) MergeExistingWin(volume *Volume) {
 | 
						|
	switch {
 | 
						|
	case v == nil && volume == nil:
 | 
						|
		fallthrough
 | 
						|
	case v != nil && volume == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer v *Volume to a new
 | 
						|
	// initialized Volume without returning the volume it self.
 | 
						|
	//
 | 
						|
	// case v == nil && volume != nil:
 | 
						|
	// 	v = NewVolume()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		v.mergeExistingWinExternal(volume.External)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (v *Volume) MergeLastWin(volume *Volume) {
 | 
						|
	switch {
 | 
						|
	case v == nil && volume == nil:
 | 
						|
		fallthrough
 | 
						|
	case v != nil && volume == nil:
 | 
						|
		return
 | 
						|
 | 
						|
	// WARN: It's not possible to change the memory pointer v *Volume to a new
 | 
						|
	// initialized Volume without returning the volume it self.
 | 
						|
	//
 | 
						|
	// case v == nil && volume != nil:
 | 
						|
	// 	v = NewVolume()
 | 
						|
	// 	fallthrough
 | 
						|
 | 
						|
	default:
 | 
						|
		v.mergeLastWinExternal(volume.External)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (v *Volume) mergeExistingWinExternal(_ bool) {
 | 
						|
	if v.External {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	v.External = true
 | 
						|
}
 | 
						|
 | 
						|
func (v *Volume) mergeLastWinExternal(external bool) {
 | 
						|
	if v.External != external {
 | 
						|
		v.External = external
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewVolume() *Volume {
 | 
						|
	return &Volume{
 | 
						|
		External: false,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// existsInSlice returns true when the passed comparable K exists in slice of
 | 
						|
// comparables []K.
 | 
						|
func existsInSlice[K comparable](comparables []K, k K) bool {
 | 
						|
	for _, c := range comparables {
 | 
						|
		if c == k {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func equalSlice[K comparable](sliceA []K, sliceB []K) bool {
 | 
						|
	equalFunc := func(sliceA []K, sliceB []K) bool {
 | 
						|
	LOOP:
 | 
						|
		for i := range sliceA {
 | 
						|
			for j := range sliceB {
 | 
						|
				if sliceA[i] == sliceB[j] {
 | 
						|
					continue LOOP
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return false
 | 
						|
		}
 | 
						|
		return true
 | 
						|
	}
 | 
						|
 | 
						|
	return equalFunc(sliceA, sliceB) && equalFunc(sliceB, sliceA)
 | 
						|
}
 | 
						|
 | 
						|
func splitStringInKeyValue(s, sep string) (string, string) {
 | 
						|
	key := strings.Split(s, sep)[0]
 | 
						|
	value := strings.TrimPrefix(s, fmt.Sprintf("%s%s", key, sep))
 | 
						|
	return key, value
 | 
						|
}
 | 
						|
 | 
						|
// splitStringInPortMapping parses a string and returns the src, dest port including an optional protocol.
 | 
						|
//
 | 
						|
//	// Example
 | 
						|
//	s, d, p := splitStringInPortMapping("80:80/tcp")
 | 
						|
//	// Output: "80" "80" "tcp"
 | 
						|
//	s, d, p := splitStringInPortMapping("0.0.0.0:80:80/tcp")
 | 
						|
//	// Output: "0.0.0.0:80" "80" "tcp"
 | 
						|
//
 | 
						|
// Deprecated: Instead of using the splitStringInPortMapping function, use the method of the type Port{}.
 | 
						|
func splitStringInPortMapping(s string) (string, string, string) {
 | 
						|
	p := Port(s)
 | 
						|
 | 
						|
	var src string
 | 
						|
	switch {
 | 
						|
	case p.existsSrcIP() && p.existsSrcPort():
 | 
						|
		src = fmt.Sprintf("%s:%s", p.getSrcIP(), p.getSrcPort())
 | 
						|
	case !p.existsSrcIP():
 | 
						|
		src = p.getSrcPort()
 | 
						|
	}
 | 
						|
 | 
						|
	var dst string
 | 
						|
	switch {
 | 
						|
	case p.existsDstIP() && p.existsDstPort():
 | 
						|
		dst = fmt.Sprintf("%s:%s", p.getDstIP(), p.getDstPort())
 | 
						|
	case !p.existsDstIP():
 | 
						|
		dst = p.getDstPort()
 | 
						|
	}
 | 
						|
 | 
						|
	return src, dst, p.getProtocol()
 | 
						|
}
 | 
						|
 | 
						|
func splitStringInVolume(s string) (string, string, string) {
 | 
						|
	parts := strings.Split(s, volumeDelimiter)
 | 
						|
	src := parts[0]
 | 
						|
	dest := parts[1]
 | 
						|
	if len(parts) == 3 && len(parts[2]) > 0 {
 | 
						|
		perm := parts[2]
 | 
						|
		return src, dest, perm
 | 
						|
	}
 | 
						|
	return src, dest, ""
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	regExpPort = regexp.MustCompile(`^((?<srcIP>([\d]{1,3}\.){3}[\d]{1,3}):)?(?<srcPort>[\d]{1,5}):((?<dstIP>([\d]{1,3}\.){3}[\d]{1,3}):)?(?<dstPort>[\d]{1,5})(\/(?<protocol>[a-z]*))?$`)
 | 
						|
)
 | 
						|
 | 
						|
type Port string
 | 
						|
 | 
						|
// existsDstPort returns true, if the port string contains a trailing destination port definition.
 | 
						|
func (p Port) existsDstPort() bool {
 | 
						|
	return len(p.getDstPort()) > 0
 | 
						|
}
 | 
						|
 | 
						|
// existsDstIP returns true, if the port string contains a trailing destination ip definition.
 | 
						|
func (p Port) existsDstIP() bool {
 | 
						|
	return len(p.getDstIP()) > 0
 | 
						|
}
 | 
						|
 | 
						|
// existsProtocol returns true, if the port string contains a protocol definition.
 | 
						|
func (p Port) existsProtocol() bool {
 | 
						|
	return len(p.getProtocol()) > 0
 | 
						|
}
 | 
						|
 | 
						|
// existsSrcIP returns true, if the port string contains a leading src ip definition.
 | 
						|
func (p Port) existsSrcIP() bool {
 | 
						|
	return len(p.getSrcIP()) > 0
 | 
						|
}
 | 
						|
 | 
						|
// existsSrcPort returns true, if the port string contains a leading src port definition.
 | 
						|
func (p Port) existsSrcPort() bool {
 | 
						|
	return len(p.getSrcPort()) > 0
 | 
						|
}
 | 
						|
 | 
						|
// getDst returns the concatenation of the destination ip and port. If the destination ip is empty, only the port will
 | 
						|
// be returned.
 | 
						|
func (p Port) getDst() string {
 | 
						|
	switch {
 | 
						|
	case p.existsDstIP():
 | 
						|
		return fmt.Sprintf("%s%s%s", p.getDstIP(), portDelimiter, p.getDstPort())
 | 
						|
	default:
 | 
						|
		return p.getDstPort()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// getSrcIP returns the destination ip, if the port string contains a destination ip definition.
 | 
						|
func (p Port) getDstIP() string {
 | 
						|
	matches := regExpPort.FindStringSubmatch(string(p))
 | 
						|
	i := regExpPort.SubexpIndex("dstIP")
 | 
						|
 | 
						|
	switch {
 | 
						|
	case len(matches) <= 0:
 | 
						|
		return ""
 | 
						|
	case i < 0:
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
 | 
						|
	return matches[i]
 | 
						|
}
 | 
						|
 | 
						|
// getSrcPort returns the destination port, if the port string contains an destination port definition.
 | 
						|
func (p Port) getDstPort() string {
 | 
						|
	matches := regExpPort.FindStringSubmatch(string(p))
 | 
						|
	i := regExpPort.SubexpIndex("dstPort")
 | 
						|
 | 
						|
	switch {
 | 
						|
	case len(matches) <= 0:
 | 
						|
		return ""
 | 
						|
	case i < 0:
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
 | 
						|
	return matches[i]
 | 
						|
}
 | 
						|
 | 
						|
// getProtocol returns the protocol, if the port string contains a protocol definition.
 | 
						|
func (p Port) getProtocol() string {
 | 
						|
	matches := regExpPort.FindStringSubmatch(string(p))
 | 
						|
	i := regExpPort.SubexpIndex("protocol")
 | 
						|
 | 
						|
	switch {
 | 
						|
	case len(matches) <= 0:
 | 
						|
		return ""
 | 
						|
	case i < 0:
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
 | 
						|
	return matches[i]
 | 
						|
}
 | 
						|
 | 
						|
// getSrc returns the concatenation of the source ip and port. If the source ip is empty, only the port will be
 | 
						|
// returned.
 | 
						|
func (p Port) getSrc() string {
 | 
						|
	switch {
 | 
						|
	case p.existsSrcIP():
 | 
						|
		return fmt.Sprintf("%s%s%s", p.getSrcIP(), portDelimiter, p.getSrcPort())
 | 
						|
	default:
 | 
						|
		return p.getSrcPort()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// getSrcIP returns the source ip, if the port string contains an src ip definition.
 | 
						|
func (p Port) getSrcIP() string {
 | 
						|
	matches := regExpPort.FindStringSubmatch(string(p))
 | 
						|
	i := regExpPort.SubexpIndex("srcIP")
 | 
						|
 | 
						|
	switch {
 | 
						|
	case len(matches) <= 0:
 | 
						|
		return ""
 | 
						|
	case i < 0:
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
 | 
						|
	return matches[i]
 | 
						|
}
 | 
						|
 | 
						|
// getSrcPort returns the source port, if the port string contains an src port definition.
 | 
						|
func (p Port) getSrcPort() string {
 | 
						|
	matches := regExpPort.FindStringSubmatch(string(p))
 | 
						|
	i := regExpPort.SubexpIndex("srcPort")
 | 
						|
 | 
						|
	switch {
 | 
						|
	case len(matches) <= 0:
 | 
						|
		return ""
 | 
						|
	case i < 0:
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
 | 
						|
	return matches[i]
 | 
						|
}
 |