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  }