Correctly matches optional variants for amd64 arch. These should be used for standardized values v1-v4 from https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels. V1 remains the default and is cleared by default. Pulling a higher variant will match the highest available platform lower or equal to the provided one when platformVector is used. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
		
			
				
	
	
		
			204 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
   Copyright The containerd Authors.
 | 
						|
 | 
						|
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
   you may not use this file except in compliance with the License.
 | 
						|
   You may obtain a copy of the License at
 | 
						|
 | 
						|
       http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
   Unless required by applicable law or agreed to in writing, software
 | 
						|
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
   See the License for the specific language governing permissions and
 | 
						|
   limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package platforms
 | 
						|
 | 
						|
import (
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	specs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						|
)
 | 
						|
 | 
						|
// MatchComparer is able to match and compare platforms to
 | 
						|
// filter and sort platforms.
 | 
						|
type MatchComparer interface {
 | 
						|
	Matcher
 | 
						|
 | 
						|
	Less(specs.Platform, specs.Platform) bool
 | 
						|
}
 | 
						|
 | 
						|
// platformVector returns an (ordered) vector of appropriate specs.Platform
 | 
						|
// objects to try matching for the given platform object (see platforms.Only).
 | 
						|
func platformVector(platform specs.Platform) []specs.Platform {
 | 
						|
	vector := []specs.Platform{platform}
 | 
						|
 | 
						|
	switch platform.Architecture {
 | 
						|
	case "amd64":
 | 
						|
		if amd64Version, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && amd64Version > 1 {
 | 
						|
			for amd64Version--; amd64Version >= 1; amd64Version-- {
 | 
						|
				vector = append(vector, specs.Platform{
 | 
						|
					Architecture: platform.Architecture,
 | 
						|
					OS:           platform.OS,
 | 
						|
					OSVersion:    platform.OSVersion,
 | 
						|
					OSFeatures:   platform.OSFeatures,
 | 
						|
					Variant:      "v" + strconv.Itoa(amd64Version),
 | 
						|
				})
 | 
						|
			}
 | 
						|
		}
 | 
						|
		vector = append(vector, specs.Platform{
 | 
						|
			Architecture: "386",
 | 
						|
			OS:           platform.OS,
 | 
						|
			OSVersion:    platform.OSVersion,
 | 
						|
			OSFeatures:   platform.OSFeatures,
 | 
						|
		})
 | 
						|
	case "arm":
 | 
						|
		if armVersion, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && armVersion > 5 {
 | 
						|
			for armVersion--; armVersion >= 5; armVersion-- {
 | 
						|
				vector = append(vector, specs.Platform{
 | 
						|
					Architecture: platform.Architecture,
 | 
						|
					OS:           platform.OS,
 | 
						|
					OSVersion:    platform.OSVersion,
 | 
						|
					OSFeatures:   platform.OSFeatures,
 | 
						|
					Variant:      "v" + strconv.Itoa(armVersion),
 | 
						|
				})
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case "arm64":
 | 
						|
		variant := platform.Variant
 | 
						|
		if variant == "" {
 | 
						|
			variant = "v8"
 | 
						|
		}
 | 
						|
		vector = append(vector, platformVector(specs.Platform{
 | 
						|
			Architecture: "arm",
 | 
						|
			OS:           platform.OS,
 | 
						|
			OSVersion:    platform.OSVersion,
 | 
						|
			OSFeatures:   platform.OSFeatures,
 | 
						|
			Variant:      variant,
 | 
						|
		})...)
 | 
						|
	}
 | 
						|
 | 
						|
	return vector
 | 
						|
}
 | 
						|
 | 
						|
// Only returns a match comparer for a single platform
 | 
						|
// using default resolution logic for the platform.
 | 
						|
//
 | 
						|
// For arm/v8, will also match arm/v7, arm/v6 and arm/v5
 | 
						|
// For arm/v7, will also match arm/v6 and arm/v5
 | 
						|
// For arm/v6, will also match arm/v5
 | 
						|
// For amd64, will also match 386
 | 
						|
func Only(platform specs.Platform) MatchComparer {
 | 
						|
	return Ordered(platformVector(Normalize(platform))...)
 | 
						|
}
 | 
						|
 | 
						|
// OnlyStrict returns a match comparer for a single platform.
 | 
						|
//
 | 
						|
// Unlike Only, OnlyStrict does not match sub platforms.
 | 
						|
// So, "arm/vN" will not match "arm/vM" where M < N,
 | 
						|
// and "amd64" will not also match "386".
 | 
						|
//
 | 
						|
// OnlyStrict matches non-canonical forms.
 | 
						|
// So, "arm64" matches "arm/64/v8".
 | 
						|
func OnlyStrict(platform specs.Platform) MatchComparer {
 | 
						|
	return Ordered(Normalize(platform))
 | 
						|
}
 | 
						|
 | 
						|
// Ordered returns a platform MatchComparer which matches any of the platforms
 | 
						|
// but orders them in order they are provided.
 | 
						|
func Ordered(platforms ...specs.Platform) MatchComparer {
 | 
						|
	matchers := make([]Matcher, len(platforms))
 | 
						|
	for i := range platforms {
 | 
						|
		matchers[i] = NewMatcher(platforms[i])
 | 
						|
	}
 | 
						|
	return orderedPlatformComparer{
 | 
						|
		matchers: matchers,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Any returns a platform MatchComparer which matches any of the platforms
 | 
						|
// with no preference for ordering.
 | 
						|
func Any(platforms ...specs.Platform) MatchComparer {
 | 
						|
	matchers := make([]Matcher, len(platforms))
 | 
						|
	for i := range platforms {
 | 
						|
		matchers[i] = NewMatcher(platforms[i])
 | 
						|
	}
 | 
						|
	return anyPlatformComparer{
 | 
						|
		matchers: matchers,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// All is a platform MatchComparer which matches all platforms
 | 
						|
// with preference for ordering.
 | 
						|
var All MatchComparer = allPlatformComparer{}
 | 
						|
 | 
						|
type orderedPlatformComparer struct {
 | 
						|
	matchers []Matcher
 | 
						|
}
 | 
						|
 | 
						|
func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
 | 
						|
	for _, m := range c.matchers {
 | 
						|
		if m.Match(platform) {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
 | 
						|
	for _, m := range c.matchers {
 | 
						|
		p1m := m.Match(p1)
 | 
						|
		p2m := m.Match(p2)
 | 
						|
		if p1m && !p2m {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
		if p1m || p2m {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
type anyPlatformComparer struct {
 | 
						|
	matchers []Matcher
 | 
						|
}
 | 
						|
 | 
						|
func (c anyPlatformComparer) Match(platform specs.Platform) bool {
 | 
						|
	for _, m := range c.matchers {
 | 
						|
		if m.Match(platform) {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
 | 
						|
	var p1m, p2m bool
 | 
						|
	for _, m := range c.matchers {
 | 
						|
		if !p1m && m.Match(p1) {
 | 
						|
			p1m = true
 | 
						|
		}
 | 
						|
		if !p2m && m.Match(p2) {
 | 
						|
			p2m = true
 | 
						|
		}
 | 
						|
		if p1m && p2m {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// If one matches, and the other does, sort match first
 | 
						|
	return p1m && !p2m
 | 
						|
}
 | 
						|
 | 
						|
type allPlatformComparer struct{}
 | 
						|
 | 
						|
func (allPlatformComparer) Match(specs.Platform) bool {
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
 | 
						|
	return false
 | 
						|
}
 |