sigs.k8s.io/kubebuilder/v3@v3.14.0/pkg/cli/root.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 cli 18 19 import ( 20 "fmt" 21 "sort" 22 "strings" 23 24 "github.com/spf13/cobra" 25 ) 26 27 const ( 28 pluginKeysHeader = "Plugin keys" 29 projectVersionsHeader = "Supported project versions" 30 ) 31 32 var ( 33 supportedPlatforms = []string{"darwin", "linux"} 34 ) 35 36 func (c CLI) newRootCmd() *cobra.Command { 37 cmd := &cobra.Command{ 38 Use: c.commandName, 39 Long: c.description, 40 Example: c.rootExamples(), 41 RunE: func(cmd *cobra.Command, args []string) error { 42 return cmd.Help() 43 }, 44 } 45 46 // Global flags for all subcommands. 47 cmd.PersistentFlags().StringSlice(pluginsFlag, nil, "plugin keys to be used for this subcommand execution") 48 49 // Register --project-version on the root command so that it shows up in help. 50 cmd.Flags().String(projectVersionFlag, c.defaultProjectVersion.String(), "project version") 51 52 // As the root command will be used to shot the help message under some error conditions, 53 // like during plugin resolving, we need to allow unknown flags to prevent parsing errors. 54 cmd.FParseErrWhitelist = cobra.FParseErrWhitelist{UnknownFlags: true} 55 56 return cmd 57 } 58 59 // rootExamples builds the examples string for the root command before resolving plugins 60 func (c CLI) rootExamples() string { 61 str := fmt.Sprintf(`The first step is to initialize your project: 62 %[1]s init [--plugins=<PLUGIN KEYS> [--project-version=<PROJECT VERSION>]] 63 64 <PLUGIN KEYS> is a comma-separated list of plugin keys from the following table 65 and <PROJECT VERSION> a supported project version for these plugins. 66 67 %[2]s 68 69 For more specific help for the init command of a certain plugins and project version 70 configuration please run: 71 %[1]s init --help --plugins=<PLUGIN KEYS> [--project-version=<PROJECT VERSION>] 72 `, 73 c.commandName, c.getPluginTable()) 74 75 if len(c.defaultPlugins) != 0 { 76 if defaultPlugins, found := c.defaultPlugins[c.defaultProjectVersion]; found { 77 str += fmt.Sprintf("\nDefault plugin keys: %q\n", strings.Join(defaultPlugins, ",")) 78 } 79 } 80 81 if c.defaultProjectVersion.Validate() == nil { 82 str += fmt.Sprintf("Default project version: %q\n", c.defaultProjectVersion) 83 } 84 85 return str 86 } 87 88 // getPluginTable returns an ASCII table of the available plugins and their supported project versions. 89 func (c CLI) getPluginTable() string { 90 var ( 91 maxPluginKeyLength = len(pluginKeysHeader) 92 pluginKeys = make([]string, 0, len(c.plugins)) 93 maxProjectVersionLength = len(projectVersionsHeader) 94 projectVersions = make(map[string]string, len(c.plugins)) 95 ) 96 97 for pluginKey, plugin := range c.plugins { 98 if len(pluginKey) > maxPluginKeyLength { 99 maxPluginKeyLength = len(pluginKey) 100 } 101 pluginKeys = append(pluginKeys, pluginKey) 102 supportedProjectVersions := plugin.SupportedProjectVersions() 103 supportedProjectVersionStrs := make([]string, 0, len(supportedProjectVersions)) 104 for _, version := range supportedProjectVersions { 105 supportedProjectVersionStrs = append(supportedProjectVersionStrs, version.String()) 106 } 107 supportedProjectVersionsStr := strings.Join(supportedProjectVersionStrs, ", ") 108 if len(supportedProjectVersionsStr) > maxProjectVersionLength { 109 maxProjectVersionLength = len(supportedProjectVersionsStr) 110 } 111 projectVersions[pluginKey] = supportedProjectVersionsStr 112 } 113 114 lines := make([]string, 0, len(c.plugins)+2) 115 lines = append(lines, fmt.Sprintf(" %[1]*[2]s | %[3]*[4]s", 116 maxPluginKeyLength, pluginKeysHeader, maxProjectVersionLength, projectVersionsHeader)) 117 lines = append(lines, strings.Repeat("-", maxPluginKeyLength+2)+"+"+ 118 strings.Repeat("-", maxProjectVersionLength+2)) 119 120 sort.Strings(pluginKeys) 121 for _, pluginKey := range pluginKeys { 122 supportedProjectVersions := projectVersions[pluginKey] 123 lines = append(lines, fmt.Sprintf(" %[1]*[2]s | %[3]*[4]s", 124 maxPluginKeyLength, pluginKey, maxProjectVersionLength, supportedProjectVersions)) 125 } 126 127 return strings.Join(lines, "\n") 128 }