...

Source file src/github.com/google/go-containerregistry/pkg/v1/platform.go

Documentation: github.com/google/go-containerregistry/pkg/v1

     1  // Copyright 2018 Google LLC All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package v1
    16  
    17  import (
    18  	"fmt"
    19  	"sort"
    20  	"strings"
    21  )
    22  
    23  // Platform represents the target os/arch for an image.
    24  type Platform struct {
    25  	Architecture string   `json:"architecture"`
    26  	OS           string   `json:"os"`
    27  	OSVersion    string   `json:"os.version,omitempty"`
    28  	OSFeatures   []string `json:"os.features,omitempty"`
    29  	Variant      string   `json:"variant,omitempty"`
    30  	Features     []string `json:"features,omitempty"`
    31  }
    32  
    33  func (p Platform) String() string {
    34  	if p.OS == "" {
    35  		return ""
    36  	}
    37  	var b strings.Builder
    38  	b.WriteString(p.OS)
    39  	if p.Architecture != "" {
    40  		b.WriteString("/")
    41  		b.WriteString(p.Architecture)
    42  	}
    43  	if p.Variant != "" {
    44  		b.WriteString("/")
    45  		b.WriteString(p.Variant)
    46  	}
    47  	if p.OSVersion != "" {
    48  		b.WriteString(":")
    49  		b.WriteString(p.OSVersion)
    50  	}
    51  	return b.String()
    52  }
    53  
    54  // ParsePlatform parses a string representing a Platform, if possible.
    55  func ParsePlatform(s string) (*Platform, error) {
    56  	var p Platform
    57  	parts := strings.Split(strings.TrimSpace(s), ":")
    58  	if len(parts) == 2 {
    59  		p.OSVersion = parts[1]
    60  	}
    61  	parts = strings.Split(parts[0], "/")
    62  	if len(parts) > 0 {
    63  		p.OS = parts[0]
    64  	}
    65  	if len(parts) > 1 {
    66  		p.Architecture = parts[1]
    67  	}
    68  	if len(parts) > 2 {
    69  		p.Variant = parts[2]
    70  	}
    71  	if len(parts) > 3 {
    72  		return nil, fmt.Errorf("too many slashes in platform spec: %s", s)
    73  	}
    74  	return &p, nil
    75  }
    76  
    77  // Equals returns true if the given platform is semantically equivalent to this one.
    78  // The order of Features and OSFeatures is not important.
    79  func (p Platform) Equals(o Platform) bool {
    80  	return p.OS == o.OS &&
    81  		p.Architecture == o.Architecture &&
    82  		p.Variant == o.Variant &&
    83  		p.OSVersion == o.OSVersion &&
    84  		stringSliceEqualIgnoreOrder(p.OSFeatures, o.OSFeatures) &&
    85  		stringSliceEqualIgnoreOrder(p.Features, o.Features)
    86  }
    87  
    88  // Satisfies returns true if this Platform "satisfies" the given spec Platform.
    89  //
    90  // Note that this is different from Equals and that Satisfies is not reflexive.
    91  //
    92  // The given spec represents "requirements" such that any missing values in the
    93  // spec are not compared.
    94  //
    95  // For OSFeatures and Features, Satisfies will return true if this Platform's
    96  // fields contain a superset of the values in the spec's fields (order ignored).
    97  func (p Platform) Satisfies(spec Platform) bool {
    98  	return satisfies(spec.OS, p.OS) &&
    99  		satisfies(spec.Architecture, p.Architecture) &&
   100  		satisfies(spec.Variant, p.Variant) &&
   101  		satisfies(spec.OSVersion, p.OSVersion) &&
   102  		satisfiesList(spec.OSFeatures, p.OSFeatures) &&
   103  		satisfiesList(spec.Features, p.Features)
   104  }
   105  
   106  func satisfies(want, have string) bool {
   107  	return want == "" || want == have
   108  }
   109  
   110  func satisfiesList(want, have []string) bool {
   111  	if len(want) == 0 {
   112  		return true
   113  	}
   114  
   115  	set := map[string]struct{}{}
   116  	for _, h := range have {
   117  		set[h] = struct{}{}
   118  	}
   119  
   120  	for _, w := range want {
   121  		if _, ok := set[w]; !ok {
   122  			return false
   123  		}
   124  	}
   125  
   126  	return true
   127  }
   128  
   129  // stringSliceEqual compares 2 string slices and returns if their contents are identical.
   130  func stringSliceEqual(a, b []string) bool {
   131  	if len(a) != len(b) {
   132  		return false
   133  	}
   134  	for i, elm := range a {
   135  		if elm != b[i] {
   136  			return false
   137  		}
   138  	}
   139  	return true
   140  }
   141  
   142  // stringSliceEqualIgnoreOrder compares 2 string slices and returns if their contents are identical, ignoring order
   143  func stringSliceEqualIgnoreOrder(a, b []string) bool {
   144  	if a != nil && b != nil {
   145  		sort.Strings(a)
   146  		sort.Strings(b)
   147  	}
   148  	return stringSliceEqual(a, b)
   149  }
   150  

View as plain text