github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/platforms/compare.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package platforms
    18  
    19  import specs "github.com/opencontainers/image-spec/specs-go/v1"
    20  
    21  // MatchComparer is able to match and compare platforms to
    22  // filter and sort platforms.
    23  type MatchComparer interface {
    24  	Matcher
    25  
    26  	Less(specs.Platform, specs.Platform) bool
    27  }
    28  
    29  // Only returns a match comparer for a single platform
    30  // using default resolution logic for the platform.
    31  //
    32  // For ARMv8, will also match ARMv7, ARMv6 and ARMv5 (for 32bit runtimes)
    33  // For ARMv7, will also match ARMv6 and ARMv5
    34  // For ARMv6, will also match ARMv5
    35  func Only(platform specs.Platform) MatchComparer {
    36  	platform = Normalize(platform)
    37  	if platform.Architecture == "arm" {
    38  		if platform.Variant == "v8" {
    39  			return orderedPlatformComparer{
    40  				matchers: []Matcher{
    41  					&matcher{
    42  						Platform: platform,
    43  					},
    44  					&matcher{
    45  						Platform: specs.Platform{
    46  							Architecture: platform.Architecture,
    47  							OS:           platform.OS,
    48  							OSVersion:    platform.OSVersion,
    49  							OSFeatures:   platform.OSFeatures,
    50  							Variant:      "v7",
    51  						},
    52  					},
    53  					&matcher{
    54  						Platform: specs.Platform{
    55  							Architecture: platform.Architecture,
    56  							OS:           platform.OS,
    57  							OSVersion:    platform.OSVersion,
    58  							OSFeatures:   platform.OSFeatures,
    59  							Variant:      "v6",
    60  						},
    61  					},
    62  					&matcher{
    63  						Platform: specs.Platform{
    64  							Architecture: platform.Architecture,
    65  							OS:           platform.OS,
    66  							OSVersion:    platform.OSVersion,
    67  							OSFeatures:   platform.OSFeatures,
    68  							Variant:      "v5",
    69  						},
    70  					},
    71  				},
    72  			}
    73  		}
    74  		if platform.Variant == "v7" {
    75  			return orderedPlatformComparer{
    76  				matchers: []Matcher{
    77  					&matcher{
    78  						Platform: platform,
    79  					},
    80  					&matcher{
    81  						Platform: specs.Platform{
    82  							Architecture: platform.Architecture,
    83  							OS:           platform.OS,
    84  							OSVersion:    platform.OSVersion,
    85  							OSFeatures:   platform.OSFeatures,
    86  							Variant:      "v6",
    87  						},
    88  					},
    89  					&matcher{
    90  						Platform: specs.Platform{
    91  							Architecture: platform.Architecture,
    92  							OS:           platform.OS,
    93  							OSVersion:    platform.OSVersion,
    94  							OSFeatures:   platform.OSFeatures,
    95  							Variant:      "v5",
    96  						},
    97  					},
    98  				},
    99  			}
   100  		}
   101  		if platform.Variant == "v6" {
   102  			return orderedPlatformComparer{
   103  				matchers: []Matcher{
   104  					&matcher{
   105  						Platform: platform,
   106  					},
   107  					&matcher{
   108  						Platform: specs.Platform{
   109  							Architecture: platform.Architecture,
   110  							OS:           platform.OS,
   111  							OSVersion:    platform.OSVersion,
   112  							OSFeatures:   platform.OSFeatures,
   113  							Variant:      "v5",
   114  						},
   115  					},
   116  				},
   117  			}
   118  		}
   119  	}
   120  
   121  	return singlePlatformComparer{
   122  		Matcher: &matcher{
   123  			Platform: platform,
   124  		},
   125  	}
   126  }
   127  
   128  // Ordered returns a platform MatchComparer which matches any of the platforms
   129  // but orders them in order they are provided.
   130  func Ordered(platforms ...specs.Platform) MatchComparer {
   131  	matchers := make([]Matcher, len(platforms))
   132  	for i := range platforms {
   133  		matchers[i] = NewMatcher(platforms[i])
   134  	}
   135  	return orderedPlatformComparer{
   136  		matchers: matchers,
   137  	}
   138  }
   139  
   140  // Any returns a platform MatchComparer which matches any of the platforms
   141  // with no preference for ordering.
   142  func Any(platforms ...specs.Platform) MatchComparer {
   143  	matchers := make([]Matcher, len(platforms))
   144  	for i := range platforms {
   145  		matchers[i] = NewMatcher(platforms[i])
   146  	}
   147  	return anyPlatformComparer{
   148  		matchers: matchers,
   149  	}
   150  }
   151  
   152  // All is a platform MatchComparer which matches all platforms
   153  // with preference for ordering.
   154  var All MatchComparer = allPlatformComparer{}
   155  
   156  type singlePlatformComparer struct {
   157  	Matcher
   158  }
   159  
   160  func (c singlePlatformComparer) Less(p1, p2 specs.Platform) bool {
   161  	return c.Match(p1) && !c.Match(p2)
   162  }
   163  
   164  type orderedPlatformComparer struct {
   165  	matchers []Matcher
   166  }
   167  
   168  func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
   169  	for _, m := range c.matchers {
   170  		if m.Match(platform) {
   171  			return true
   172  		}
   173  	}
   174  	return false
   175  }
   176  
   177  func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
   178  	for _, m := range c.matchers {
   179  		p1m := m.Match(p1)
   180  		p2m := m.Match(p2)
   181  		if p1m && !p2m {
   182  			return true
   183  		}
   184  		if p1m || p2m {
   185  			return false
   186  		}
   187  	}
   188  	return false
   189  }
   190  
   191  type anyPlatformComparer struct {
   192  	matchers []Matcher
   193  }
   194  
   195  func (c anyPlatformComparer) Match(platform specs.Platform) bool {
   196  	for _, m := range c.matchers {
   197  		if m.Match(platform) {
   198  			return true
   199  		}
   200  	}
   201  	return false
   202  }
   203  
   204  func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
   205  	var p1m, p2m bool
   206  	for _, m := range c.matchers {
   207  		if !p1m && m.Match(p1) {
   208  			p1m = true
   209  		}
   210  		if !p2m && m.Match(p2) {
   211  			p2m = true
   212  		}
   213  		if p1m && p2m {
   214  			return false
   215  		}
   216  	}
   217  	// If one matches, and the other does, sort match first
   218  	return p1m && !p2m
   219  }
   220  
   221  type allPlatformComparer struct{}
   222  
   223  func (allPlatformComparer) Match(specs.Platform) bool {
   224  	return true
   225  }
   226  
   227  func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
   228  	return false
   229  }