k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/genman/gen_kube_man.go (about) 1 /* 2 Copyright 2014 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 main 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 "os" 24 "strings" 25 26 mangen "github.com/cpuguy83/go-md2man/v2/md2man" 27 "github.com/spf13/cobra" 28 "github.com/spf13/pflag" 29 "k8s.io/cli-runtime/pkg/genericiooptions" 30 kubectlcmd "k8s.io/kubectl/pkg/cmd" 31 "k8s.io/kubernetes/cmd/genutils" 32 apiservapp "k8s.io/kubernetes/cmd/kube-apiserver/app" 33 cmapp "k8s.io/kubernetes/cmd/kube-controller-manager/app" 34 proxyapp "k8s.io/kubernetes/cmd/kube-proxy/app" 35 schapp "k8s.io/kubernetes/cmd/kube-scheduler/app" 36 kubeadmapp "k8s.io/kubernetes/cmd/kubeadm/app/cmd" 37 kubeletapp "k8s.io/kubernetes/cmd/kubelet/app" 38 ) 39 40 func main() { 41 // use os.Args instead of "flags" because "flags" will mess up the man pages! 42 path := "docs/man/man1" 43 module := "" 44 if len(os.Args) == 3 { 45 path = os.Args[1] 46 module = os.Args[2] 47 } else { 48 fmt.Fprintf(os.Stderr, "usage: %s [output directory] [module] \n", os.Args[0]) 49 os.Exit(1) 50 } 51 52 outDir, err := genutils.OutDir(path) 53 if err != nil { 54 fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) 55 os.Exit(1) 56 } 57 58 // Set environment variables used by command so the output is consistent, 59 // regardless of where we run. 60 os.Setenv("HOME", "/home/username") 61 62 switch module { 63 case "kube-apiserver": 64 // generate manpage for kube-apiserver 65 apiserver := apiservapp.NewAPIServerCommand() 66 genMarkdown(apiserver, "", outDir) 67 for _, c := range apiserver.Commands() { 68 genMarkdown(c, "kube-apiserver", outDir) 69 } 70 case "kube-controller-manager": 71 // generate manpage for kube-controller-manager 72 controllermanager := cmapp.NewControllerManagerCommand() 73 genMarkdown(controllermanager, "", outDir) 74 for _, c := range controllermanager.Commands() { 75 genMarkdown(c, "kube-controller-manager", outDir) 76 } 77 case "kube-proxy": 78 // generate manpage for kube-proxy 79 proxy := proxyapp.NewProxyCommand() 80 genMarkdown(proxy, "", outDir) 81 for _, c := range proxy.Commands() { 82 genMarkdown(c, "kube-proxy", outDir) 83 } 84 case "kube-scheduler": 85 // generate manpage for kube-scheduler 86 scheduler := schapp.NewSchedulerCommand() 87 genMarkdown(scheduler, "", outDir) 88 for _, c := range scheduler.Commands() { 89 genMarkdown(c, "kube-scheduler", outDir) 90 } 91 case "kubelet": 92 // generate manpage for kubelet 93 kubelet := kubeletapp.NewKubeletCommand() 94 genMarkdown(kubelet, "", outDir) 95 for _, c := range kubelet.Commands() { 96 genMarkdown(c, "kubelet", outDir) 97 } 98 case "kubectl": 99 // generate manpage for kubectl 100 kubectl := kubectlcmd.NewKubectlCommand(kubectlcmd.KubectlOptions{IOStreams: genericiooptions.IOStreams{In: bytes.NewReader(nil), Out: io.Discard, ErrOut: io.Discard}}) 101 genMarkdown(kubectl, "", outDir) 102 for _, c := range kubectl.Commands() { 103 genMarkdown(c, "kubectl", outDir) 104 } 105 case "kubeadm": 106 // generate manpage for kubeadm 107 kubeadm := kubeadmapp.NewKubeadmCommand(bytes.NewReader(nil), io.Discard, io.Discard) 108 genMarkdown(kubeadm, "", outDir) 109 for _, c := range kubeadm.Commands() { 110 genMarkdown(c, "kubeadm", outDir) 111 } 112 default: 113 fmt.Fprintf(os.Stderr, "Module %s is not supported", module) 114 os.Exit(1) 115 } 116 } 117 118 func preamble(out *bytes.Buffer, name, short, long string) { 119 out.WriteString(`% KUBERNETES(1) kubernetes User Manuals 120 % Eric Paris 121 % Jan 2015 122 # NAME 123 `) 124 fmt.Fprintf(out, "%s \\- %s\n\n", name, short) 125 fmt.Fprintf(out, "# SYNOPSIS\n") 126 fmt.Fprintf(out, "**%s** [OPTIONS]\n\n", name) 127 fmt.Fprintf(out, "# DESCRIPTION\n") 128 fmt.Fprintf(out, "%s\n\n", long) 129 } 130 131 func printFlags(out *bytes.Buffer, flags *pflag.FlagSet) { 132 flags.VisitAll(func(flag *pflag.Flag) { 133 format := "**--%s**=%s\n\t%s\n\n" 134 if flag.Value.Type() == "string" { 135 // put quotes on the value 136 format = "**--%s**=%q\n\t%s\n\n" 137 } 138 139 // Todo, when we mark a shorthand is deprecated, but specify an empty message. 140 // The flag.ShorthandDeprecated is empty as the shorthand is deprecated. 141 // Using len(flag.ShorthandDeprecated) > 0 can't handle this, others are ok. 142 if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 { 143 format = "**-%s**, " + format 144 fmt.Fprintf(out, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage) 145 } else { 146 fmt.Fprintf(out, format, flag.Name, flag.DefValue, flag.Usage) 147 } 148 }) 149 } 150 151 func printOptions(out *bytes.Buffer, command *cobra.Command) { 152 flags := command.NonInheritedFlags() 153 if flags.HasFlags() { 154 fmt.Fprintf(out, "# OPTIONS\n") 155 printFlags(out, flags) 156 fmt.Fprintf(out, "\n") 157 } 158 flags = command.InheritedFlags() 159 if flags.HasFlags() { 160 fmt.Fprintf(out, "# OPTIONS INHERITED FROM PARENT COMMANDS\n") 161 printFlags(out, flags) 162 fmt.Fprintf(out, "\n") 163 } 164 } 165 166 func genMarkdown(command *cobra.Command, parent, docsDir string) { 167 dparent := strings.Replace(parent, " ", "-", -1) 168 name := command.Name() 169 dname := name 170 if len(parent) > 0 { 171 dname = dparent + "-" + name 172 name = parent + " " + name 173 } 174 175 out := new(bytes.Buffer) 176 short := command.Short 177 long := command.Long 178 if len(long) == 0 { 179 long = short 180 } 181 182 preamble(out, name, short, long) 183 printOptions(out, command) 184 185 if len(command.Example) > 0 { 186 fmt.Fprintf(out, "# EXAMPLE\n") 187 fmt.Fprintf(out, "```\n%s\n```\n", command.Example) 188 } 189 190 if len(command.Commands()) > 0 || len(parent) > 0 { 191 fmt.Fprintf(out, "# SEE ALSO\n") 192 if len(parent) > 0 { 193 fmt.Fprintf(out, "**%s(1)**, ", dparent) 194 } 195 for _, c := range command.Commands() { 196 fmt.Fprintf(out, "**%s-%s(1)**, ", dname, c.Name()) 197 genMarkdown(c, name, docsDir) 198 } 199 fmt.Fprintf(out, "\n") 200 } 201 202 out.WriteString(` 203 # HISTORY 204 January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since! 205 `) 206 207 final := mangen.Render(out.Bytes()) 208 209 filename := docsDir + dname + ".1" 210 outFile, err := os.Create(filename) 211 if err != nil { 212 fmt.Println(err) 213 os.Exit(1) 214 } 215 defer outFile.Close() 216 _, err = outFile.Write(final) 217 if err != nil { 218 fmt.Println(err) 219 os.Exit(1) 220 } 221 222 }