Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement the plugin chaining (plugin phase 1.5)
Signed-off-by: Adrian Orive <[email protected]>
  • Loading branch information
Adirio committed Mar 2, 2021
commit bc9576cd3528e168a3e1a0b6bc742317b8609f73
81 changes: 31 additions & 50 deletions pkg/cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,77 +14,58 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package cli // nolint:dupl
package cli //nolint:dupl

import (
"fmt"

"github.com/spf13/cobra"

yamlstore "sigs.k8s.io/kubebuilder/v3/pkg/config/store/yaml"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)

const apiErrorMsg = "failed to create API"

func (c cli) newCreateAPICmd() *cobra.Command {
ctx := c.newAPIContext()
cmd := &cobra.Command{
Use: "api",
Short: "Scaffold a Kubernetes API",
Long: ctx.Description,
Example: ctx.Examples,
Use: "api",
Short: "Scaffold a Kubernetes API",
Long: `Scaffold a Kubernetes API.
`,
RunE: errCmdFunc(
fmt.Errorf("api subcommand requires an existing project"),
),
}

// Lookup the plugin for projectVersion and bind it to the command.
c.bindCreateAPI(ctx, cmd)
return cmd
}

func (c cli) newAPIContext() plugin.Context {
return plugin.Context{
CommandName: c.commandName,
Description: `Scaffold a Kubernetes API.
`,
}
}

// nolint:dupl
func (c cli) bindCreateAPI(ctx plugin.Context, cmd *cobra.Command) {
// In case no plugin was resolved, instead of failing the construction of the CLI, fail the execution of
// this subcommand. This allows the use of subcommands that do not require resolved plugins like help.
if len(c.resolvedPlugins) == 0 {
cmdErr(cmd, fmt.Errorf(noPluginError))
return
cmdErr(cmd, noResolvedPluginError{})
return cmd
}

var createAPIPlugin plugin.CreateAPI
for _, p := range c.resolvedPlugins {
tmpPlugin, isValid := p.(plugin.CreateAPI)
if isValid {
if createAPIPlugin != nil {
err := fmt.Errorf("duplicate API creation plugins (%s, %s), use a more specific plugin key",
plugin.KeyFor(createAPIPlugin), plugin.KeyFor(p))
cmdErr(cmd, err)
return
}
createAPIPlugin = tmpPlugin
}
}
// Obtain the plugin keys and subcommands from the plugins that implement plugin.CreateAPI.
pluginKeys, subcommands := c.filterSubcommands(
func(p plugin.Plugin) bool {
_, isValid := p.(plugin.CreateAPI)
return isValid
},
func(p plugin.Plugin) plugin.Subcommand {
return p.(plugin.CreateAPI).GetCreateAPISubcommand()
},
)

if createAPIPlugin == nil {
cmdErr(cmd, fmt.Errorf("resolved plugins do not provide an API creation plugin: %v", c.pluginKeys))
return
// Verify that there is at least one remaining plugin.
if len(*subcommands) == 0 {
cmdErr(cmd, noAvailablePluginError{"API creation"})
return cmd
}

subcommand := createAPIPlugin.GetCreateAPISubcommand()
subcommand.BindFlags(cmd.Flags())
subcommand.UpdateContext(&ctx)
cmd.Long = ctx.Description
cmd.Example = ctx.Examples
// Initialization methods.
options := c.initializationMethods(cmd, subcommands)

// Execution methods.
cmd.PreRunE, cmd.RunE, cmd.PostRunE = c.executionMethodsFuncs(pluginKeys, subcommands, options, apiErrorMsg)

cfg := yamlstore.New(c.fs)
msg := fmt.Sprintf("failed to create API with %q", plugin.KeyFor(createAPIPlugin))
cmd.PreRunE = preRunECmdFunc(subcommand, cfg, msg)
cmd.RunE = runECmdFunc(c.fs, subcommand, msg)
cmd.PostRunE = postRunECmdFunc(cfg, msg)
return cmd
}
9 changes: 7 additions & 2 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ const (

projectVersionFlag = "project-version"
pluginsFlag = "plugins"

noPluginError = "invalid config file please verify that the version and layout fields are set and valid"
)

// equalStringSlice checks if two string slices are equal.
Expand Down Expand Up @@ -480,6 +478,13 @@ func (c cli) printDeprecationWarnings() {
}
}

// metadata returns CLI's metadata.
func (c cli) metadata() plugin.CLIMetadata {
return plugin.CLIMetadata{
CommandName: c.commandName,
}
}

// Run implements CLI.Run.
func (c cli) Run() error {
return c.cmd.Execute()
Expand Down
Loading