sigs.k8s.io/kubebuilder/v3@v3.14.0/pkg/plugin/bundle.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package plugin 18 19 import ( 20 "fmt" 21 22 "sigs.k8s.io/kubebuilder/v3/pkg/config" 23 ) 24 25 type bundle struct { 26 name string 27 version Version 28 plugins []Plugin 29 30 supportedProjectVersions []config.Version 31 deprecateWarning string 32 } 33 34 type BundleOption func(*bundle) 35 36 func WithName(name string) BundleOption { 37 return func(opts *bundle) { 38 opts.name = name 39 } 40 } 41 42 func WithVersion(version Version) BundleOption { 43 return func(opts *bundle) { 44 opts.version = version 45 } 46 } 47 48 func WithPlugins(plugins ...Plugin) BundleOption { 49 return func(opts *bundle) { 50 opts.plugins = plugins 51 } 52 } 53 54 func WithDeprecationMessage(msg string) BundleOption { 55 return func(opts *bundle) { 56 opts.deprecateWarning = msg 57 } 58 59 } 60 61 // NewBundle creates a new Bundle with the provided name and version, and that wraps the provided plugins. 62 // The list of supported project versions is computed from the provided plugins. 63 // 64 // Deprecated: Use the NewBundle informing the options from now one. Replace its use for as the 65 // following example. Example: 66 // 67 // mylanguagev1Bundle, _ := plugin.NewBundle(plugin.WithName(language.DefaultNameQualifier), 68 // plugin.WithVersion(plugin.Version{Number: 1}), 69 // plugin.WithPlugins(kustomizecommonv1.Plugin{}, mylanguagev1.Plugin{}), 70 func NewBundle(name string, version Version, deprecateWarning string, plugins ...Plugin) (Bundle, error) { 71 supportedProjectVersions := CommonSupportedProjectVersions(plugins...) 72 if len(supportedProjectVersions) == 0 { 73 return nil, fmt.Errorf("in order to bundle plugins, they must all support at least one common project version") 74 } 75 76 // Plugins may be bundles themselves, so unbundle here 77 // NOTE(Adirio): unbundling here ensures that Bundle.Plugin always returns a flat list of Plugins instead of also 78 // including Bundles, and therefore we don't have to use a recursive algorithm when resolving. 79 allPlugins := make([]Plugin, 0, len(plugins)) 80 for _, plugin := range plugins { 81 if pluginBundle, isBundle := plugin.(Bundle); isBundle { 82 allPlugins = append(allPlugins, pluginBundle.Plugins()...) 83 } else { 84 allPlugins = append(allPlugins, plugin) 85 } 86 } 87 88 return bundle{ 89 name: name, 90 version: version, 91 plugins: allPlugins, 92 supportedProjectVersions: supportedProjectVersions, 93 deprecateWarning: deprecateWarning, 94 }, nil 95 } 96 97 // NewBundleWithOptions creates a new Bundle with the provided BundleOptions. 98 // The list of supported project versions is computed from the provided plugins in options. 99 func NewBundleWithOptions(opts ...BundleOption) (Bundle, error) { 100 bundleOpts := bundle{} 101 102 for _, opts := range opts { 103 opts(&bundleOpts) 104 } 105 106 supportedProjectVersions := CommonSupportedProjectVersions(bundleOpts.plugins...) 107 if len(supportedProjectVersions) == 0 { 108 return nil, fmt.Errorf("in order to bundle plugins, they must all support at least one common project version") 109 } 110 111 // Plugins may be bundles themselves, so unbundle here 112 // NOTE(Adirio): unbundling here ensures that Bundle.Plugin always returns a flat list of Plugins instead of also 113 // including Bundles, and therefore we don't have to use a recursive algorithm when resolving. 114 allPlugins := make([]Plugin, 0, len(bundleOpts.plugins)) 115 for _, plugin := range bundleOpts.plugins { 116 if pluginBundle, isBundle := plugin.(Bundle); isBundle { 117 allPlugins = append(allPlugins, pluginBundle.Plugins()...) 118 } else { 119 allPlugins = append(allPlugins, plugin) 120 } 121 } 122 123 return bundle{ 124 name: bundleOpts.name, 125 version: bundleOpts.version, 126 plugins: allPlugins, 127 supportedProjectVersions: supportedProjectVersions, 128 deprecateWarning: bundleOpts.deprecateWarning, 129 }, nil 130 } 131 132 // Name implements Plugin 133 func (b bundle) Name() string { 134 return b.name 135 } 136 137 // Version implements Plugin 138 func (b bundle) Version() Version { 139 return b.version 140 } 141 142 // SupportedProjectVersions implements Plugin 143 func (b bundle) SupportedProjectVersions() []config.Version { 144 return b.supportedProjectVersions 145 } 146 147 // Plugins implements Bundle 148 func (b bundle) Plugins() []Plugin { 149 return b.plugins 150 } 151 152 // Plugins implements Bundle 153 func (b bundle) DeprecationWarning() string { 154 return b.deprecateWarning 155 }