diff --git a/go.mod b/go.mod index 62f9142b6..18436fa86 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/vmware-labs/reconciler-runtime v0.11.1 github.com/vmware-tanzu/carvel-imgpkg v0.36.2 github.com/vmware-tanzu/difflib v0.0.0-20201117154628-0c031775bf57 - github.com/vmware-tanzu/tanzu-plugin-runtime v0.90.0 + github.com/vmware-tanzu/tanzu-plugin-runtime v1.1.0 golang.org/x/crypto v0.14.0 gopkg.in/yaml.v2 v2.4.0 gotest.tools/v3 v3.5.1 diff --git a/go.sum b/go.sum index d66a0eedd..30421b212 100644 --- a/go.sum +++ b/go.sum @@ -659,6 +659,7 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= @@ -672,8 +673,8 @@ github.com/vmware-tanzu/carvel-imgpkg v0.36.2 h1:RxHd4A4o+Q2qn67ZhiQSMR42cslN/Xn github.com/vmware-tanzu/carvel-imgpkg v0.36.2/go.mod h1:eBOaUEF4tVajROCfcNFnB3zThG6xONhKuahbLFiqGU4= github.com/vmware-tanzu/difflib v0.0.0-20201117154628-0c031775bf57 h1:NmeWaPuGdwr2+NdXEFqDfcBYiA8Qi/z+twfED7mqCyY= github.com/vmware-tanzu/difflib v0.0.0-20201117154628-0c031775bf57/go.mod h1:q4R37lXdaJmkpws5TUoMwT2GXOMs8qJJ9P+zxrtHv28= -github.com/vmware-tanzu/tanzu-plugin-runtime v0.90.0 h1:MbnTxvqCBOLR8gHpnzwxlcbP16vF71LyV8Tx2ANC57o= -github.com/vmware-tanzu/tanzu-plugin-runtime v0.90.0/go.mod h1:wMK/qpJjU7hytDAGt3FX5/iGdlUK8TsJLu36pCr+Zvk= +github.com/vmware-tanzu/tanzu-plugin-runtime v1.1.0 h1:HtlrUyddxVzn4rZBtW6kQM4v2I6bgI0C/k9wJzGrbjE= +github.com/vmware-tanzu/tanzu-plugin-runtime v1.1.0/go.mod h1:M7WVZoItdyQp53tEprQIa6PZmhbrLe3CzuyQphWuRyI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/README.md b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/README.md index 5da27c9d9..35953d443 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/README.md +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/README.md @@ -68,12 +68,26 @@ This package provides a way to write output to different formats. It defines the #### Initialization ``` go -func NewOutputWriter(output io.Writer, outputFormat string, headers ...string) OutputWriter +func NewOutputWriterWithOptions(output io.Writer, outputFormat string, opts []OutputWriterOption, headers ...string) OutputWriter func NewObjectWriter(output io.Writer, outputFormat string, data interface{}) OutputWriter ``` -- `NewOutputWriter` returns a new instance of `OutputWriter` and it accepts an `io.Writer`, an `outputFormat` (one of `TableOutputType`, `YAMLOutputType`, `JSONOutputType`, `ListTableOutputType`), and a variadic list of headers for the table. -- `NewObjectWriter` is the same as `NewOutputWriter` but it is used for writing objects instead of tables. It accepts an `io.Writer`, an `outputFormat` (one of `YAMLOutputType`, `JSONOutputType`), and an object that should be written. +- `NewOutputWriterWithOptions` returns a new instance of `OutputWriter` and it accepts an `io.Writer`, an `outputFormat` (one of `TableOutputType`, `YAMLOutputType`, `JSONOutputType`, `ListTableOutputType`), and a variadic list of headers for the table. + +- `NewObjectWriter` is the same as `NewOutputWriterWithOptions` but it is used for writing objects instead of tables. It accepts an `io.Writer`, an `outputFormat` (one of `YAMLOutputType`, `JSONOutputType`), and an object that should be written. +- It also accepts a list of OutputWriterOption's that can be used to further customize its output. + +Note that NewOutputWriter has been deprecated in favor of NewOutputWriterWithOptions +One difference in the default rendering behavior for YAML/JSON output between +the writer created with NewOutputWriter vs that created with NewOutputWriterWithOptions +is that row fields no longer gets auto stringified in the latter. + +To retain the stringify behavior (unlikely what if needed except for backward compatibility +reasons), create the output writer like so: + +``` go + writer := output.NewOutputWriter(os.Stdout, output.TableOutputType, []OutputWriterOption{WithAutoStringify()}, "Name", "Age") +``` #### Usage @@ -98,7 +112,7 @@ func (obw *objectwriter) Render() `Render` emits the generated output to the output stream. -If `NewOutputWriter` was used for initialization, `Render` will generate output in the format specified by the `outputFormat` parameter. +If `NewOutputWriterWithOptions` was used for initialization, `Render` will generate output in the format specified by the `outputFormat` parameter. If `NewObjectWriter` was used for initialization, `Render` will generate output in the format specified by the `outputFormat` parameter, and it will use the provided object for output. @@ -131,8 +145,11 @@ import ( ) func main() { - // Example usage of NewOutputWriter - writer := output.NewOutputWriter(os.Stdout, output.TableOutputType, "Name", "Age") + // Example usage of NewOutputWriterWithOptions + + // Create a OutputWriter with default options + writer := output.NewOutputWriterWithOptions(os.Stdout, output.TableOutputType, []OutputWriterOption{}, "Name", "Age") + writer.AddRow("John", 30) writer.AddRow("Bob", 45) writer.Render() @@ -162,18 +179,27 @@ This will output: ## OutputWriterSpinner Component -`OutputWriterSpinner` is a Go package that provides an interface to `OutputWriter` augmented with a spinner. It allows for rendering output with a spinner while also providing the ability to stop the spinner and render the final output. +`OutputWriterSpinner` provides an interface to `OutputWriter` augmented with a spinner. It allows for rendering output with a spinner while also providing the ability to stop the spinner and render the final output. ### Usage -To use `OutputWriterSpinner`, you can import the package in your Go code and create an instance of the `OutputWriterSpinner` interface using the `NewOutputWriterWithSpinner` function. +To use `OutputWriterSpinner`, you can import the package in your Go code and create an instance of the `OutputWriterSpinner` interface using the `NewOutputWriterSpinnerWithOptions` function. + +Note that NewOutputWriterWithSpinner has been deprecated in favor of NewOutputWriterSpinnerWithOptions +One difference in the default rendering behavior for YAML/JSON output between +the writer created with NewOutputWriterWithSpinner vs that created with NewOutputWriterSpinnerWithOptions +is that row fields no longer gets auto stringified in the latter. + +To retain the stringify behavior (unlikely what if needed except for backward compatibility +reasons), create the output writer by including WithAutoStringify() in the +options list . ``` go import "github.com/vmware-tanzu/tanzu-plugin-runtime/component" // create new OutputWriterSpinner -outputWriterSpinner, err := component.NewOutputWriterWithSpinner(os.Stdout, "json", "Loading...", true) +outputWriterSpinner, err := component.NewOutputWriterSpinnerWithOptions(os.Stdout, "json", "Loading...", true, []OutputWriterOption{}) if err != nil { fmt.Println("Error creating OutputWriterSpinner:", err) return diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output.go index c34630717..5d157c7ac 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output.go @@ -42,37 +42,83 @@ const ( // outputwriter is our internal implementation. type outputwriter struct { - out io.Writer - keys []string - values [][]string - outputFormat OutputType + out io.Writer + keys []string + values [][]interface{} + outputFormat OutputType + autoStringifyFields bool +} + +// OutputWriterOption is an option for outputwriter +type OutputWriterOption func(*outputwriter) + +// WithAutoStringify configures the output writer to automatically convert +// row fields to their golang string representations. It is used to maintain +// backward compatibility with old rendering behavior, and should be _avoided_ +// if that need does not apply. +func WithAutoStringify() OutputWriterOption { + return func(ow *outputwriter) { + ow.autoStringifyFields = true + } } // NewOutputWriter gets a new instance of our output writer. +// +// Deprecated: NewOutputWriter is being deprecated in favor of NewOutputWriterWithOptions +// Until it is removed, it will retain the existing behavior of converting +// incoming row values to their golang string representation for backward +// compatibility reasons func NewOutputWriter(output io.Writer, outputFormat string, headers ...string) OutputWriter { + // for retaining old json/yaml rendering behavior + opts := []OutputWriterOption{WithAutoStringify()} + + return NewOutputWriterWithOptions(output, outputFormat, opts, headers...) +} + +// NewOutputWriterWithOptions gets a new instance of our output writer with some customization options. +func NewOutputWriterWithOptions(output io.Writer, outputFormat string, opts []OutputWriterOption, headers ...string) OutputWriter { // Initialize the output writer that we use under the covers ow := &outputwriter{} ow.out = output ow.outputFormat = OutputType(outputFormat) ow.keys = headers + ow.applyOptions(opts) + return ow } +func (ow *outputwriter) applyOptions(opts []OutputWriterOption) { + for i := range opts { + opts[i](ow) + } +} + // SetKeys sets the values to use as the keys for the output values. func (ow *outputwriter) SetKeys(headerKeys ...string) { // Overwrite whatever was used in initialization ow.keys = headerKeys } +func stringify(items []interface{}) []interface{} { + var results []interface{} + for i := range items { + results = append(results, fmt.Sprintf("%v", items[i])) + } + return results +} + // AddRow appends a new row to our table. func (ow *outputwriter) AddRow(items ...interface{}) { - row := []string{} + row := []interface{}{} - // Make sure all values are ultimately strings - for _, item := range items { - row = append(row, fmt.Sprintf("%v", item)) + var rowValues []interface{} + rowValues = items + if ow.autoStringifyFields { + rowValues = stringify(items) } + + row = append(row, rowValues...) ow.values = append(ow.values, row) } @@ -90,15 +136,15 @@ func (ow *outputwriter) Render() { } } -func (ow *outputwriter) dataStruct() []map[string]string { - data := []map[string]string{} +func (ow *outputwriter) dataStruct() []map[string]interface{} { + data := []map[string]interface{}{} keys := ow.keys for i, k := range keys { keys[i] = strings.ToLower(strings.ReplaceAll(k, " ", "_")) } for _, itemValues := range ow.values { - item := map[string]string{} + item := map[string]interface{}{} for i, value := range itemValues { if i == len(keys) { continue @@ -192,7 +238,7 @@ func renderListTable(ow *outputwriter) { // There are more headers than values, leave it blank continue } - row = append(row, data[i]) + row = append(row, fmt.Sprintf("%v", data[i])) } headerLabel := strings.ToUpper(header) + ":" values := strings.Join(row, ", ") @@ -222,6 +268,19 @@ func renderTable(ow *outputwriter) { table.SetColWidth(colWidth) table.SetTablePadding("\t\t") table.SetHeader(ow.keys) - table.AppendBulk(ow.values) + table.AppendBulk(convertInterfaceToString(ow.values)) table.Render() } + +func convertInterfaceToString(values [][]interface{}) [][]string { + result := [][]string{} + for _, valuesRow := range values { + row := []string{} + for _, field := range valuesRow { + row = append(row, fmt.Sprintf("%v", field)) + } + + result = append(result, row) + } + return result +} diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output_spinner.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output_spinner.go index aee413740..116306d34 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output_spinner.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/component/output_spinner.go @@ -28,11 +28,25 @@ type outputwriterspinner struct { } // NewOutputWriterWithSpinner returns implementation of OutputWriterSpinner. +// +// Deprecated: NewOutputWriterWithSpinner is being deprecated in favor of +// NewOutputWriterspinnerWithOptions. +// Until it is removed, it will retain the existing behavior of converting +// incoming row values to their golang string representation for backward +// compatibility reasons func NewOutputWriterWithSpinner(output io.Writer, outputFormat, spinnerText string, startSpinner bool, headers ...string) (OutputWriterSpinner, error) { + opts := []OutputWriterOption{WithAutoStringify()} + return NewOutputWriterSpinnerWithOptions(output, outputFormat, spinnerText, startSpinner, opts, headers...) +} + +// NewOutputWriterSpinnerWithOptions returns implementation of OutputWriterSpinner. +func NewOutputWriterSpinnerWithOptions(output io.Writer, outputFormat, spinnerText string, startSpinner bool, opts []OutputWriterOption, headers ...string) (OutputWriterSpinner, error) { ows := &outputwriterspinner{} ows.out = output ows.outputFormat = OutputType(outputFormat) ows.keys = headers + ows.applyOptions(opts) + if ows.outputFormat != JSONOutputType && ows.outputFormat != YAMLOutputType { ows.spinnerText = spinnerText ows.spinner = spinner.New(spinner.CharSets[9], 100*time.Millisecond) diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig.go index a710683b8..e39a1abf5 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig.go @@ -10,6 +10,24 @@ import ( "strings" ) +// ContextType defines the type of control plane endpoint a context represents +type ContextType string + +const ( + // ContextTypeK8s represents a type of control plane endpoint that is a Kubernetes cluster + ContextTypeK8s ContextType = "kubernetes" + contextTypeK8s ContextType = "k8s" + + // ContextTypeTMC represents a type of control plane endpoint that is a TMC SaaS/self-managed endpoint + ContextTypeTMC ContextType = "mission-control" + contextTypeTMC ContextType = "tmc" + + // ContextTypeTanzu represents the type of context used to interact with + // Tanzu control plane endpoint + // Note!! Experimental, please expect changes + ContextTypeTanzu ContextType = "tanzu" +) + // Target is the namespace of the CLI to which plugin is applicable type Target string @@ -34,6 +52,8 @@ const ( var ( // SupportedTargets is a list of all supported Target SupportedTargets = []Target{TargetK8s, TargetTMC} + // SupportedContextTypes is a list of all supported ContextTypes + SupportedContextTypes = []ContextType{ContextTypeK8s, ContextTypeTMC, ContextTypeTanzu} ) const ( @@ -97,7 +117,7 @@ func (s *Server) IsManagementCluster() bool { // GetCurrentServer returns the current server. // -// Deprecated: This API is deprecated. Use GetCurrentContext() instead. +// Deprecated: GetCurrentServer is deprecated. Use GetActiveContext() instead. func (c *ClientConfig) GetCurrentServer() (*Server, error) { for _, server := range c.KnownServers { if server.Name == c.CurrentServer { @@ -136,10 +156,17 @@ func (c *ClientConfig) HasContext(name string) bool { } // GetCurrentContext returns the current context for the given type. +// +// Deprecated: GetCurrentContext is deprecated. Use GetActiveContext instead func (c *ClientConfig) GetCurrentContext(target Target) (*Context, error) { - ctxName := c.CurrentContext[target] + return c.GetActiveContext(ConvertTargetToContextType(target)) +} + +// GetActiveContext returns the current context for the given type. +func (c *ClientConfig) GetActiveContext(context ContextType) (*Context, error) { + ctxName := c.CurrentContext[context] if ctxName == "" { - return nil, fmt.Errorf("no current context set for target %q", target) + return nil, fmt.Errorf("no current context set for type %q", context) } ctx, err := c.GetContext(ctxName) if err != nil { @@ -149,6 +176,9 @@ func (c *ClientConfig) GetCurrentContext(target Target) (*Context, error) { } // GetAllCurrentContextsMap returns all current context per Target +// +// Deprecated: GetAllCurrentContextsMap is deprecated. Use GetAllActiveContextsMap instead +// Note: This function will not return information for tanzu ContextType func (c *ClientConfig) GetAllCurrentContextsMap() (map[Target]*Context, error) { currentContexts := make(map[Target]*Context) for _, target := range SupportedTargets { @@ -160,10 +190,22 @@ func (c *ClientConfig) GetAllCurrentContextsMap() (map[Target]*Context, error) { return currentContexts, nil } -// GetAllCurrentContextsList returns all current context names as list -func (c *ClientConfig) GetAllCurrentContextsList() ([]string, error) { +// GetAllActiveContextsMap returns all active context per ContextType +func (c *ClientConfig) GetAllActiveContextsMap() (map[ContextType]*Context, error) { + currentContexts := make(map[ContextType]*Context) + for _, contextType := range SupportedContextTypes { + context, err := c.GetActiveContext(contextType) + if err == nil && context != nil { + currentContexts[contextType] = context + } + } + return currentContexts, nil +} + +// GetAllActiveContextsList returns all active context names as list +func (c *ClientConfig) GetAllActiveContextsList() ([]string, error) { var serverNames []string - currentContextsMap, err := c.GetAllCurrentContextsMap() + currentContextsMap, err := c.GetAllActiveContextsMap() if err != nil { return nil, err } @@ -174,17 +216,31 @@ func (c *ClientConfig) GetAllCurrentContextsList() ([]string, error) { return serverNames, nil } +// GetAllCurrentContextsList returns all current context names as list +// +// Deprecated: GetAllCurrentContextsList is deprecated. Use GetAllActiveContextsList instead +func (c *ClientConfig) GetAllCurrentContextsList() ([]string, error) { + return c.GetAllActiveContextsList() +} + // SetCurrentContext sets the current context for the given target. +// +// Deprecated: SetCurrentContext is deprecated. Use SetActiveContext instead func (c *ClientConfig) SetCurrentContext(target Target, ctxName string) error { + return c.SetActiveContext(ConvertTargetToContextType(target), ctxName) +} + +// SetActiveContext sets the active context for the given contextType. +func (c *ClientConfig) SetActiveContext(contextType ContextType, ctxName string) error { if c.CurrentContext == nil { - c.CurrentContext = make(map[Target]string) + c.CurrentContext = make(map[ContextType]string) } - c.CurrentContext[target] = ctxName + c.CurrentContext[contextType] = ctxName ctx, err := c.GetContext(ctxName) if err != nil { return err } - if ctx.IsManagementCluster() || ctx.Target == TargetTMC { + if ctx.IsManagementCluster() || ctx.ContextType == ContextTypeTMC { c.CurrentServer = ctxName } return nil @@ -287,3 +343,27 @@ func (c *ClientConfig) SetEditionSelector(edition EditionSelector) { } c.ClientOptions.CLI.UnstableVersionSelector = EditionStandard } + +func ConvertTargetToContextType(target Target) ContextType { + switch target { + case TargetK8s: + return ContextTypeK8s + case TargetTMC: + return ContextTypeTMC + case Target(ContextTypeTanzu): + return ContextTypeTanzu + } + return ContextType(target) +} + +func ConvertContextTypeToTarget(ctxType ContextType) Target { + switch ctxType { + case ContextTypeK8s: + return TargetK8s + case ContextTypeTMC: + return TargetTMC + case ContextTypeTanzu: + return Target(ContextTypeTanzu) + } + return Target(ctxType) +} diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_helper.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_helper.go index 88ba39e1e..a27644b69 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_helper.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_helper.go @@ -3,6 +3,8 @@ package types +import "strings" + // StringToTarget converts string to Target type func StringToTarget(target string) Target { if target == string(targetK8s) || target == string(TargetK8s) { @@ -28,3 +30,25 @@ func IsValidTarget(target string, allowGlobal, allowUnknown bool) bool { (allowGlobal && target == string(TargetGlobal)) || (allowUnknown && target == string(TargetUnknown)) } + +// StringToContextType converts string to ContextType +func StringToContextType(contextType string) ContextType { + contextType = strings.ToLower(contextType) + if contextType == string(contextTypeK8s) || contextType == string(ContextTypeK8s) { + return ContextTypeK8s + } else if contextType == string(contextTypeTMC) || contextType == string(ContextTypeTMC) { + return ContextTypeTMC + } else if contextType == string(ContextTypeTanzu) { + return ContextTypeTanzu + } + return "" +} + +// IsValidContextType validates the contextType string specified is valid or not +func IsValidContextType(contextType string) bool { + ct := StringToContextType(contextType) + if ct == "" && contextType != "" { + return false + } + return true +} diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_types.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_types.go index 60a10ad1f..b39243567 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_types.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/config/types/clientconfig_types.go @@ -52,19 +52,27 @@ type Server struct { // Context configuration for a control plane. This can one of the following, // 1. Kubernetes Cluster // 2. Tanzu Mission Control endpoint +// 3. Tanzu control plane endpoint type Context struct { // Name of the context. Name string `json:"name,omitempty" yaml:"name,omitempty"` // Target of the context. + // Deprecated: This field is deprecated. Please use ContextType Target Target `json:"target,omitempty" yaml:"target,omitempty"` + // ContextType of the context. + ContextType ContextType `json:"contextType,omitempty" yaml:"contextType,omitempty"` + // GlobalOpts if the context is a global control plane (e.g., TMC). GlobalOpts *GlobalServer `json:"globalOpts,omitempty" yaml:"globalOpts,omitempty"` // ClusterOpts if the context is a kubernetes cluster. ClusterOpts *ClusterServer `json:"clusterOpts,omitempty" yaml:"clusterOpts,omitempty"` + // AdditionalMetadata to provide any additional data that is respective to each context + AdditionalMetadata map[string]interface{} `json:"additionalMetadata,omitempty" yaml:"additionalMetadata,omitempty"` + // DiscoverySources determines from where to discover plugins // associated with this context. // Deprecated: This field is deprecated. It is currently no used. @@ -295,8 +303,23 @@ type CoreCliOptions struct { CEIPOptIn string `json:"ceipOptIn,omitempty" yaml:"ceipOptIn,omitempty"` // EULAStatus is the EULA acceptance status. EULAStatus string `json:"eulaStatus,omitempty" yaml:"eulaStatus,omitempty"` + // EULAAcceptedVersions is comma-separated list of EULA versions accepted. + EULAAcceptedVersions string `json:"eulaAcceptedVersions,omitempty" yaml:"eulaAcceptedVersions,omitempty"` // DiscoverySources determine where to discover plugins DiscoverySources []PluginDiscovery `json:"discoverySources,omitempty" yaml:"discoverySources,omitempty"` + // CliID is the uuid uniquely identifying the CLI instance + CliID string `json:"cliId,omitempty" yaml:"cliId,omitempty"` + // TelemetryOptions are the core CLI specific telemetry options + TelemetryOptions *TelemetryOptions `json:"telemetry,omitempty" yaml:"telemetry,omitempty"` +} + +type TelemetryOptions struct { + // Source is the path of the telemetry source database + Source string `json:"source,omitempty" yaml:"source,omitempty"` + // CSPOrgID is the organization ID the user + CSPOrgID string `json:"cspOrgID,omitempty" yaml:"cspOrgID,omitempty"` + // EntitlementAccountNumber is the organization ID the user + EntitlementAccountNumber string `json:"entitlementAccountNumber,omitempty" yaml:"entitlementAccountNumber,omitempty"` } // Cert provides a certificate configuration for an endpoint @@ -327,7 +350,7 @@ type ClientConfig struct { KnownContexts []*Context `json:"contexts,omitempty" yaml:"contexts,omitempty"` // CurrentContext for every type. - CurrentContext map[Target]string `json:"currentContext,omitempty" yaml:"currentContext,omitempty"` + CurrentContext map[ContextType]string `json:"currentContext,omitempty" yaml:"currentContext,omitempty"` // ClientOptions are client specific options like feature flags, environment variables, repositories, discoverySources, etc. ClientOptions *ClientOptions `json:"clientOptions,omitempty" yaml:"clientOptions,omitempty"` diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/log/logger.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/log/logger.go index a511df90c..3de3355f4 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/log/logger.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/log/logger.go @@ -8,12 +8,17 @@ import ( "fmt" "os" "runtime" + "strconv" "strings" "time" "github.com/pkg/errors" ) +const ( + EnvTanzuCLILogLevel = "TANZU_CLI_LOG_LEVEL" +) + var defaultLogThreshold int32 = 3 // logEntry defines the information that can be used for composing a log line. @@ -28,14 +33,27 @@ type logEntry struct { Values []interface{} } -// NewLogger returns a new instance of the clusterctl. +// NewLogger returns a new instance of the logger. func NewLogger() LoggerImpl { + logThreshold := getLogThreshold() return &logger{ - threshold: &defaultLogThreshold, + threshold: &logThreshold, + } +} + +func getLogThreshold() int32 { + reqLogLevelStr := os.Getenv(EnvTanzuCLILogLevel) + if reqLogLevelStr != "" { + requestedLogLevel, err := strconv.ParseUint(reqLogLevelStr, 10, 32) + if err == nil { + return int32(requestedLogLevel) + } + fmt.Fprintf(os.Stderr, "invalid value %q for %s\n", reqLogLevelStr, EnvTanzuCLILogLevel) } + return defaultLogThreshold } -// logger defines a clusterctl friendly logr.Logger +// logger defines a logr.Logger type logger struct { threshold *int32 level int32 diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/info.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/info.go index 032bd2aec..441514daa 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/info.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/info.go @@ -6,6 +6,7 @@ package plugin import ( "encoding/json" "fmt" + "runtime" "runtime/debug" "github.com/spf13/cobra" @@ -24,6 +25,11 @@ type pluginInfo struct { // PluginRuntimeVersion of the plugin. Must be a valid semantic version https://semver.org/ // This version specifies the version of Plugin Runtime that was used to build the plugin PluginRuntimeVersion string `json:"pluginRuntimeVersion" yaml:"pluginRuntimeVersion"` + + // The machine architecture of the plugin binary. + // This information can prove useful on Darwin (MacOS) ARM64 machine + // which can also execute AMD64 binaries in the Rosetta emulator. + BinaryArch string `json:"binaryArch" yaml:"binaryArch"` } func newInfoCmd(desc *PluginDescriptor) *cobra.Command { @@ -35,6 +41,7 @@ func newInfoCmd(desc *PluginDescriptor) *cobra.Command { pi := pluginInfo{ PluginDescriptor: *desc, PluginRuntimeVersion: getPluginRuntimeVersion(), + BinaryArch: runtime.GOARCH, } b, err := json.Marshal(pi) if err != nil { diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/cli-wordlist.yml b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/cli-wordlist.yml index 6c77e3c2f..98e63f6c3 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/cli-wordlist.yml +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/cli-wordlist.yml @@ -1,124 +1,368 @@ --- nouns: + - accelerator - account - admin-kubeconfig + - agentartifacts + - aks-cluster - alpha - app + - apps + - audit - available - available-upgrades + - available-zone - aws + - backup + - backup-location + - build-service + - builder + - buildpack - ceip-participation + - chart + - chartmetadata + - claimable + - claims + - class-claim + - classes + - cli + - cli-usage-analytics - cluster + - cluster-stores + - cluster-supply-chain + - clusterbuilder + - clusterbuildpack - clustergroup + - clusterstack + - clusterstore - component + - config + - continuousdelivery + - credential - credentials - data-protection + - docs + - ekscluster + - events + - extension + - external-secrets + - feature + - fragment + - gitrepository + - health + - helm + - iam + - image - insight + - inspection - installed + - instances + - integration + - inventory + - isolated-cluster - kubeconfig - kubernetes-release + - kustomization + - local-source-proxy - login + - logs - machinehealthcheck + - managed-resources - management-cluster + - metadata + - namespace + - namespaces + - nodepool + - node-pool + - object + - options - os + - osimage - package + - participation - permissions - pinniped-auth - plugin - policy + - policy-template + - post-install + - provider-aks-cluster + - provider-eks-cluster - provisioner + - recipe + - registry + - release - repo - repository + - repositorysecret + - resource-claims + - role + - schedule + - secret + - secrets + - service-mesh + - services + - setting + - snapshot-location - source + - status + - stores + - stream + - tanzupackage + - tap + - telemetry + - template + - test + - test-permission + - type + - types + - update-policy + - vulnerabilities - wordlist + - workload + - workload-cluster - workspace verbs: + - activate - add + - add-binding + - apply + - attach + - build - clean - completion - create - delete + - deactivate + - deregister - describe + - disable + - download-bundle + - enable + - export + - fetch + - generate + - generate-docs + - generate-from-local + - generate-token - get - import - info - init - install - list + - manage + - publish + - push + - reattach - register + - remove-binding + - reregister + - restore - scale + - scan - show + - triage + - unmanage + - upload-bundle - update - upgrade + - validate - version global-flags: + - column + - context + - debug - help + - kube-api-burst + - kube-api-qps + - kubeconfig + - kubeconfig-context + - kubeconfig-yaml - log-file + - namespace + - no-color + - output-format - v - verbose + - verbosity + - yes command-flags: + - CEIP-opt-in + - CEIP-opt-out + - accelerator-name + - accelerator-path + - acknowledge-CEIP + - activated + - additional-tkg-system-manifests + - agent-name + - all - all-namespaces - - apiToken - app + - artifact-group-uid + - az-file - bind - browser + - build-values + - build-ytt-validations - ca-bundle - ca-bundle-data + - ca-certificate - ceip-participation + - chdir - client-id + - cluster + - cluster-arn + - cluster-group + - cluster-group-name + - cluster-name - cni + - comment - concierge-authenticator-name - concierge-authenticator-type - concierge-ca-bundle-data - concierge-endpoint + - concierge-is-cluster-scoped - concierge-namespace - context + - continue-bootstrap - controlplane-machine-count - controlplane-size + - copy-to - create - create-namespace + - credential-cache + - credential-name + - csp-org-id + - cveid + - dangerous-allow-use-of-shared-namespace + - data-values-file + - deactivated - debug + - debug-always - debug-session-cache + - default-cluster-group + - default-workload-cluster-image-registry + - default-workload-cluster-proxy-name + - delete-backups - deploy-tkg-on-vSphere7 + - description + - destination-repo + - direct + - directory - disable-grouping - disable-no-echo + - display-name + - docs-dir - dry-run - enable-cluster-options - enable-concierge - enable-tkgs-on-vSphere7 - endpoint + - entitlement-account-number - env + - env-is-prod + - export-to-all-namespaces + - extended + - extension-name - feature-flags + - featuregate - file + - filename - force + - force-config-update - force-csp + - fragment-names + - fragment-paths + - from-context - gcp-bucket-name - gcp-root-path - git-branch - git-commit - git-repo + - git-sub-path - git-tag + - group + - groups + - icon-url + - image-registry + - img-digest + - img-registry + - include-all-families + - include-experimental - include-management-cluster - infrastructure + - input-artifact-dir + - insecure + - interval - issuer + - justification - kubeconfig + - kubernetes-provider-type + - labels + - latest + - limit - limit-cpu - limit-memory - listen-port + - local + - local-output-discovery-dir + - local-output-distribution-dir + - local-path + - manageable + - management-cluster + - management-cluster-name + - max-size - name - namespace + - namespace-name + - node-pool-name + - oci-discovery-image + - oci-distribution-image-repository - offset + - openapi-schema + - options + - options-file + - org - os-arch - os-name - os-version - output + - output-dir + - package - package-name + - page + - password + - password-env-var + - password-file + - password-stdin + - permission + - pkg-name + - pkg-version - plan + - plugins - poll-interval - poll-timeout + - private-saas + - provisioner + - provisioner-name + - proxy-name + - query + - reconcile + - region + - repo-output + - repo-type - request-audience + - resource-group + - resource-group-name + - response + - role + - scope - scopes + - secret-ref + - secret-type - server + - server-url - service-account-name - session-cache - show-all-conditions @@ -126,22 +370,50 @@ command-flags: - show-group-members - size - skip-browser + - skip-verify + - source-directory + - source-image + - source-repo + - src-commit + - src-org + - src-repo - staging + - state - stderr-only + - subscription-id + - tag + - tags - target-namespace + - template - timeout + - tkg-custom-compatibility-image-path + - tkg-version - tkr + - token + - triage-uid-to-copy + - tty + - type - ui - uri - url - use-existing-bootstrap-cluster - use-existing-cleanup-cluster + - use-proxy + - user + - username + - users + - values - values-file - values-schema + - verbose - version - vsphere-controlplane-endpoint - vsphere-vm-template-name - wait + - wait-check-interval + - wait-timeout - worker-machine-count - worker-size - yes + - ytt-overlay-file + - ytt-overlays diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/lint.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/lint.go index 97593604f..bb4f12e55 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/lint.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/lint/lint.go @@ -71,7 +71,8 @@ func (c *CobraLintRunner) Run() bool { // Output writes the results of linting in a table form. func (c *CobraLintRunner) Output() { - t := component.NewOutputWriter(c.config.cmd.OutOrStdout(), "table", "command", "lint") + opts := []component.OutputWriterOption{} + t := component.NewOutputWriterWithOptions(c.config.cmd.OutOrStdout(), "table", opts, "command", "lint") for k, vs := range *c.results { for _, v := range vs { t.AddRow(k, v) diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/root.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/root.go index e64215263..1982021e6 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/root.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/root.go @@ -30,7 +30,7 @@ func newRootCmd(descriptor *PluginDescriptor) *cobra.Command { }, } cobra.AddTemplateFuncs(TemplateFuncs) - cmd.SetUsageTemplate(CmdTemplate) + cmd.SetUsageTemplate(cmdTemplate) cmd.AddCommand( newDescribeCmd(descriptor.Description), diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/sync_plugins.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/sync_plugins.go index b1f276507..e1cc18e0a 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/sync_plugins.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/sync_plugins.go @@ -7,6 +7,7 @@ import ( "bytes" "errors" "fmt" + "io" "os" "os/exec" "strings" @@ -21,16 +22,62 @@ const ( customCommandName string = "_custom_command" ) -func runCommand(commandPath string, args []string) (bytes.Buffer, bytes.Buffer, error) { +// cmdOptions specifies the command options +type cmdOptions struct { + outWriter io.Writer + errWriter io.Writer +} + +type CommandOptions func(o *cmdOptions) + +// WithOutputWriter specifies the CommandOption for configuring Stdout +func WithOutputWriter(outWriter io.Writer) CommandOptions { + return func(o *cmdOptions) { + o.outWriter = outWriter + } +} + +// WithErrorWriter specifies the CommandOption for configuring Stderr +func WithErrorWriter(errWriter io.Writer) CommandOptions { + return func(o *cmdOptions) { + o.errWriter = errWriter + } +} + +// WithNoStdout specifies to ignore stdout +func WithNoStdout() CommandOptions { + return func(o *cmdOptions) { + o.outWriter = io.Discard + } +} + +// WithNoStderr specifies to ignore stderr +func WithNoStderr() CommandOptions { + return func(o *cmdOptions) { + o.errWriter = io.Discard + } +} + +func runCommand(commandPath string, args []string, opts *cmdOptions) (bytes.Buffer, bytes.Buffer, error) { + command := exec.Command(commandPath, args...) + var stderr bytes.Buffer var stdout bytes.Buffer - command := exec.Command(commandPath, args...) - command.Stdout = &stdout - command.Stderr = &stderr + wout := io.MultiWriter(&stdout, os.Stdout) + werr := io.MultiWriter(&stderr, os.Stderr) - err := command.Run() - return stdout, stderr, err + if opts.outWriter != nil { + wout = io.MultiWriter(&stdout, opts.outWriter) + } + if opts.errWriter != nil { + werr = io.MultiWriter(&stderr, opts.errWriter) + } + + command.Stdout = wout + command.Stderr = werr + + return stdout, stderr, command.Run() } // SyncPluginsForTarget will attempt to install plugins required by the active @@ -43,11 +90,49 @@ func runCommand(commandPath string, args []string) (bytes.Buffer, bytes.Buffer, // implementation are subjected to change/removal if an alternative means to // provide equivalent functionality can be introduced. // -// The output of the plugin syncing will be return as a string. -func SyncPluginsForTarget(target types.Target) (string, error) { +// By default this API will write to os.Stdout and os.Stderr. +// To write the logs to different output and error streams as part of the plugin sync +// command invocation, configure CommandOptions as part of the parameters. +// +// Example: +// +// var outBuf bytes.Buffer +// var errBuf bytes.Buffer +// SyncPluginsForTarget(types.TargetK8s, WithOutputWriter(&outBuf), WithErrorWriter(&errBuf)) +// +// Deprecated: SyncPluginsForTarget is deprecated. Use SyncPluginsForContextType instead +func SyncPluginsForTarget(target types.Target, opts ...CommandOptions) (string, error) { + return SyncPluginsForContextType(types.ConvertTargetToContextType(target), opts...) +} + +// SyncPluginsForContextType will attempt to install plugins required by the active +// Context of the provided contextType. This is most useful for any plugin +// implementation which creates a new Context or updates an existing one as +// part of its operation, and prefers that the plugins appropriate for the +// Context are immediately available for use. +// +// Note: This API is considered EXPERIMENTAL. Both the function's signature and +// implementation are subjected to change/removal if an alternative means to +// provide equivalent functionality can be introduced. +// +// By default this API will write to os.Stdout and os.Stderr. +// To write the logs to different output and error streams as part of the plugin sync +// command invocation, configure CommandOptions as part of the parameters. +// +// Example: +// +// var outBuf bytes.Buffer +// var errBuf bytes.Buffer +// SyncPluginsForContextType(types.ContextTypeK8s, WithOutputWriter(&outBuf), WithErrorWriter(&errBuf)) +func SyncPluginsForContextType(contextType types.ContextType, opts ...CommandOptions) (string, error) { // For now, the implementation expects env var TANZU_BIN to be set and // pointing to the core CLI binary used to invoke the plugin sync with. + options := &cmdOptions{} + for _, opt := range opts { + opt(options) + } + cliPath := os.Getenv("TANZU_BIN") if cliPath == "" { return "", errors.New("the environment variable TANZU_BIN is not set") @@ -57,16 +142,16 @@ func SyncPluginsForTarget(target types.Target) (string, error) { args := []string{"plugin", "sync"} altCommandArgs = append(altCommandArgs, args...) - altCommandArgs = append(altCommandArgs, "--target", string(target)) + altCommandArgs = append(altCommandArgs, "--type", string(contextType)) // Check if there is an alternate means to perform the plugin syncing // operation, if not fall back to `plugin sync` - output, _, err := runCommand(cliPath, altCommandArgs) - if err == nil && output.String() != "" { - args = strings.Fields(output.String()) + stdoutOutput, _, err := runCommand(cliPath, altCommandArgs, &cmdOptions{outWriter: io.Discard, errWriter: io.Discard}) + if err == nil && stdoutOutput.String() != "" { + args = strings.Fields(stdoutOutput.String()) } // Runs the actual command - stdoutOutput, stderrOutput, err := runCommand(cliPath, args) + stdoutOutput, stderrOutput, err := runCommand(cliPath, args, options) return fmt.Sprintf("%s%s", stdoutOutput.String(), stderrOutput.String()), err } diff --git a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/usage.go b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/usage.go index a605e1812..0b1d09487 100644 --- a/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/usage.go +++ b/vendor/github.com/vmware-tanzu/tanzu-plugin-runtime/plugin/usage.go @@ -5,16 +5,18 @@ package plugin import ( "os" + "strings" "text/template" "github.com/spf13/cobra" "github.com/vmware-tanzu/tanzu-plugin-runtime/component" + "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" ) // UsageFunc is the usage func for a plugin. var UsageFunc = func(c *cobra.Command) error { - t, err := template.New("usage").Funcs(TemplateFuncs).Parse(CmdTemplate) + t, err := template.New("usage").Funcs(TemplateFuncs).Parse(cmdTemplate) if err != nil { return err } @@ -22,9 +24,9 @@ var UsageFunc = func(c *cobra.Command) error { } // CmdTemplate is the template for plugin commands. -const CmdTemplate = `{{ bold "Usage:" }}{{if .Runnable}} - tanzu{{ $target := index .Annotations "target" }}{{ if and (ne $target "global") (ne $target "") }} {{ $target }} {{ else }} {{ end }}{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} - tanzu{{ $target := index .Annotations "target" }}{{ if and (ne $target "global") (ne $target "") }} {{ $target }} {{ else }} {{ end }}{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} +// Deprecated: This variable is deprecated. +const CmdTemplate = `{{ bold "Usage:" }} + {{if .Runnable}}{{ $target := index .Annotations "target" }}{{ if or (eq $target "kubernetes") (eq $target "k8s") }}tanzu {{.UseLine}}{{ end }}{{ if and (ne $target "global") (ne $target "") }}tanzu {{ $target }} {{ else }} {{ end }}{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}{{ $target := index .Annotations "target" }}{{ if or (eq $target "kubernetes") (eq $target "k8s") }}tanzu {{.CommandPath}} [command]{{end}}{{ if and (ne $target "global") (ne $target "") }}tanzu {{ $target }} {{ else }} {{ end }}{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} {{ bold "Aliases:" }} {{.NameAndAliases}}{{end}}{{if .HasExample}} @@ -44,11 +46,145 @@ const CmdTemplate = `{{ bold "Usage:" }}{{if .Runnable}} {{ bold "Additional help topics:" }}{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} -Use "{{if beginsWith .CommandPath "tanzu "}}{{.CommandPath}}{{else}}tanzu{{ $target := index .Annotations "target" }}{{ if and (ne $target "global") (ne $target "") }} {{ $target }} {{ else }} {{ end }}{{.CommandPath}}{{end}} [command] --help" for more information about a command.{{end}} +{{ $target := index .Annotations "target" }}{{ if or (eq $target "kubernetes") (eq $target "k8s") }}Use "{{if beginsWith .CommandPath "tanzu "}}{{.CommandPath}}{{else}}tanzu {{.CommandPath}}{{end}} [command] --help" for more information about a command.{{end}}Use "{{if beginsWith .CommandPath "tanzu "}}{{.CommandPath}}{{else}}tanzu{{ $target := index .Annotations "target" }}{{ if and (ne $target "global") (ne $target "") }} {{ $target }} {{ else }} {{ end }}{{.CommandPath}}{{end}} [command] --help" for more information about a command.{{end}} ` +// cmdTemplate is the template for plugin commands. +const cmdTemplate = `{{ printHelp . }}` + +// Constants for help text labels +const ( + usageStr = "Usage:" + aliasesStr = "Aliases:" + examplesStr = "Examples:" + availableCommandsStr = "Available Commands:" + flagsStr = "Flags:" + globalFlagsStr = "Global Flags:" + additionalHelpTopicsStr = "Additional help topics:" + indentStr = " " +) + +// Helper to format the usage help section. +func formatUsageHelpSection(cmd *cobra.Command, target types.Target) string { + var output strings.Builder + + output.WriteString(component.Bold(usageStr) + "\n") + base := indentStr + "tanzu " + + if cmd.Runnable() { + // For kubernetes, k8s, global, or no target display tanzu command path without target + if target == types.TargetK8s || target == types.TargetGlobal || target == types.TargetUnknown { + output.WriteString(base + cmd.UseLine() + "\n") + } + + // For non global, or no target ;display tanzu command path with target + if target != types.TargetGlobal && target != types.TargetUnknown { + output.WriteString(base + string(target) + " " + cmd.UseLine() + "\n") + } + } + + if cmd.HasAvailableSubCommands() { + if cmd.Runnable() { + // If the command is both Runnable and has sub-commands, let's insert an empty + // line between the usage for the Runnable and the one for the sub-commands + output.WriteString("\n") + } + // For kubernetes, k8s, global, or no target display tanzu command path without target + if target == types.TargetK8s || target == types.TargetGlobal || target == types.TargetUnknown { + output.WriteString(base + cmd.CommandPath() + " [command]\n") + } + + // For non global, or no target display tanzu command path with target + if target != types.TargetGlobal && target != types.TargetUnknown { + output.WriteString(base + string(target) + " " + cmd.CommandPath() + " [command]\n") + } + } + return output.String() +} + +// Helper to format the help footer. +func formatHelpFooter(cmd *cobra.Command, target types.Target) string { + var footer strings.Builder + if !cmd.HasAvailableSubCommands() { + return "" + } + + footer.WriteString("\n") + + // For kubernetes, k8s, global, or no target display tanzu command path without target + if target == types.TargetK8s || target == types.TargetGlobal || target == types.TargetUnknown { + footer.WriteString(`Use "`) + if !strings.HasPrefix(cmd.CommandPath(), "tanzu ") { + footer.WriteString("tanzu ") + } + footer.WriteString(cmd.CommandPath() + ` [command] --help" for more information about a command.` + "\n") + } + + // For non global, or no target display tanzu command path with target + if target != types.TargetGlobal && target != types.TargetUnknown { + footer.WriteString(`Use "`) + if !strings.HasPrefix(cmd.CommandPath(), "tanzu ") { + footer.WriteString("tanzu ") + } + footer.WriteString(string(target) + " " + cmd.CommandPath() + ` [command] --help" for more information about a command.` + "\n") + } + + return footer.String() +} + +func printHelp(cmd *cobra.Command) string { + var output strings.Builder + target := types.StringToTarget(cmd.Annotations["target"]) + + output.WriteString(formatUsageHelpSection(cmd, target)) + + if len(cmd.Aliases) > 0 { + output.WriteString("\n" + component.Bold(aliasesStr) + "\n") + output.WriteString(indentStr + cmd.NameAndAliases() + "\n") + } + + if cmd.HasExample() { + output.WriteString("\n" + component.Bold(examplesStr) + "\n") + output.WriteString(indentStr + cmd.Example + "\n") + } + + if cmd.HasAvailableSubCommands() { + output.WriteString("\n" + component.Bold(availableCommandsStr) + "\n") + for _, c := range cmd.Commands() { + if c.IsAvailableCommand() { + output.WriteString(indentStr + component.Rpad(c.Name(), c.NamePadding()) + " " + c.Short + "\n") + } + } + } + + if cmd.HasAvailableLocalFlags() { + output.WriteString("\n" + component.Bold(flagsStr) + "\n") + output.WriteString(strings.TrimRight(cmd.LocalFlags().FlagUsages(), " ")) + } + + if cmd.HasAvailableInheritedFlags() { + output.WriteString("\n" + component.Bold(globalFlagsStr) + "\n") + output.WriteString(strings.TrimRight(cmd.InheritedFlags().FlagUsages(), " ")) + } + + if cmd.HasHelpSubCommands() { + output.WriteString("\n" + component.Bold(additionalHelpTopicsStr) + "\n") + for _, c := range cmd.Commands() { + if c.IsAdditionalHelpTopicCommand() { + output.WriteString(indentStr + component.Rpad(c.CommandPath(), c.CommandPathPadding()) + " " + c.Short + "\n") + } + } + } + output.WriteString(formatHelpFooter(cmd, target)) + + return output.String() +} + // TemplateFuncs are the template usage funcs. var TemplateFuncs = template.FuncMap{ + "printHelp": printHelp, + // The below are not needed but are kept for backwards-compatibility + // in case it is being used through the API "rpad": component.Rpad, "bold": component.Bold, "underline": component.Underline, diff --git a/vendor/modules.txt b/vendor/modules.txt index 40a87d394..db687ac3e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -512,7 +512,7 @@ github.com/vmware-tanzu/carvel-imgpkg/pkg/imgpkg/registry/auth/credentialprovide # github.com/vmware-tanzu/difflib v0.0.0-20201117154628-0c031775bf57 ## explicit github.com/vmware-tanzu/difflib -# github.com/vmware-tanzu/tanzu-plugin-runtime v0.90.0 +# github.com/vmware-tanzu/tanzu-plugin-runtime v1.1.0 ## explicit; go 1.18 github.com/vmware-tanzu/tanzu-plugin-runtime/component github.com/vmware-tanzu/tanzu-plugin-runtime/config/types