@@ -12,6 +12,7 @@ import (
1212 "sort"
1313 "strings"
1414 "sync"
15+ "text/template"
1516
1617 "github.com/h2non/filetype"
1718 "github.com/h2non/filetype/matchers"
@@ -39,6 +40,7 @@ const (
3940 RefSqliteFile
4041 RefDCImage
4142 RefDCDir
43+ RefBundleDir
4244
4345 RefAll = 0
4446)
@@ -50,10 +52,11 @@ func (r RefType) Allowed(refType RefType) bool {
5052var ErrNotAllowed = errors .New ("not allowed" )
5153
5254type Render struct {
53- Refs []string
54- Registry image.Registry
55- AllowedRefMask RefType
56- Migrate bool
55+ Refs []string
56+ Registry image.Registry
57+ AllowedRefMask RefType
58+ Migrate bool
59+ ImageRefTemplate * template.Template
5760
5861 skipSqliteDeprecationLog bool
5962}
@@ -125,25 +128,44 @@ func (r Render) createRegistry() (*containerdregistry.Registry, error) {
125128}
126129
127130func (r Render ) renderReference (ctx context.Context , ref string ) (* declcfg.DeclarativeConfig , error ) {
128- if stat , serr := os .Stat (ref ); serr == nil {
129- if stat .IsDir () {
130- if ! r .AllowedRefMask .Allowed (RefDCDir ) {
131- return nil , fmt .Errorf ("cannot render declarative config directory: %w" , ErrNotAllowed )
132- }
133- return declcfg .LoadFS (ctx , os .DirFS (ref ))
134- } else {
135- // The only supported file type is an sqlite DB file,
136- // since declarative configs will be in a directory.
137- if err := checkDBFile (ref ); err != nil {
138- return nil , err
139- }
140- if ! r .AllowedRefMask .Allowed (RefSqliteFile ) {
141- return nil , fmt .Errorf ("cannot render sqlite file: %w" , ErrNotAllowed )
131+ stat , err := os .Stat (ref )
132+ if err != nil {
133+ return r .imageToDeclcfg (ctx , ref )
134+ }
135+ if stat .IsDir () {
136+ dirEntries , err := os .ReadDir (ref )
137+ if err != nil {
138+ return nil , err
139+ }
140+ if isBundle (dirEntries ) {
141+ // Looks like a bundle directory
142+ if ! r .AllowedRefMask .Allowed (RefBundleDir ) {
143+ return nil , fmt .Errorf ("cannot render bundle directory %q: %w" , ref , ErrNotAllowed )
142144 }
143- return sqliteToDeclcfg ( ctx , ref )
145+ return r . renderBundleDirectory ( ref )
144146 }
147+
148+ // Otherwise, assume it is a declarative config root directory.
149+ if ! r .AllowedRefMask .Allowed (RefDCDir ) {
150+ return nil , fmt .Errorf ("cannot render declarative config directory: %w" , ErrNotAllowed )
151+ }
152+ return declcfg .LoadFS (ctx , os .DirFS (ref ))
153+ }
154+ // The only supported file type is an sqlite DB file,
155+ // since declarative configs will be in a directory.
156+ if err := checkDBFile (ref ); err != nil {
157+ return nil , err
158+ }
159+ if ! r .AllowedRefMask .Allowed (RefSqliteFile ) {
160+ return nil , fmt .Errorf ("cannot render sqlite file: %w" , ErrNotAllowed )
161+ }
162+
163+ db , err := sqlite .Open (ref )
164+ if err != nil {
165+ return nil , err
145166 }
146- return r .imageToDeclcfg (ctx , ref )
167+ defer db .Close ()
168+ return sqliteToDeclcfg (ctx , db )
147169}
148170
149171func (r Render ) imageToDeclcfg (ctx context.Context , imageRef string ) (* declcfg.DeclarativeConfig , error ) {
@@ -169,7 +191,12 @@ func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.D
169191 if ! r .AllowedRefMask .Allowed (RefSqliteImage ) {
170192 return nil , fmt .Errorf ("cannot render sqlite image: %w" , ErrNotAllowed )
171193 }
172- cfg , err = sqliteToDeclcfg (ctx , filepath .Join (tmpDir , dbFile ))
194+ db , err := sqlite .Open (filepath .Join (tmpDir , dbFile ))
195+ if err != nil {
196+ return nil , err
197+ }
198+ defer db .Close ()
199+ cfg , err = sqliteToDeclcfg (ctx , db )
173200 if err != nil {
174201 return nil , err
175202 }
@@ -190,10 +217,11 @@ func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.D
190217 return nil , err
191218 }
192219
193- cfg , err = bundleToDeclcfg (img .Bundle )
220+ bundle , err : = bundleToDeclcfg (img .Bundle )
194221 if err != nil {
195222 return nil , err
196223 }
224+ cfg = & declcfg.DeclarativeConfig {Bundles : []declcfg.Bundle {* bundle }}
197225 } else {
198226 labelKeys := sets .StringKeySet (labels )
199227 labelVals := []string {}
@@ -221,17 +249,11 @@ func checkDBFile(ref string) error {
221249 return nil
222250}
223251
224- func sqliteToDeclcfg (ctx context.Context , dbFile string ) (* declcfg.DeclarativeConfig , error ) {
252+ func sqliteToDeclcfg (ctx context.Context , db * sql. DB ) (* declcfg.DeclarativeConfig , error ) {
225253 logDeprecationMessage .Do (func () {
226254 sqlite .LogSqliteDeprecation ()
227255 })
228256
229- db , err := sqlite .Open (dbFile )
230- if err != nil {
231- return nil , err
232- }
233- defer db .Close ()
234-
235257 migrator , err := sqlite .NewSQLLiteMigrator (db )
236258 if err != nil {
237259 return nil , err
@@ -303,7 +325,7 @@ func populateDBRelatedImages(ctx context.Context, cfg *declcfg.DeclarativeConfig
303325 return nil
304326}
305327
306- func bundleToDeclcfg (bundle * registry.Bundle ) (* declcfg.DeclarativeConfig , error ) {
328+ func bundleToDeclcfg (bundle * registry.Bundle ) (* declcfg.Bundle , error ) {
307329 objs , props , err := registry .ObjectsAndPropertiesFromBundle (bundle )
308330 if err != nil {
309331 return nil , fmt .Errorf ("get properties for bundle %q: %v" , bundle .Name , err )
@@ -323,7 +345,7 @@ func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.DeclarativeConfig, error
323345 }
324346 }
325347
326- dBundle := declcfg.Bundle {
348+ return & declcfg.Bundle {
327349 Schema : "olm.bundle" ,
328350 Name : bundle .Name ,
329351 Package : bundle .Package ,
@@ -332,9 +354,7 @@ func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.DeclarativeConfig, error
332354 RelatedImages : relatedImages ,
333355 Objects : objs ,
334356 CsvJSON : string (csvJson ),
335- }
336-
337- return & declcfg.DeclarativeConfig {Bundles : []declcfg.Bundle {dBundle }}, nil
357+ }, nil
338358}
339359
340360func getRelatedImages (b * registry.Bundle ) ([]declcfg.RelatedImage , error ) {
@@ -363,7 +383,7 @@ func getRelatedImages(b *registry.Bundle) ([]declcfg.RelatedImage, error) {
363383 allImages = allImages .Insert (ri .Image )
364384 }
365385
366- if ! allImages .Has (b .BundleImage ) {
386+ if b . BundleImage != "" && ! allImages .Has (b .BundleImage ) {
367387 relatedImages = append (relatedImages , declcfg.RelatedImage {
368388 Image : b .BundleImage ,
369389 })
@@ -454,3 +474,72 @@ func combineConfigs(cfgs []declcfg.DeclarativeConfig) *declcfg.DeclarativeConfig
454474 }
455475 return out
456476}
477+
478+ func isBundle (entries []os.DirEntry ) bool {
479+ foundManifests := false
480+ foundMetadata := false
481+ for _ , e := range entries {
482+ if e .IsDir () {
483+ switch e .Name () {
484+ case "manifests" :
485+ foundManifests = true
486+ case "metadata" :
487+ foundMetadata = true
488+ }
489+ }
490+ if foundMetadata && foundManifests {
491+ return true
492+ }
493+ }
494+ return false
495+ }
496+
497+ type imageReferenceTemplateData struct {
498+ Package string
499+ Name string
500+ Version string
501+ }
502+
503+ func (r * Render ) renderBundleDirectory (ref string ) (* declcfg.DeclarativeConfig , error ) {
504+ img , err := registry .NewImageInput (image .SimpleReference ("" ), ref )
505+ if err != nil {
506+ return nil , err
507+ }
508+ if err := r .templateBundleImageRef (img .Bundle ); err != nil {
509+ return nil , fmt .Errorf ("failed templating image reference from bundle for %q: %v" , ref , err )
510+ }
511+ fbcBundle , err := bundleToDeclcfg (img .Bundle )
512+ if err != nil {
513+ return nil , err
514+ }
515+ return & declcfg.DeclarativeConfig {Bundles : []declcfg.Bundle {* fbcBundle }}, nil
516+ }
517+
518+ func (r * Render ) templateBundleImageRef (bundle * registry.Bundle ) error {
519+ if r .ImageRefTemplate == nil {
520+ return nil
521+ }
522+
523+ var pkgProp property.Package
524+ for _ , p := range bundle .Properties {
525+ if p .Type != property .TypePackage {
526+ continue
527+ }
528+ if err := json .Unmarshal (p .Value , & pkgProp ); err != nil {
529+ return err
530+ }
531+ break
532+ }
533+
534+ var buf strings.Builder
535+ tmplInput := imageReferenceTemplateData {
536+ Package : bundle .Package ,
537+ Name : bundle .Name ,
538+ Version : pkgProp .Version ,
539+ }
540+ if err := r .ImageRefTemplate .Execute (& buf , tmplInput ); err != nil {
541+ return err
542+ }
543+ bundle .BundleImage = buf .String ()
544+ return nil
545+ }
0 commit comments