Add a manifest filter limiting the number of matches

Adds a manifest filter for pulling which ensures only one
manifest from a manifest list is pulled even when multiple matches.
Removes unused filter platform list.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
Derek McGowan 2018-08-27 13:28:36 -07:00
parent 0a3f87ec2e
commit 3d1082e06d
No known key found for this signature in database
GPG Key ID: F58C5D0A4405ACDB
2 changed files with 42 additions and 41 deletions

View File

@ -338,7 +338,7 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag
}
defer done(ctx)
return c.fetch(ctx, fetchCtx, ref)
return c.fetch(ctx, fetchCtx, ref, 0)
}
// Pull downloads the provided content into containerd's content store
@ -372,7 +372,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
}
defer done(ctx)
img, err := c.fetch(ctx, pullCtx, ref)
img, err := c.fetch(ctx, pullCtx, ref, 1)
if err != nil {
return nil, err
}
@ -388,7 +388,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
return i, nil
}
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string) (images.Image, error) {
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) {
store := c.ContentStore()
name, desc, err := rCtx.Resolver.Resolve(ctx, ref)
if err != nil {
@ -414,6 +414,10 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string) (im
childrenHandler = images.SetChildrenLabels(store, childrenHandler)
// Filter children by platforms
childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.PlatformMatcher)
// Sort and limit manifests if a finite number is needed
if limit > 0 {
childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit)
}
handler = images.Handlers(append(rCtx.BaseHandlers,
remotes.FetchHandler(store, fetcher),

View File

@ -19,6 +19,7 @@ package images
import (
"context"
"fmt"
"sort"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/platforms"
@ -182,44 +183,6 @@ func SetChildrenLabels(manager content.Manager, f HandlerFunc) HandlerFunc {
}
}
// FilterPlatformList is a handler wrapper which limits the descriptors returned
// by a handler to the specified platforms.
func FilterPlatformList(f HandlerFunc, platformList ...string) HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
children, err := f(ctx, desc)
if err != nil {
return children, err
}
if len(platformList) == 0 {
return children, nil
}
var m platforms.Matcher
if len(platformList) > 0 {
ps := make([]ocispec.Platform, len(platformList))
for i, platform := range platformList {
p, err := platforms.Parse(platform)
if err != nil {
return nil, err
}
ps[i] = p
}
m = platforms.Any(ps...)
}
var descs []ocispec.Descriptor
for _, d := range children {
if d.Platform == nil || m.Match(*d.Platform) {
descs = append(descs, d)
}
}
return descs, nil
}
}
// FilterPlatforms is a handler wrapper which limits the descriptors returned
// based on matching the specified platform matcher.
func FilterPlatforms(f HandlerFunc, m platforms.Matcher) HandlerFunc {
@ -244,3 +207,37 @@ func FilterPlatforms(f HandlerFunc, m platforms.Matcher) HandlerFunc {
return descs, nil
}
}
// LimitManifests is a handler wrapper which filters the manifest descriptors
// returned using the provided platform.
// The results will be ordered according to the comparison operator and
// use the ordering in the manifests for equal matches.
// A limit of 0 or less is considered no limit.
func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
children, err := f(ctx, desc)
if err != nil {
return children, err
}
switch desc.MediaType {
case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
sort.SliceStable(children, func(i, j int) bool {
if children[i].Platform == nil {
return false
}
if children[j].Platform == nil {
return true
}
return m.Less(*children[i].Platform, *children[j].Platform)
})
if n > 0 && len(children) > n {
children = children[:n]
}
default:
// only limit manifests from an index
}
return children, nil
}
}