github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/image/cache/compare.go (about) 1 package cache // import "github.com/docker/docker/image/cache" 2 3 import ( 4 "strings" 5 6 "github.com/containerd/containerd/platforms" 7 "github.com/docker/docker/api/types/container" 8 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 9 ) 10 11 // TODO: Remove once containerd image service directly uses the ImageCache and 12 // LocalImageCache structs. 13 func CompareConfig(a, b *container.Config) bool { 14 return compare(a, b) 15 } 16 17 func comparePlatform(builderPlatform, imagePlatform ocispec.Platform) bool { 18 // On Windows, only check the Major and Minor versions. 19 // The Build and Revision compatibility depends on whether `process` or 20 // `hyperv` isolation used. 21 // 22 // Fixes https://github.com/moby/moby/issues/47307 23 if builderPlatform.OS == "windows" && imagePlatform.OS == builderPlatform.OS { 24 // OSVersion format is: 25 // Major.Minor.Build.Revision 26 builderParts := strings.Split(builderPlatform.OSVersion, ".") 27 imageParts := strings.Split(imagePlatform.OSVersion, ".") 28 29 if len(builderParts) >= 3 && len(imageParts) >= 3 { 30 // Keep only Major & Minor. 31 builderParts[0] = imageParts[0] 32 builderParts[1] = imageParts[1] 33 imagePlatform.OSVersion = strings.Join(builderParts, ".") 34 } 35 } 36 37 return platforms.Only(builderPlatform).Match(imagePlatform) 38 } 39 40 // compare two Config struct. Do not container-specific fields: 41 // - Image 42 // - Hostname 43 // - Domainname 44 // - MacAddress 45 func compare(a, b *container.Config) bool { 46 if a == nil || b == nil { 47 return false 48 } 49 50 if len(a.Env) != len(b.Env) { 51 return false 52 } 53 if len(a.Cmd) != len(b.Cmd) { 54 return false 55 } 56 if len(a.Entrypoint) != len(b.Entrypoint) { 57 return false 58 } 59 if len(a.Shell) != len(b.Shell) { 60 return false 61 } 62 if len(a.ExposedPorts) != len(b.ExposedPorts) { 63 return false 64 } 65 if len(a.Volumes) != len(b.Volumes) { 66 return false 67 } 68 if len(a.Labels) != len(b.Labels) { 69 return false 70 } 71 if len(a.OnBuild) != len(b.OnBuild) { 72 return false 73 } 74 75 for i := 0; i < len(a.Env); i++ { 76 if a.Env[i] != b.Env[i] { 77 return false 78 } 79 } 80 for i := 0; i < len(a.OnBuild); i++ { 81 if a.OnBuild[i] != b.OnBuild[i] { 82 return false 83 } 84 } 85 for i := 0; i < len(a.Cmd); i++ { 86 if a.Cmd[i] != b.Cmd[i] { 87 return false 88 } 89 } 90 for i := 0; i < len(a.Entrypoint); i++ { 91 if a.Entrypoint[i] != b.Entrypoint[i] { 92 return false 93 } 94 } 95 for i := 0; i < len(a.Shell); i++ { 96 if a.Shell[i] != b.Shell[i] { 97 return false 98 } 99 } 100 for k := range a.ExposedPorts { 101 if _, exists := b.ExposedPorts[k]; !exists { 102 return false 103 } 104 } 105 for key := range a.Volumes { 106 if _, exists := b.Volumes[key]; !exists { 107 return false 108 } 109 } 110 for k, v := range a.Labels { 111 if v != b.Labels[k] { 112 return false 113 } 114 } 115 116 if a.AttachStdin != b.AttachStdin { 117 return false 118 } 119 if a.AttachStdout != b.AttachStdout { 120 return false 121 } 122 if a.AttachStderr != b.AttachStderr { 123 return false 124 } 125 if a.NetworkDisabled != b.NetworkDisabled { 126 return false 127 } 128 if a.Tty != b.Tty { 129 return false 130 } 131 if a.OpenStdin != b.OpenStdin { 132 return false 133 } 134 if a.StdinOnce != b.StdinOnce { 135 return false 136 } 137 if a.ArgsEscaped != b.ArgsEscaped { 138 return false 139 } 140 if a.User != b.User { 141 return false 142 } 143 if a.WorkingDir != b.WorkingDir { 144 return false 145 } 146 if a.StopSignal != b.StopSignal { 147 return false 148 } 149 150 if (a.StopTimeout == nil) != (b.StopTimeout == nil) { 151 return false 152 } 153 if a.StopTimeout != nil && b.StopTimeout != nil { 154 if *a.StopTimeout != *b.StopTimeout { 155 return false 156 } 157 } 158 if (a.Healthcheck == nil) != (b.Healthcheck == nil) { 159 return false 160 } 161 if a.Healthcheck != nil && b.Healthcheck != nil { 162 if a.Healthcheck.Interval != b.Healthcheck.Interval { 163 return false 164 } 165 if a.Healthcheck.StartInterval != b.Healthcheck.StartInterval { 166 return false 167 } 168 if a.Healthcheck.StartPeriod != b.Healthcheck.StartPeriod { 169 return false 170 } 171 if a.Healthcheck.Timeout != b.Healthcheck.Timeout { 172 return false 173 } 174 if a.Healthcheck.Retries != b.Healthcheck.Retries { 175 return false 176 } 177 if len(a.Healthcheck.Test) != len(b.Healthcheck.Test) { 178 return false 179 } 180 for i := 0; i < len(a.Healthcheck.Test); i++ { 181 if a.Healthcheck.Test[i] != b.Healthcheck.Test[i] { 182 return false 183 } 184 } 185 } 186 187 return true 188 }