cuelabs.dev/go/oci/ociregistry@v0.0.0-20240906074133-82eb438dd565/ociunify/reader.go (about) 1 // Copyright 2023 CUE Labs AG 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 ociunify 16 17 import ( 18 "context" 19 "fmt" 20 21 "cuelabs.dev/go/oci/ociregistry" 22 ) 23 24 // Reader methods. 25 26 func (u unifier) GetBlob(ctx context.Context, repo string, digest ociregistry.Digest) (ociregistry.BlobReader, error) { 27 return runReadBlobReader(ctx, u, func(ctx context.Context, r ociregistry.Interface, i int) t2[ociregistry.BlobReader] { 28 return mk2(r.GetBlob(ctx, repo, digest)) 29 }) 30 } 31 32 func (u unifier) GetBlobRange(ctx context.Context, repo string, digest ociregistry.Digest, o0, o1 int64) (ociregistry.BlobReader, error) { 33 return runReadBlobReader(ctx, u, 34 func(ctx context.Context, r ociregistry.Interface, i int) t2[ociregistry.BlobReader] { 35 return mk2(r.GetBlobRange(ctx, repo, digest, o0, o1)) 36 }, 37 ) 38 } 39 40 func (u unifier) GetManifest(ctx context.Context, repo string, digest ociregistry.Digest) (ociregistry.BlobReader, error) { 41 return runReadBlobReader(ctx, u, 42 func(ctx context.Context, r ociregistry.Interface, i int) t2[ociregistry.BlobReader] { 43 return mk2(r.GetManifest(ctx, repo, digest)) 44 }, 45 ) 46 } 47 48 type blobReader struct { 49 ociregistry.BlobReader 50 cancel func() 51 } 52 53 func (r blobReader) Close() error { 54 defer r.cancel() 55 return r.BlobReader.Close() 56 } 57 58 func (u unifier) GetTag(ctx context.Context, repo string, tagName string) (ociregistry.BlobReader, error) { 59 r0, r1 := both(u, func(r ociregistry.Interface, _ int) t2[ociregistry.BlobReader] { 60 return mk2(r.GetTag(ctx, repo, tagName)) 61 }) 62 switch { 63 case r0.err == nil && r1.err == nil: 64 if r0.x.Descriptor().Digest == r1.x.Descriptor().Digest { 65 r1.x.Close() 66 return r0.get() 67 } 68 r0.close() 69 r1.close() 70 return nil, fmt.Errorf("conflicting results for tag") 71 case r0.err != nil && r1.err != nil: 72 return r0.get() 73 case r0.err == nil: 74 return r0.get() 75 case r1.err == nil: 76 return r1.get() 77 } 78 panic("unreachable") 79 } 80 81 func (u unifier) ResolveBlob(ctx context.Context, repo string, digest ociregistry.Digest) (ociregistry.Descriptor, error) { 82 return runRead(ctx, u, func(ctx context.Context, r ociregistry.Interface, _ int) t2[ociregistry.Descriptor] { 83 return mk2(r.ResolveBlob(ctx, repo, digest)) 84 }).get() 85 } 86 87 func (u unifier) ResolveManifest(ctx context.Context, repo string, digest ociregistry.Digest) (ociregistry.Descriptor, error) { 88 return runRead(ctx, u, func(ctx context.Context, r ociregistry.Interface, _ int) t2[ociregistry.Descriptor] { 89 return mk2(r.ResolveManifest(ctx, repo, digest)) 90 }).get() 91 } 92 93 func (u unifier) ResolveTag(ctx context.Context, repo string, tagName string) (ociregistry.Descriptor, error) { 94 r0, r1 := both(u, func(r ociregistry.Interface, _ int) t2[ociregistry.Descriptor] { 95 return mk2(r.ResolveTag(ctx, repo, tagName)) 96 }) 97 switch { 98 case r0.err == nil && r1.err == nil: 99 if r0.x.Digest == r1.x.Digest { 100 return r0.get() 101 } 102 return ociregistry.Descriptor{}, fmt.Errorf("conflicting results for tag") 103 case r0.err != nil && r1.err != nil: 104 return r0.get() 105 case r0.err == nil: 106 return r0.get() 107 case r1.err == nil: 108 return r1.get() 109 } 110 panic("unreachable") 111 } 112 113 func runReadBlobReader(ctx context.Context, u unifier, f func(ctx context.Context, r ociregistry.Interface, i int) t2[ociregistry.BlobReader]) (ociregistry.BlobReader, error) { 114 rv, cancel := runReadWithCancel(ctx, u, f) 115 r, err := rv.get() 116 if err != nil { 117 cancel() 118 return nil, err 119 } 120 return blobReader{ 121 BlobReader: r, 122 cancel: cancel, 123 }, nil 124 }