Upgrade k8s package verison (#5358)
* upgrade k8s package version Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> * Script upgrade and code formatting. Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io>
This commit is contained in:
213
vendor/oras.land/oras-go/pkg/oras/copy.go
vendored
Normal file
213
vendor/oras.land/oras-go/pkg/oras/copy.go
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright The ORAS 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 oras
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"oras.land/oras-go/pkg/target"
|
||||
)
|
||||
|
||||
// Copy copy a ref from one target.Target to a ref in another target.Target. If toRef is blank, reuses fromRef
|
||||
// Returns the root
|
||||
// Descriptor of the copied item. Can use the root to retrieve child elements from target.Target.
|
||||
func Copy(ctx context.Context, from target.Target, fromRef string, to target.Target, toRef string, opts ...CopyOpt) (ocispec.Descriptor, error) {
|
||||
if from == nil {
|
||||
return ocispec.Descriptor{}, ErrFromTargetUndefined
|
||||
}
|
||||
if to == nil {
|
||||
return ocispec.Descriptor{}, ErrToTargetUndefined
|
||||
}
|
||||
// blank toRef
|
||||
if toRef == "" {
|
||||
toRef = fromRef
|
||||
}
|
||||
opt := copyOptsDefaults()
|
||||
for _, o := range opts {
|
||||
if err := o(opt); err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if from == nil {
|
||||
return ocispec.Descriptor{}, ErrFromResolverUndefined
|
||||
}
|
||||
if to == nil {
|
||||
return ocispec.Descriptor{}, ErrToResolverUndefined
|
||||
}
|
||||
|
||||
// for the "from", we resolve the ref, then use resolver.Fetcher to fetch the various content blobs
|
||||
// for the "to", we simply use resolver.Pusher to push the various content blobs
|
||||
|
||||
_, desc, err := from.Resolve(ctx, fromRef)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
|
||||
fetcher, err := from.Fetcher(ctx, fromRef)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
// construct the reference we send to the pusher using the digest, so it knows what the root is
|
||||
pushRef := fmt.Sprintf("%s@%s", toRef, desc.Digest.String())
|
||||
pusher, err := to.Pusher(ctx, pushRef)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
|
||||
if err := transferContent(ctx, desc, fetcher, pusher, opt); err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
func transferContent(ctx context.Context, desc ocispec.Descriptor, fetcher remotes.Fetcher, pusher remotes.Pusher, opts *copyOpts) error {
|
||||
var descriptors, manifests []ocispec.Descriptor
|
||||
lock := &sync.Mutex{}
|
||||
picker := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if isAllowedMediaType(desc.MediaType, opts.allowedMediaTypes...) {
|
||||
if opts.filterName(desc) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
descriptors = append(descriptors, desc)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
// we use a hybrid store - a cache wrapping the underlying pusher - for two reasons:
|
||||
// 1. so that we can cache the manifests as pushing them, then retrieve them later to push in reverse order after the blobs
|
||||
// 2. so that we can retrieve them to analyze and find children in the Dispatch routine
|
||||
store := opts.contentProvideIngesterPusherFetcher
|
||||
if store == nil {
|
||||
store = newHybridStoreFromPusher(pusher, opts.cachedMediaTypes, true)
|
||||
}
|
||||
|
||||
// fetchHandler pushes to the *store*, which may or may not cache it
|
||||
baseFetchHandler := func(p remotes.Pusher, f remotes.Fetcher) images.HandlerFunc {
|
||||
return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
cw, err := p.Push(ctx, desc)
|
||||
if err != nil {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
defer cw.Close()
|
||||
|
||||
rc, err := f.Fetch(ctx, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
return nil, content.Copy(ctx, cw, rc, desc.Size, desc.Digest)
|
||||
})
|
||||
}
|
||||
|
||||
// track all of our manifests that will be cached
|
||||
fetchHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if isAllowedMediaType(desc.MediaType, opts.cachedMediaTypes...) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
manifests = append(manifests, desc)
|
||||
}
|
||||
return baseFetchHandler(store, fetcher)(ctx, desc)
|
||||
})
|
||||
|
||||
handlers := []images.Handler{
|
||||
filterHandler(opts, opts.allowedMediaTypes...),
|
||||
}
|
||||
handlers = append(handlers, opts.baseHandlers...)
|
||||
handlers = append(handlers,
|
||||
fetchHandler,
|
||||
picker,
|
||||
images.ChildrenHandler(&ProviderWrapper{Fetcher: store}),
|
||||
)
|
||||
handlers = append(handlers, opts.callbackHandlers...)
|
||||
|
||||
if err := opts.dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we cached all of the manifests, so push those out
|
||||
// Iterate in reverse order as seen, parent always uploaded after child
|
||||
for i := len(manifests) - 1; i >= 0; i-- {
|
||||
_, err := baseFetchHandler(pusher, store)(ctx, manifests[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// if the option to request the root manifest was passed, accommodate it
|
||||
if opts.saveManifest != nil && len(manifests) > 0 {
|
||||
rc, err := store.Fetch(ctx, manifests[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get root manifest to save based on CopyOpt: %v", err)
|
||||
}
|
||||
defer rc.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
if _, err := buf.ReadFrom(rc); err != nil {
|
||||
return fmt.Errorf("unable to read data for root manifest to save based on CopyOpt: %v", err)
|
||||
}
|
||||
// get the root manifest from the store
|
||||
opts.saveManifest(buf.Bytes())
|
||||
}
|
||||
|
||||
// if the option to request the layers was passed, accommodate it
|
||||
if opts.saveLayers != nil && len(descriptors) > 0 {
|
||||
opts.saveLayers(descriptors)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func filterHandler(opts *copyOpts, allowedMediaTypes ...string) images.HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
switch {
|
||||
case isAllowedMediaType(desc.MediaType, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex):
|
||||
return nil, nil
|
||||
case isAllowedMediaType(desc.MediaType, allowedMediaTypes...):
|
||||
if opts.filterName(desc) {
|
||||
return nil, nil
|
||||
}
|
||||
log.G(ctx).Warnf("blob no name: %v", desc.Digest)
|
||||
default:
|
||||
log.G(ctx).Warnf("unknown type: %v", desc.MediaType)
|
||||
}
|
||||
return nil, images.ErrStopHandler
|
||||
}
|
||||
}
|
||||
|
||||
func isAllowedMediaType(mediaType string, allowedMediaTypes ...string) bool {
|
||||
if len(allowedMediaTypes) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, allowedMediaType := range allowedMediaTypes {
|
||||
if mediaType == allowedMediaType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
42
vendor/oras.land/oras-go/pkg/oras/errors.go
vendored
Normal file
42
vendor/oras.land/oras-go/pkg/oras/errors.go
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright The ORAS 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 oras
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Common errors
|
||||
var (
|
||||
ErrResolverUndefined = errors.New("resolver undefined")
|
||||
ErrFromResolverUndefined = errors.New("from target resolver undefined")
|
||||
ErrToResolverUndefined = errors.New("to target resolver undefined")
|
||||
ErrFromTargetUndefined = errors.New("from target undefined")
|
||||
ErrToTargetUndefined = errors.New("from target undefined")
|
||||
)
|
||||
|
||||
// Path validation related errors
|
||||
var (
|
||||
ErrDirtyPath = errors.New("dirty path")
|
||||
ErrPathNotSlashSeparated = errors.New("path not slash separated")
|
||||
ErrAbsolutePathDisallowed = errors.New("absolute path disallowed")
|
||||
ErrPathTraversalDisallowed = errors.New("path traversal disallowed")
|
||||
)
|
||||
|
||||
// ErrStopProcessing is used to stop processing an oras operation.
|
||||
// This error only makes sense in sequential pulling operation.
|
||||
var ErrStopProcessing = fmt.Errorf("stop processing")
|
||||
254
vendor/oras.land/oras-go/pkg/oras/opts.go
vendored
Normal file
254
vendor/oras.land/oras-go/pkg/oras/opts.go
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
Copyright The ORAS 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 oras
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/semaphore"
|
||||
orascontent "oras.land/oras-go/pkg/content"
|
||||
)
|
||||
|
||||
func copyOptsDefaults() *copyOpts {
|
||||
return ©Opts{
|
||||
dispatch: images.Dispatch,
|
||||
filterName: filterName,
|
||||
cachedMediaTypes: []string{ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex},
|
||||
validateName: ValidateNameAsPath,
|
||||
}
|
||||
}
|
||||
|
||||
type CopyOpt func(o *copyOpts) error
|
||||
|
||||
type copyOpts struct {
|
||||
allowedMediaTypes []string
|
||||
dispatch func(context.Context, images.Handler, *semaphore.Weighted, ...ocispec.Descriptor) error
|
||||
baseHandlers []images.Handler
|
||||
callbackHandlers []images.Handler
|
||||
contentProvideIngesterPusherFetcher orascontent.Store
|
||||
filterName func(ocispec.Descriptor) bool
|
||||
cachedMediaTypes []string
|
||||
|
||||
saveManifest func([]byte)
|
||||
saveLayers func([]ocispec.Descriptor)
|
||||
validateName func(desc ocispec.Descriptor) error
|
||||
|
||||
userAgent string
|
||||
}
|
||||
|
||||
// ValidateNameAsPath validates name in the descriptor as file path in order
|
||||
// to generate good packages intended to be pulled using the FileStore or
|
||||
// the oras cli.
|
||||
// For cross-platform considerations, only unix paths are accepted.
|
||||
func ValidateNameAsPath(desc ocispec.Descriptor) error {
|
||||
// no empty name
|
||||
path, ok := orascontent.ResolveName(desc)
|
||||
if !ok || path == "" {
|
||||
return orascontent.ErrNoName
|
||||
}
|
||||
|
||||
// path should be clean
|
||||
if target := filepath.ToSlash(filepath.Clean(path)); target != path {
|
||||
return errors.Wrap(ErrDirtyPath, path)
|
||||
}
|
||||
|
||||
// path should be slash-separated
|
||||
if strings.Contains(path, "\\") {
|
||||
return errors.Wrap(ErrPathNotSlashSeparated, path)
|
||||
}
|
||||
|
||||
// disallow absolute path: covers unix and windows format
|
||||
if strings.HasPrefix(path, "/") {
|
||||
return errors.Wrap(ErrAbsolutePathDisallowed, path)
|
||||
}
|
||||
if len(path) > 2 {
|
||||
c := path[0]
|
||||
if path[1] == ':' && path[2] == '/' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
|
||||
return errors.Wrap(ErrAbsolutePathDisallowed, path)
|
||||
}
|
||||
}
|
||||
|
||||
// disallow path traversal
|
||||
if strings.HasPrefix(path, "../") || path == ".." {
|
||||
return errors.Wrap(ErrPathTraversalDisallowed, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// dispatchBFS behaves the same as images.Dispatch() but in sequence with breath-first search.
|
||||
func dispatchBFS(ctx context.Context, handler images.Handler, weighted *semaphore.Weighted, descs ...ocispec.Descriptor) error {
|
||||
for i := 0; i < len(descs); i++ {
|
||||
desc := descs[i]
|
||||
children, err := handler.Handle(ctx, desc)
|
||||
if err != nil {
|
||||
switch err := errors.Cause(err); err {
|
||||
case images.ErrSkipDesc:
|
||||
continue // don't traverse the children.
|
||||
case ErrStopProcessing:
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
descs = append(descs, children...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func filterName(desc ocispec.Descriptor) bool {
|
||||
// needs to be filled in
|
||||
return true
|
||||
}
|
||||
|
||||
// WithAdditionalCachedMediaTypes adds media types normally cached in memory when pulling.
|
||||
// This does not replace the default media types, but appends to them
|
||||
func WithAdditionalCachedMediaTypes(cachedMediaTypes ...string) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.cachedMediaTypes = append(o.cachedMediaTypes, cachedMediaTypes...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithAllowedMediaType sets the allowed media types
|
||||
func WithAllowedMediaType(allowedMediaTypes ...string) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.allowedMediaTypes = append(o.allowedMediaTypes, allowedMediaTypes...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithAllowedMediaTypes sets the allowed media types
|
||||
func WithAllowedMediaTypes(allowedMediaTypes []string) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.allowedMediaTypes = append(o.allowedMediaTypes, allowedMediaTypes...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPullByBFS opt to pull in sequence with breath-first search
|
||||
func WithPullByBFS(o *copyOpts) error {
|
||||
o.dispatch = dispatchBFS
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithPullBaseHandler provides base handlers, which will be called before
|
||||
// any pull specific handlers.
|
||||
func WithPullBaseHandler(handlers ...images.Handler) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.baseHandlers = append(o.baseHandlers, handlers...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPullCallbackHandler provides callback handlers, which will be called after
|
||||
// any pull specific handlers.
|
||||
func WithPullCallbackHandler(handlers ...images.Handler) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.callbackHandlers = append(o.callbackHandlers, handlers...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithContentProvideIngester opt to the provided Provider and Ingester
|
||||
// for file system I/O, including caches.
|
||||
func WithContentStore(store orascontent.Store) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.contentProvideIngesterPusherFetcher = store
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPullEmptyNameAllowed allows pulling blobs with empty name.
|
||||
func WithPullEmptyNameAllowed() CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.filterName = func(ocispec.Descriptor) bool {
|
||||
return true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPullStatusTrack report results to stdout
|
||||
func WithPullStatusTrack(writer io.Writer) CopyOpt {
|
||||
return WithPullCallbackHandler(pullStatusTrack(writer))
|
||||
}
|
||||
|
||||
func pullStatusTrack(writer io.Writer) images.Handler {
|
||||
var printLock sync.Mutex
|
||||
return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if name, ok := orascontent.ResolveName(desc); ok {
|
||||
digestString := desc.Digest.String()
|
||||
if err := desc.Digest.Validate(); err == nil {
|
||||
if algo := desc.Digest.Algorithm(); algo == digest.SHA256 {
|
||||
digestString = desc.Digest.Encoded()[:12]
|
||||
}
|
||||
}
|
||||
printLock.Lock()
|
||||
defer printLock.Unlock()
|
||||
fmt.Fprintln(writer, "Downloaded", digestString, name)
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithNameValidation validates the image title in the descriptor.
|
||||
// Pass nil to disable name validation.
|
||||
func WithNameValidation(validate func(desc ocispec.Descriptor) error) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.validateName = validate
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithUserAgent set the user agent string in http communications
|
||||
func WithUserAgent(agent string) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
o.userAgent = agent
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithLayerDescriptors passes the slice of Descriptors for layers to the
|
||||
// provided func. If the passed parameter is nil, returns an error.
|
||||
func WithLayerDescriptors(save func([]ocispec.Descriptor)) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
if save == nil {
|
||||
return errors.New("layers save func must be non-nil")
|
||||
}
|
||||
o.saveLayers = save
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRootManifest passes the root manifest for the artifacts to the provided
|
||||
// func. If the passed parameter is nil, returns an error.
|
||||
func WithRootManifest(save func(b []byte)) CopyOpt {
|
||||
return func(o *copyOpts) error {
|
||||
if save == nil {
|
||||
return errors.New("manifest save func must be non-nil")
|
||||
}
|
||||
o.saveManifest = save
|
||||
return nil
|
||||
}
|
||||
}
|
||||
79
vendor/oras.land/oras-go/pkg/oras/provider.go
vendored
Normal file
79
vendor/oras.land/oras-go/pkg/oras/provider.go
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright The ORAS 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 oras
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// ProviderWrapper wraps a remote.Fetcher to make a content.Provider, which is useful for things
|
||||
type ProviderWrapper struct {
|
||||
Fetcher remotes.Fetcher
|
||||
}
|
||||
|
||||
func (p *ProviderWrapper) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
|
||||
if p.Fetcher == nil {
|
||||
return nil, errors.New("no Fetcher provided")
|
||||
}
|
||||
return &fetcherReaderAt{
|
||||
ctx: ctx,
|
||||
fetcher: p.Fetcher,
|
||||
desc: desc,
|
||||
offset: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type fetcherReaderAt struct {
|
||||
ctx context.Context
|
||||
fetcher remotes.Fetcher
|
||||
desc ocispec.Descriptor
|
||||
rc io.ReadCloser
|
||||
offset int64
|
||||
}
|
||||
|
||||
func (f *fetcherReaderAt) Close() error {
|
||||
if f.rc == nil {
|
||||
return nil
|
||||
}
|
||||
return f.rc.Close()
|
||||
}
|
||||
|
||||
func (f *fetcherReaderAt) Size() int64 {
|
||||
return f.desc.Size
|
||||
}
|
||||
|
||||
func (f *fetcherReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
// if we do not have a readcloser, get it
|
||||
if f.rc == nil || f.offset != off {
|
||||
rc, err := f.fetcher.Fetch(f.ctx, f.desc)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f.rc = rc
|
||||
}
|
||||
|
||||
n, err = io.ReadFull(f.rc, p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
f.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
213
vendor/oras.land/oras-go/pkg/oras/store.go
vendored
Normal file
213
vendor/oras.land/oras-go/pkg/oras/store.go
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Copyright The ORAS 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 oras
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
orascontent "oras.land/oras-go/pkg/content"
|
||||
)
|
||||
|
||||
type hybridStore struct {
|
||||
cache *orascontent.Memory
|
||||
cachedMediaTypes []string
|
||||
cacheOnly bool
|
||||
provider content.Provider
|
||||
ingester content.Ingester
|
||||
}
|
||||
|
||||
func newHybridStoreFromPusher(pusher remotes.Pusher, cachedMediaTypes []string, cacheOnly bool) *hybridStore {
|
||||
// construct an ingester from a pusher
|
||||
ingester := pusherIngester{
|
||||
pusher: pusher,
|
||||
}
|
||||
return &hybridStore{
|
||||
cache: orascontent.NewMemory(),
|
||||
cachedMediaTypes: cachedMediaTypes,
|
||||
ingester: ingester,
|
||||
cacheOnly: cacheOnly,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *hybridStore) Set(desc ocispec.Descriptor, content []byte) {
|
||||
s.cache.Set(desc, content)
|
||||
}
|
||||
|
||||
func (s *hybridStore) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) {
|
||||
reader, err := s.cache.Fetch(ctx, desc)
|
||||
if err == nil {
|
||||
return reader, err
|
||||
}
|
||||
if s.provider != nil {
|
||||
rat, err := s.provider.ReaderAt(ctx, desc)
|
||||
return ioutil.NopCloser(orascontent.NewReaderAtWrapper(rat)), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *hybridStore) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) {
|
||||
return s.Writer(ctx, content.WithDescriptor(desc))
|
||||
}
|
||||
|
||||
// Writer begins or resumes the active writer identified by desc
|
||||
func (s *hybridStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
|
||||
var wOpts content.WriterOpts
|
||||
for _, opt := range opts {
|
||||
if err := opt(&wOpts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if isAllowedMediaType(wOpts.Desc.MediaType, s.cachedMediaTypes...) || s.ingester == nil {
|
||||
pusher, err := s.cache.Pusher(ctx, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheWriter, err := pusher.Push(ctx, wOpts.Desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// if we cache it only, do not pass it through
|
||||
if s.cacheOnly {
|
||||
return cacheWriter, nil
|
||||
}
|
||||
ingesterWriter, err := s.ingester.Writer(ctx, opts...)
|
||||
switch {
|
||||
case err == nil:
|
||||
return newTeeWriter(wOpts.Desc, cacheWriter, ingesterWriter), nil
|
||||
case errdefs.IsAlreadyExists(err):
|
||||
return cacheWriter, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return s.ingester.Writer(ctx, opts...)
|
||||
}
|
||||
|
||||
// teeWriter tees the content to one or more content.Writer
|
||||
type teeWriter struct {
|
||||
writers []content.Writer
|
||||
digester digest.Digester
|
||||
status content.Status
|
||||
}
|
||||
|
||||
func newTeeWriter(desc ocispec.Descriptor, writers ...content.Writer) *teeWriter {
|
||||
now := time.Now()
|
||||
return &teeWriter{
|
||||
writers: writers,
|
||||
digester: digest.Canonical.Digester(),
|
||||
status: content.Status{
|
||||
Total: desc.Size,
|
||||
StartedAt: now,
|
||||
UpdatedAt: now,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *teeWriter) Close() error {
|
||||
g := new(errgroup.Group)
|
||||
for _, w := range t.writers {
|
||||
w := w // closure issues, see https://golang.org/doc/faq#closures_and_goroutines
|
||||
g.Go(func() error {
|
||||
return w.Close()
|
||||
})
|
||||
}
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
func (t *teeWriter) Write(p []byte) (n int, err error) {
|
||||
g := new(errgroup.Group)
|
||||
for _, w := range t.writers {
|
||||
w := w // closure issues, see https://golang.org/doc/faq#closures_and_goroutines
|
||||
g.Go(func() error {
|
||||
n, err := w.Write(p[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(p) {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
err = g.Wait()
|
||||
n = len(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
_, _ = t.digester.Hash().Write(p[:n])
|
||||
t.status.Offset += int64(len(p))
|
||||
t.status.UpdatedAt = time.Now()
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Digest may return empty digest or panics until committed.
|
||||
func (t *teeWriter) Digest() digest.Digest {
|
||||
return t.digester.Digest()
|
||||
}
|
||||
|
||||
func (t *teeWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
|
||||
g := new(errgroup.Group)
|
||||
for _, w := range t.writers {
|
||||
w := w // closure issues, see https://golang.org/doc/faq#closures_and_goroutines
|
||||
g.Go(func() error {
|
||||
return w.Commit(ctx, size, expected, opts...)
|
||||
})
|
||||
}
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
// Status returns the current state of write
|
||||
func (t *teeWriter) Status() (content.Status, error) {
|
||||
return t.status, nil
|
||||
}
|
||||
|
||||
// Truncate updates the size of the target blob
|
||||
func (t *teeWriter) Truncate(size int64) error {
|
||||
g := new(errgroup.Group)
|
||||
for _, w := range t.writers {
|
||||
w := w // closure issues, see https://golang.org/doc/faq#closures_and_goroutines
|
||||
g.Go(func() error {
|
||||
return w.Truncate(size)
|
||||
})
|
||||
}
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
// pusherIngester simple wrapper to get an ingester from a pusher
|
||||
type pusherIngester struct {
|
||||
pusher remotes.Pusher
|
||||
}
|
||||
|
||||
func (p pusherIngester) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
|
||||
var wOpts content.WriterOpts
|
||||
for _, opt := range opts {
|
||||
if err := opt(&wOpts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return p.pusher.Push(ctx, wOpts.Desc)
|
||||
}
|
||||
Reference in New Issue
Block a user