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  }