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  }