github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/client/cli/cmd/usage.go (about) 1 package cmd 2 3 import ( 4 "os" 5 "strconv" 6 7 "github.com/moby/term" 8 "github.com/spf13/cobra" 9 "github.com/spf13/pflag" 10 "k8s.io/cli-runtime/pkg/genericclioptions" 11 12 "github.com/telepresenceio/telepresence/v2/pkg/client/cli/global" 13 ) 14 15 var CLIHelpDocumentationURL = "https://www.telepresence.io" //nolint:gochecknoglobals // extension point 16 17 const ( 18 help = `Telepresence can connect to a cluster and route all outbound traffic from your 19 workstation to that cluster so that software running locally can communicate 20 as if it executed remotely, inside the cluster. This is achieved using the 21 command: 22 23 telepresence connect 24 25 Telepresence can also intercept traffic intended for a specific service in a 26 cluster and redirect it to your local workstation: 27 28 telepresence intercept <name of service> 29 30 Telepresence uses background processes to manage the cluster session. One of 31 the processes runs with superuser privileges because it modifies the network. 32 Unless the daemons are already started, an attempt will be made to start them. 33 This will involve a call to sudo unless this command is run as root (not 34 recommended) which in turn may result in a password prompt.` 35 36 usage = `Usage:{{if .Runnable}} 37 {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} 38 {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} 39 40 Aliases: 41 {{.NameAndAliases}}{{end}}{{if .HasExample}} 42 43 Examples: 44 {{.Example}}{{end}}{{if .HasAvailableSubCommands}} 45 46 Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} 47 {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} 48 49 Flags: 50 {{flags . | wrappedFlagUsages | trimTrailingWhitespaces}}{{end}} 51 {{- if hasKubeFlags .}} 52 53 Kubernetes flags: 54 {{kubeFlags | wrappedFlagUsages | trimTrailingWhitespaces}}{{end}} 55 56 Global flags: 57 {{globalFlags . | wrappedFlagUsages | trimTrailingWhitespaces}}{{if .HasHelpSubCommands}} 58 59 Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} 60 {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} 61 62 Use "{{.CommandPath}} [command] --help" for more information about a command. 63 64 For complete documentation and quick-start guides, check out our website at {{ getDocumentationURL }}{{end}} 65 ` 66 ) 67 68 func flagEqual(a, b *pflag.Flag) bool { 69 if a == b { 70 return true 71 } 72 if a == nil || b == nil { 73 return false 74 } 75 return a.Name == b.Name && a.Usage == b.Usage && a.Hidden == b.Hidden 76 } 77 78 func localFlags(cmd *cobra.Command, exclude ...*pflag.FlagSet) *pflag.FlagSet { 79 ngFlags := pflag.NewFlagSet("local", pflag.ContinueOnError) 80 cmd.Flags().VisitAll(func(flag *pflag.Flag) { 81 for _, ex := range exclude { 82 if flagEqual(flag, ex.Lookup(flag.Name)) { 83 return 84 } 85 } 86 ngFlags.AddFlag(flag) 87 }) 88 return ngFlags 89 } 90 91 func kubeFlags() *pflag.FlagSet { 92 pflag.NewFlagSet("Kubernetes flags", 0) 93 kubeConfig := genericclioptions.NewConfigFlags(false) 94 kubeConfig.Namespace = nil // "connect", don't take --namespace 95 flags := pflag.NewFlagSet("Kubernetes flags", 0) 96 kubeConfig.AddFlags(flags) 97 return flags 98 } 99 100 func hasKubeFlags(cmd *cobra.Command) bool { 101 yep := true 102 flags := cmd.Flags() 103 kubeFlags().VisitAll(func(flag *pflag.Flag) { 104 if yep && !flagEqual(flag, flags.Lookup(flag.Name)) { 105 yep = false 106 } 107 }) 108 return yep 109 } 110 111 func addUsageTemplate(cmd *cobra.Command) { 112 cobra.AddTemplateFunc("globalFlags", func(cmd *cobra.Command) *pflag.FlagSet { return global.Flags(hasKubeFlags(cmd)) }) 113 cobra.AddTemplateFunc("flags", func(cmd *cobra.Command) *pflag.FlagSet { 114 return localFlags(cmd, kubeFlags(), global.Flags(hasKubeFlags(cmd))) 115 }) 116 cobra.AddTemplateFunc("hasKubeFlags", hasKubeFlags) 117 cobra.AddTemplateFunc("kubeFlags", kubeFlags) 118 cobra.AddTemplateFunc("wrappedFlagUsages", func(flags *pflag.FlagSet) string { 119 // This is based off of what Docker does (github.com/docker/cli/cli/cobra.go), but is 120 // adjusted 121 // 1. to take a pflag.FlagSet instead of a cobra.interceptCmd, so that we can have flag groups, and 122 // 2. to correct for the ways that Docker upsets me. 123 124 // Obey COLUMNS if the shell or user sets it. (Docker doesn't do this.) 125 cols, err := strconv.Atoi(os.Getenv("COLUMNS")) 126 if err != nil { 127 // Try to detect the size of the stdout file descriptor. (Docker checks stdin, not stdout.) 128 if ws, err := term.GetWinsize(1); err != nil { 129 // If stdout is a terminal, but we were unable to get its size (I'm not sure how that can 130 // happen), then fall back to assuming 80. If stdout isn't a terminal, then we leave cols 131 // as 0, meaning "don't wrap it". (Docker wraps it even if stdout isn't a terminal.) 132 if term.IsTerminal(1) { 133 cols = 80 134 } 135 } else { 136 cols = int(ws.Width) 137 } 138 } 139 return flags.FlagUsagesWrapped(cols) 140 }) 141 cobra.AddTemplateFunc("getDocumentationURL", func() string { 142 return CLIHelpDocumentationURL 143 }) 144 145 // Set a usage template that is derived from the default but replaces the "Available Commands" 146 // section with the commandGroups() from the given command 147 cmd.SetUsageTemplate(usage) 148 }