@@ -6,15 +6,17 @@ import (
66 "errors"
77 "fmt"
88 "hash/fnv"
9+ "io"
910 "io/fs"
1011 "os"
1112 "path/filepath"
13+ "sort"
1214 "strings"
1315
1416 "github.com/operator-framework/operator-registry/alpha/declcfg"
1517 "github.com/operator-framework/operator-registry/pkg/api"
1618 "github.com/operator-framework/operator-registry/pkg/registry"
17- "k8s.io/apimachinery/pkg/util/sets "
19+ "github.com/sirupsen/logrus "
1820)
1921
2022var _ Cache = & JSON {}
@@ -58,31 +60,66 @@ func (q *JSON) ListBundles(ctx context.Context) ([]*api.Bundle, error) {
5860}
5961
6062func (q * JSON ) SendBundles (_ context.Context , s registry.BundleSender ) error {
63+ var keys []apiBundleKey
6164 for _ , pkg := range q .packageIndex {
62- channels := sets .KeySet (pkg .Channels )
63- for _ , chName := range sets .List (channels ) {
64- ch := pkg .Channels [chName ]
65-
66- bundles := sets .KeySet (ch .Bundles )
67- for _ , bName := range sets .List (bundles ) {
68- b := ch .Bundles [bName ]
69- apiBundle , err := q .loadAPIBundle (apiBundleKey {pkg .Name , ch .Name , b .Name })
70- if err != nil {
71- return fmt .Errorf ("convert bundle %q: %v" , b .Name , err )
72- }
73- if apiBundle .BundlePath != "" {
74- // The SQLite-based server
75- // configures its querier to
76- // omit these fields when
77- // bundle path is set.
78- apiBundle .CsvJson = ""
79- apiBundle .Object = nil
80- }
81- if err := s .Send (apiBundle ); err != nil {
82- return err
83- }
65+ for _ , ch := range pkg .Channels {
66+ for _ , b := range ch .Bundles {
67+ keys = append (keys , apiBundleKey {pkg .Name , ch .Name , b .Name })
68+ }
69+ }
70+ }
71+ sort .Slice (keys , func (i , j int ) bool {
72+ if keys [i ].chName != keys [j ].chName {
73+ return keys [i ].chName < keys [j ].chName
74+ }
75+ if keys [i ].pkgName != keys [j ].pkgName {
76+ return keys [i ].pkgName < keys [j ].pkgName
77+ }
78+ return keys [i ].name < keys [j ].name
79+ })
80+ var files []* os.File
81+ var readers []io.Reader
82+ for _ , key := range keys {
83+ filename , ok := q .apiBundles [key ]
84+ if ! ok {
85+ return fmt .Errorf ("package %q, channel %q, key %q not found" , key .pkgName , key .chName , key .name )
86+ }
87+ file , err := os .Open (filename )
88+ if err != nil {
89+ return fmt .Errorf ("failed to open file for package %q, channel %q, key %q: %w" , key .pkgName , key .chName , key .name , err )
90+ }
91+ files = append (files , file )
92+ readers = append (readers , file )
93+ }
94+ defer func () {
95+ for _ , file := range files {
96+ if err := file .Close (); err != nil {
97+ logrus .WithError (err ).WithField ("file" , file .Name ()).Warn ("could not close file" )
8498 }
8599 }
100+ }()
101+ multiReader := io .MultiReader (readers ... )
102+ decoder := json .NewDecoder (multiReader )
103+ index := 0
104+ for {
105+ var bundle api.Bundle
106+ if err := decoder .Decode (& bundle ); err == io .EOF {
107+ break
108+ } else if err != nil {
109+ return fmt .Errorf ("failed to decode file for package %q, channel %q, key %q: %w" , keys [index ].pkgName , keys [index ].chName , keys [index ].name , err )
110+ }
111+ if bundle .BundlePath != "" {
112+ // The SQLite-based server
113+ // configures its querier to
114+ // omit these fields when
115+ // key path is set.
116+ bundle .CsvJson = ""
117+ bundle .Object = nil
118+ }
119+ if err := s .Send (& bundle ); err != nil {
120+ return err
121+ }
122+ index += 1
86123 }
87124 return nil
88125}
0 commit comments