github.com/oam-dev/kubevela@v1.9.11/pkg/cmd/builder.go (about) 1 /* 2 Copyright 2022 The KubeVela 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 cmd 18 19 import ( 20 "github.com/spf13/cobra" 21 "k8s.io/kubectl/pkg/util/term" 22 23 "github.com/oam-dev/kubevela/apis/types" 24 cmdutil "github.com/oam-dev/kubevela/pkg/cmd/util" 25 "github.com/oam-dev/kubevela/pkg/utils/util" 26 ) 27 28 // Builder build command with factory 29 type Builder struct { 30 cmd *cobra.Command 31 f Factory 32 } 33 34 // NamespaceFlagConfig config for namespace flag in cmd 35 type NamespaceFlagConfig struct { 36 completion bool 37 usage string 38 loadEnv bool 39 } 40 41 // NamespaceFlagOption the option for configuring namespace flag in cmd 42 type NamespaceFlagOption interface { 43 ApplyToNamespaceFlagOptions(*NamespaceFlagConfig) 44 } 45 46 func newNamespaceFlagOptions(options ...NamespaceFlagOption) NamespaceFlagConfig { 47 cfg := NamespaceFlagConfig{ 48 completion: true, 49 usage: usageNamespace, 50 loadEnv: true, 51 } 52 for _, option := range options { 53 option.ApplyToNamespaceFlagOptions(&cfg) 54 } 55 return cfg 56 } 57 58 // ClusterFlagConfig config for cluster flag in cmd 59 type ClusterFlagConfig struct { 60 completion bool 61 usage string 62 disableSliceInput bool 63 } 64 65 // ClusterFlagOption the option for configuring cluster flag 66 type ClusterFlagOption interface { 67 ApplyToClusterFlagOptions(*ClusterFlagConfig) 68 } 69 70 func newClusterFlagOptions(options ...ClusterFlagOption) ClusterFlagConfig { 71 cfg := ClusterFlagConfig{ 72 completion: true, 73 usage: usageCluster, 74 disableSliceInput: false, 75 } 76 for _, option := range options { 77 option.ApplyToClusterFlagOptions(&cfg) 78 } 79 return cfg 80 } 81 82 // FlagNoCompletionOption disable auto-completion for flag 83 type FlagNoCompletionOption struct{} 84 85 // ApplyToNamespaceFlagOptions . 86 func (option FlagNoCompletionOption) ApplyToNamespaceFlagOptions(cfg *NamespaceFlagConfig) { 87 cfg.completion = false 88 } 89 90 // ApplyToClusterFlagOptions . 91 func (option FlagNoCompletionOption) ApplyToClusterFlagOptions(cfg *ClusterFlagConfig) { 92 cfg.completion = false 93 } 94 95 // UsageOption the usage description for flag 96 type UsageOption string 97 98 // ApplyToNamespaceFlagOptions . 99 func (option UsageOption) ApplyToNamespaceFlagOptions(cfg *NamespaceFlagConfig) { 100 cfg.usage = string(option) 101 } 102 103 // ApplyToClusterFlagOptions . 104 func (option UsageOption) ApplyToClusterFlagOptions(cfg *ClusterFlagConfig) { 105 cfg.usage = string(option) 106 } 107 108 // NamespaceFlagDisableEnvOption disable loading namespace from env 109 type NamespaceFlagDisableEnvOption struct{} 110 111 // ApplyToNamespaceFlagOptions . 112 func (option NamespaceFlagDisableEnvOption) ApplyToNamespaceFlagOptions(cfg *NamespaceFlagConfig) { 113 cfg.loadEnv = false 114 } 115 116 // WithNamespaceFlag add namespace flag to the command, by default, it will also add env flag to the command 117 func (builder *Builder) WithNamespaceFlag(options ...NamespaceFlagOption) *Builder { 118 cfg := newNamespaceFlagOptions(options...) 119 builder.cmd.Flags().StringP(flagNamespace, "n", "", cfg.usage) 120 if cfg.completion { 121 cmdutil.CheckErr(builder.cmd.RegisterFlagCompletionFunc( 122 flagNamespace, 123 func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 124 return GetNamespacesForCompletion(cmd.Context(), builder.f, toComplete) 125 })) 126 } 127 if cfg.loadEnv { 128 return builder.WithEnvFlag() 129 } 130 return builder 131 } 132 133 // WithEnvFlag add env flag to the command 134 func (builder *Builder) WithEnvFlag() *Builder { 135 builder.cmd.PersistentFlags().StringP(flagEnv, "e", "", usageEnv) 136 return builder 137 } 138 139 // ClusterFlagDisableSliceInputOption set the cluster flag to allow multiple input 140 type ClusterFlagDisableSliceInputOption struct{} 141 142 // ApplyToClusterFlagOptions . 143 func (option ClusterFlagDisableSliceInputOption) ApplyToClusterFlagOptions(cfg *ClusterFlagConfig) { 144 cfg.disableSliceInput = true 145 } 146 147 // WithClusterFlag add cluster flag to the command 148 func (builder *Builder) WithClusterFlag(options ...ClusterFlagOption) *Builder { 149 cfg := newClusterFlagOptions(options...) 150 if cfg.disableSliceInput { 151 builder.cmd.Flags().StringP(flagCluster, "c", types.ClusterLocalName, cfg.usage) 152 } else { 153 builder.cmd.Flags().StringSliceP(flagCluster, "c", []string{types.ClusterLocalName}, cfg.usage) 154 } 155 if cfg.completion { 156 cmdutil.CheckErr(builder.cmd.RegisterFlagCompletionFunc( 157 flagCluster, 158 func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 159 return GetClustersForCompletion(cmd.Context(), builder.f, toComplete) 160 })) 161 } 162 return builder 163 } 164 165 // WithStreams set the in/out/err streams for the command 166 func (builder *Builder) WithStreams(streams util.IOStreams) *Builder { 167 builder.cmd.SetIn(streams.In) 168 builder.cmd.SetOut(streams.Out) 169 builder.cmd.SetErr(streams.ErrOut) 170 return builder 171 } 172 173 // WithResponsiveWriter format the command outputs 174 func (builder *Builder) WithResponsiveWriter() *Builder { 175 builder.cmd.SetOut(term.NewResponsiveWriter(builder.cmd.OutOrStdout())) 176 return builder 177 } 178 179 // Build construct the command 180 func (builder *Builder) Build() *cobra.Command { 181 return builder.cmd 182 } 183 184 // NewCommandBuilder builder for command 185 func NewCommandBuilder(f Factory, cmd *cobra.Command) *Builder { 186 return &Builder{cmd: cmd, f: f} 187 }