...

Source file src/edge-infra.dev/pkg/f8n/warehouse/oci/match/match.go

Documentation: edge-infra.dev/pkg/f8n/warehouse/oci/match

     1  // Package match implements Warehouse matchers on top of ggcr/v1/match
     2  package match
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  
     9  	v1 "github.com/google/go-containerregistry/pkg/v1"
    10  	"github.com/google/go-containerregistry/pkg/v1/match"
    11  	"github.com/google/go-containerregistry/pkg/v1/partial"
    12  
    13  	wh "edge-infra.dev/pkg/f8n/warehouse"
    14  	"edge-infra.dev/pkg/f8n/warehouse/cluster"
    15  )
    16  
    17  // TODO: doc strings, tests
    18  
    19  var (
    20  	// ErrMultipleMatches occurs when more than one matching result was discovered.
    21  	ErrMultipleMatches = errors.New("multiple matches found")
    22  
    23  	// ErrNoMatches occurs when a single match is requested and none are found.
    24  	ErrNoMatches = errors.New("no match found")
    25  )
    26  
    27  // Local type aliases
    28  type Matcher = match.Matcher
    29  
    30  var (
    31  	Annotation = match.Annotation
    32  	Digests    = match.Digests
    33  )
    34  
    35  // Multiple returns a Matcher that executes all input matchers. If all return
    36  // true, a match is returned.
    37  func Multiple(matchers ...Matcher) Matcher {
    38  	return func(desc v1.Descriptor) bool {
    39  		matched := true
    40  		for _, m := range matchers {
    41  			if !m(desc) {
    42  				matched = false
    43  			}
    44  		}
    45  		return matched
    46  	}
    47  }
    48  
    49  // Provider returns a Matcher that returns true if the descriptor references
    50  // an artifact that supports the input provider.
    51  func Provider(p cluster.Provider) Matcher {
    52  	return func(desc v1.Descriptor) bool {
    53  		providers := desc.Annotations[wh.AnnotationClusterProviders]
    54  		switch {
    55  		case providers == "":
    56  			return false
    57  		case strings.Contains(providers, p.String()):
    58  			return true
    59  		default:
    60  			return false
    61  		}
    62  	}
    63  }
    64  
    65  // Name matches on the ref name annotation which refers to the package name that
    66  // the descriptor points to (e.g., for provider variants or dependencies).
    67  func RefName(n string) Matcher {
    68  	return Annotation(wh.AnnotationRefName, n)
    69  }
    70  
    71  // Dependencies performs an inverse match on the ref name annotation to identify
    72  // dependencies on other packages.
    73  func Dependencies(pkgName string) Matcher {
    74  	return func(desc v1.Descriptor) bool {
    75  		if desc.Annotations == nil {
    76  			return false
    77  		}
    78  		if desc.Annotations[wh.AnnotationRefName] == pkgName {
    79  			return false
    80  		}
    81  		return true
    82  	}
    83  }
    84  
    85  // FindImage searches for exactly one matching v1.Image in the input idx.
    86  //
    87  // If more than one is found, ErrMultipleMatches is returned.
    88  func FindImage(idx v1.ImageIndex, m Matcher) (v1.Image, error) {
    89  	d, err := partial.FindImages(idx, m)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	switch {
    94  	case len(d) > 1:
    95  		return nil, fmt.Errorf("%w", ErrMultipleMatches)
    96  	case len(d) == 1:
    97  		return d[0], nil
    98  	default:
    99  		return nil, fmt.Errorf("%w", ErrNoMatches)
   100  	}
   101  }
   102  
   103  // FindIndex searches for exactly one matching v1.ImageIndex in the input idx.
   104  //
   105  // If more than one is found, ErrMultipleMatches is returned.
   106  func FindIndex(idx v1.ImageIndex, m Matcher) (v1.ImageIndex, error) {
   107  	d, err := partial.FindIndexes(idx, m)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	switch {
   112  	case len(d) > 1:
   113  		return nil, fmt.Errorf("%w", ErrMultipleMatches)
   114  	case len(d) == 1:
   115  		return d[0], nil
   116  	default:
   117  		return nil, fmt.Errorf("%w", ErrNoMatches)
   118  	}
   119  }
   120  
   121  // FindManifest searches for exactly one matching v1.Descriptor in the input idx.
   122  //
   123  // If more than one is found, ErrMultipleMatches is returned.
   124  func FindManifest(idx v1.ImageIndex, m Matcher) (v1.Descriptor, error) {
   125  	d, err := partial.FindManifests(idx, m)
   126  	if err != nil {
   127  		return v1.Descriptor{}, err
   128  	}
   129  	switch {
   130  	case len(d) > 1:
   131  		return v1.Descriptor{}, fmt.Errorf("%w", ErrMultipleMatches)
   132  	case len(d) == 1:
   133  		return d[0], nil
   134  	default:
   135  		return v1.Descriptor{}, fmt.Errorf("%w", ErrNoMatches)
   136  	}
   137  }
   138  
   139  // FindIndexes is a local alias for partial.FindIndexes
   140  func FindIndexes(idx v1.ImageIndex, m Matcher) ([]v1.ImageIndex, error) {
   141  	return partial.FindIndexes(idx, m)
   142  }
   143  
   144  // FindImages is a local alias for partial.FindImages
   145  func FindImages(idx v1.ImageIndex, m Matcher) ([]v1.Image, error) {
   146  	return partial.FindImages(idx, m)
   147  }
   148  
   149  // FindManifests is a local alias for partial.FindManifests
   150  func FindManifests(idx v1.ImageIndex, m Matcher) ([]v1.Descriptor, error) {
   151  	return partial.FindManifests(idx, m)
   152  }
   153  

View as plain text