cuelabs.dev/go/oci/ociregistry@v0.0.0-20240906074133-82eb438dd565/ociunify/lister.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 "errors" 20 "slices" 21 "strings" 22 23 "cuelabs.dev/go/oci/ociregistry" 24 ) 25 26 func (u unifier) Repositories(ctx context.Context, startAfter string) ociregistry.Seq[string] { 27 r0, r1 := both(u, func(r ociregistry.Interface, _ int) ociregistry.Seq[string] { 28 return r.Repositories(ctx, startAfter) 29 }) 30 return mergeIter(r0, r1, strings.Compare) 31 } 32 33 func (u unifier) Tags(ctx context.Context, repo, startAfter string) ociregistry.Seq[string] { 34 r0, r1 := both(u, func(r ociregistry.Interface, _ int) ociregistry.Seq[string] { 35 return r.Tags(ctx, repo, startAfter) 36 }) 37 return mergeIter(r0, r1, strings.Compare) 38 } 39 40 func (u unifier) Referrers(ctx context.Context, repo string, digest ociregistry.Digest, artifactType string) ociregistry.Seq[ociregistry.Descriptor] { 41 r0, r1 := both(u, func(r ociregistry.Interface, _ int) ociregistry.Seq[ociregistry.Descriptor] { 42 return r.Referrers(ctx, repo, digest, artifactType) 43 }) 44 return mergeIter(r0, r1, compareDescriptor) 45 } 46 47 func compareDescriptor(d0, d1 ociregistry.Descriptor) int { 48 return strings.Compare(string(d0.Digest), string(d1.Digest)) 49 } 50 51 func mergeIter[T any](it0, it1 ociregistry.Seq[T], cmp func(T, T) int) ociregistry.Seq[T] { 52 // TODO streaming merge sort 53 xs0, err0 := ociregistry.All(it0) 54 xs1, err1 := ociregistry.All(it1) 55 if err0 != nil || err1 != nil { 56 notFound0 := errors.Is(err0, ociregistry.ErrNameUnknown) 57 notFound1 := errors.Is(err1, ociregistry.ErrNameUnknown) 58 if notFound0 && notFound1 { 59 return ociregistry.ErrorSeq[T](err0) 60 } 61 if notFound0 { 62 err0 = nil 63 } 64 if notFound1 { 65 err1 = nil 66 } 67 } 68 var xs []T 69 if len(xs0)+len(xs1) > 0 { 70 xs = slices.Concat(xs0, xs1) 71 slices.SortFunc(xs, cmp) 72 xs = slices.CompactFunc(xs, func(t1, t2 T) bool { 73 return cmp(t1, t2) == 0 74 }) 75 } 76 err := err0 77 if err == nil { 78 err = err1 79 } 80 if err == nil { 81 return ociregistry.SliceSeq(xs) 82 } 83 return func(yield func(T, error) bool) { 84 for _, x := range xs { 85 if !yield(x, nil) { 86 return 87 } 88 } 89 yield(*new(T), err) 90 } 91 }