@@ -6,15 +6,17 @@ import (
6
6
"errors"
7
7
"fmt"
8
8
"hash/fnv"
9
+ "io"
9
10
"io/fs"
10
11
"os"
11
12
"path/filepath"
13
+ "sort"
12
14
"strings"
13
15
14
16
"github.com/operator-framework/operator-registry/alpha/declcfg"
15
17
"github.com/operator-framework/operator-registry/pkg/api"
16
18
"github.com/operator-framework/operator-registry/pkg/registry"
17
- "k8s.io/apimachinery/pkg/util/sets "
19
+ "github.com/sirupsen/logrus "
18
20
)
19
21
20
22
var _ Cache = & JSON {}
@@ -58,31 +60,66 @@ func (q *JSON) ListBundles(ctx context.Context) ([]*api.Bundle, error) {
58
60
}
59
61
60
62
func (q * JSON ) SendBundles (_ context.Context , s registry.BundleSender ) error {
63
+ var keys []apiBundleKey
61
64
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" )
84
98
}
85
99
}
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
86
123
}
87
124
return nil
88
125
}
0 commit comments