github.com/oras-project/oras-go@v0.3.0/pkg/oras/pull_opts.go (about)

     1  /*
     2  Copyright The ORAS Authors.
     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  
    16  package oras
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"io"
    22  	"sync"
    23  
    24  	orascontent "github.com/oras-project/oras-go/pkg/content"
    25  
    26  	"github.com/containerd/containerd/images"
    27  	"github.com/opencontainers/go-digest"
    28  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    29  	"golang.org/x/sync/semaphore"
    30  )
    31  
    32  type pullOpts struct {
    33  	allowedMediaTypes      []string
    34  	dispatch               func(context.Context, images.Handler, *semaphore.Weighted, ...ocispec.Descriptor) error
    35  	baseHandlers           []images.Handler
    36  	callbackHandlers       []images.Handler
    37  	contentProvideIngester orascontent.ProvideIngester
    38  	filterName             func(ocispec.Descriptor) bool
    39  	cachedMediaTypes       []string
    40  }
    41  
    42  // PullOpt allows callers to set options on the oras pull
    43  type PullOpt func(o *pullOpts) error
    44  
    45  func pullOptsDefaults() *pullOpts {
    46  	return &pullOpts{
    47  		dispatch:         images.Dispatch,
    48  		filterName:       filterName,
    49  		cachedMediaTypes: []string{ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex},
    50  	}
    51  }
    52  
    53  // WithCachedMediaTypes sets the media types normally cached in memory when pulling.
    54  func WithCachedMediaTypes(cachedMediaTypes ...string) PullOpt {
    55  	return func(o *pullOpts) error {
    56  		o.cachedMediaTypes = cachedMediaTypes
    57  		return nil
    58  	}
    59  }
    60  
    61  // WithAdditionalCachedMediaTypes adds media types normally cached in memory when pulling.
    62  // This does not replace the default media types, but appends to them
    63  func WithAdditionalCachedMediaTypes(cachedMediaTypes ...string) PullOpt {
    64  	return func(o *pullOpts) error {
    65  		o.cachedMediaTypes = append(o.cachedMediaTypes, cachedMediaTypes...)
    66  		return nil
    67  	}
    68  }
    69  
    70  // WithAllowedMediaType sets the allowed media types
    71  func WithAllowedMediaType(allowedMediaTypes ...string) PullOpt {
    72  	return func(o *pullOpts) error {
    73  		o.allowedMediaTypes = append(o.allowedMediaTypes, allowedMediaTypes...)
    74  		return nil
    75  	}
    76  }
    77  
    78  // WithAllowedMediaTypes sets the allowed media types
    79  func WithAllowedMediaTypes(allowedMediaTypes []string) PullOpt {
    80  	return func(o *pullOpts) error {
    81  		o.allowedMediaTypes = append(o.allowedMediaTypes, allowedMediaTypes...)
    82  		return nil
    83  	}
    84  }
    85  
    86  // WithPullByBFS opt to pull in sequence with breath-first search
    87  func WithPullByBFS(o *pullOpts) error {
    88  	o.dispatch = dispatchBFS
    89  	return nil
    90  }
    91  
    92  // WithPullBaseHandler provides base handlers, which will be called before
    93  // any pull specific handlers.
    94  func WithPullBaseHandler(handlers ...images.Handler) PullOpt {
    95  	return func(o *pullOpts) error {
    96  		o.baseHandlers = append(o.baseHandlers, handlers...)
    97  		return nil
    98  	}
    99  }
   100  
   101  // WithPullCallbackHandler provides callback handlers, which will be called after
   102  // any pull specific handlers.
   103  func WithPullCallbackHandler(handlers ...images.Handler) PullOpt {
   104  	return func(o *pullOpts) error {
   105  		o.callbackHandlers = append(o.callbackHandlers, handlers...)
   106  		return nil
   107  	}
   108  }
   109  
   110  // WithContentProvideIngester opt to the provided Provider and Ingester
   111  // for file system I/O, including caches.
   112  func WithContentProvideIngester(store orascontent.ProvideIngester) PullOpt {
   113  	return func(o *pullOpts) error {
   114  		o.contentProvideIngester = store
   115  		return nil
   116  	}
   117  }
   118  
   119  // WithPullEmptyNameAllowed allows pulling blobs with empty name.
   120  func WithPullEmptyNameAllowed() PullOpt {
   121  	return func(o *pullOpts) error {
   122  		o.filterName = func(ocispec.Descriptor) bool {
   123  			return true
   124  		}
   125  		return nil
   126  	}
   127  }
   128  
   129  // WithPullStatusTrack report results to stdout
   130  func WithPullStatusTrack(writer io.Writer) PullOpt {
   131  	return WithPullCallbackHandler(pullStatusTrack(writer))
   132  }
   133  
   134  func pullStatusTrack(writer io.Writer) images.Handler {
   135  	var printLock sync.Mutex
   136  	return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
   137  		if name, ok := orascontent.ResolveName(desc); ok {
   138  			digestString := desc.Digest.String()
   139  			if err := desc.Digest.Validate(); err == nil {
   140  				if algo := desc.Digest.Algorithm(); algo == digest.SHA256 {
   141  					digestString = desc.Digest.Encoded()[:12]
   142  				}
   143  			}
   144  			printLock.Lock()
   145  			defer printLock.Unlock()
   146  			fmt.Fprintln(writer, "Downloaded", digestString, name)
   147  		}
   148  		return nil, nil
   149  	})
   150  }