fix(domain): add .Equal() methods

This commit is contained in:
Markus Pesch 2023-07-20 13:51:15 +02:00
parent b429c033b7
commit 274f3a7805
Signed by: volker.raschek
GPG Key ID: 852BCC170D81A982
3 changed files with 248 additions and 37 deletions

View File

@ -0,0 +1 @@
package cmd

View File

@ -8,24 +8,47 @@ type Config struct {
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 existsKeyInMap(c.Networks, name)
return ExistsInMap(c.Networks, name)
}
// ExistsSecret returns true if a secret with the passed named exists.
func (c *Config) ExistsSecret(name string) bool {
return existsKeyInMap(c.Secrets, name)
return ExistsInMap(c.Secrets, name)
}
// ExistsService returns true if a service with the passed named exists.
func (c *Config) ExistsService(name string) bool {
return existsKeyInMap(c.Services, name)
return ExistsInMap(c.Services, name)
}
// ExistsVolumes returns true if a volume with the passed named exists.
func (c *Config) ExistsVolume(name string) bool {
return existsKeyInMap(c.Volumes, name)
return ExistsInMap(c.Volumes, name)
}
// MergeLastWin merges a config and overwrite already existing properties
@ -46,29 +69,29 @@ func (c *Config) MergeLastWin(config *Config) {
}
}
// for secretName, secret := range c.Secrets {
// if secret == nil {
// continue
// }
for secretName, secret := range c.Secrets {
if secret == nil {
continue
}
// if c.ExistsSecret(secretName) {
// c.Secrets[secretName].MergeLastWin(secret)
// } else {
// c.Secrets[secretName] = secret
// }
// }
if c.ExistsSecret(secretName) {
c.Secrets[secretName].MergeLastWin(secret)
} else {
c.Secrets[secretName] = secret
}
}
// for serviceName, service := range c.Services {
// if service == nil {
// continue
// }
for serviceName, service := range c.Services {
if service == nil {
continue
}
// if c.ExistsService(serviceName) {
// c.Services[serviceName].MergeLastWin(service)
// } else {
// c.Services[serviceName] = service
// }
// }
if c.ExistsService(serviceName) {
c.Services[serviceName].MergeLastWin(service)
} else {
c.Services[serviceName] = service
}
}
// for volumeName, volume := range c.Volumes {
// if volume == nil {
@ -98,38 +121,108 @@ type Network struct {
IPAM *NetworkIPAM `json:"ipam,omitempty" yaml:"ipam,omitempty"`
}
// MergeLastWin merges a network and overwrite already existing properties
// 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) MergeLastWin(network *Network) {
if n.External != network.External {
n.External = network.External
if !n.IPAM.Equal(network.IPAM) {
n.IPAM = network.IPAM
}
if n.Driver != network.Driver {
n.Driver = network.Driver
}
// n.IPAM.MergeLastWin(network.IPAM.Config)
}
type NetworkIPAM struct {
Config []*NetworkIPAMConfig `json:"config,omitempty" yaml:"config,omitempty"`
}
func (nipam *NetworkIPAM) Merge(networkIPAM *NetworkIPAM) {
if networkIPAM == nil {
return
// 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.Config, networkIPAM.Config)
}
}
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
}
}
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
}
}
func (s *Secret) MergeLastWin(secret *Secret) {
if !s.Equal(secret) {
s.File = secret.File
}
}
type Service struct {
CapabilitiesAdd []string `json:"cap_add,omitempty" yaml:"cap_add,omitempty"`
CapabilitiesDrop []string `json:"cap_drop,omitempty" yaml:"cap_drop,omitempty"`
@ -145,20 +238,109 @@ type Service struct {
Volumes []string `json:"volumes,omitempty" yaml:"volumes,omitempty"`
}
// 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.CapabilitiesAdd, service.CapabilitiesAdd) &&
equalSlice(s.CapabilitiesDrop, service.CapabilitiesDrop) &&
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)
}
}
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 {
serviceDeployment, ok := equalable.(*ServiceDeploy)
if !ok {
return false
}
switch {
case sd == nil && serviceDeployment == nil:
return true
case sd != nil && serviceDeployment == nil:
fallthrough
case sd == nil && serviceDeployment != nil:
return false
default:
return sd.Resources.Equal(serviceDeployment.Resources)
}
}
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 {
serviceDeploymentResources, ok := equalable.(*ServiceDeployResources)
if !ok {
return false
}
switch {
case sdr == nil && serviceDeploymentResources == nil:
return true
case sdr != nil && serviceDeploymentResources == nil:
fallthrough
case sdr == nil && serviceDeploymentResources != nil:
return false
default:
return sdr.Limits.Equal(serviceDeploymentResources.Limits) &&
sdr.Reservations.Equal(serviceDeploymentResources)
}
}
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 {
serviceDeploymentResourcesLimits, ok := equalable.(*ServiceDeployResourcesLimits)
if !ok {
return false
}
switch {
case sdrl == nil && serviceDeploymentResourcesLimits == nil:
return true
case sdrl != nil && serviceDeploymentResourcesLimits == nil:
fallthrough
case sdrl == nil && serviceDeploymentResourcesLimits != nil:
return false
default:
return sdrl.CPUs == serviceDeploymentResourcesLimits.CPUs &&
sdrl.Memory == serviceDeploymentResourcesLimits.Memory
}
}
type ServiceNetwork struct {
Aliases []string `json:"aliases,omitempty" yaml:"aliases,omitempty"`
}
@ -178,7 +360,7 @@ func (sn *ServiceNetwork) Equal(equalable Equalable) bool {
case sn == nil && serviceNetwork != nil:
return false
default:
//TODO: return false
return equalSlice(sn.Aliases, serviceNetwork.Aliases)
}
}
@ -254,3 +436,20 @@ func (v *Volume) Equal(equalable Equalable) bool {
return v.External == volume.External
}
}
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)
}

View File

@ -52,3 +52,14 @@ func EqualStringMap[R Equalable](mapA, mapB map[string]R) bool {
return equalFunc(mapA, mapB) && equalFunc(mapB, mapA)
}
// ExistsInMap returns true if object of type any exists under the passed name.
func ExistsInMap[T any](m map[string]T, name string) bool {
switch {
case m == nil:
return false
default:
_, present := m[name]
return present
}
}