k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/genyaml/gen_kubectl_yaml.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 "github.com/spf13/cobra" 27 "github.com/spf13/pflag" 28 "gopkg.in/yaml.v2" 29 "k8s.io/cli-runtime/pkg/genericiooptions" 30 "k8s.io/kubectl/pkg/cmd" 31 "k8s.io/kubernetes/cmd/genutils" 32 ) 33 34 type cmdOption struct { 35 Name string 36 Shorthand string `yaml:",omitempty"` 37 DefaultValue string `yaml:"default_value,omitempty"` 38 Usage string `yaml:",omitempty"` 39 } 40 41 type cmdDoc struct { 42 Name string 43 Synopsis string `yaml:",omitempty"` 44 Description string `yaml:",omitempty"` 45 Options []cmdOption `yaml:",omitempty"` 46 InheritedOptions []cmdOption `yaml:"inherited_options,omitempty"` 47 Example string `yaml:",omitempty"` 48 SeeAlso []string `yaml:"see_also,omitempty"` 49 } 50 51 func main() { 52 path := "docs/yaml/kubectl" 53 if len(os.Args) == 2 { 54 path = os.Args[1] 55 } else if len(os.Args) > 2 { 56 fmt.Fprintf(os.Stderr, "usage: %s [output directory]\n", os.Args[0]) 57 os.Exit(1) 58 } 59 60 outDir, err := genutils.OutDir(path) 61 if err != nil { 62 fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) 63 os.Exit(1) 64 } 65 66 // Set environment variables used by kubectl so the output is consistent, 67 // regardless of where we run. 68 os.Setenv("HOME", "/home/username") 69 kubectl := cmd.NewKubectlCommand(cmd.KubectlOptions{IOStreams: genericiooptions.IOStreams{In: bytes.NewReader(nil), Out: io.Discard, ErrOut: io.Discard}}) 70 genYaml(kubectl, "", outDir) 71 for _, c := range kubectl.Commands() { 72 genYaml(c, "kubectl", outDir) 73 } 74 } 75 76 // Temporary workaround for yaml lib generating incorrect yaml with long strings 77 // that do not contain \n. 78 func forceMultiLine(s string) string { 79 if len(s) > 60 && !strings.Contains(s, "\n") { 80 s = s + "\n" 81 } 82 return s 83 } 84 85 func genFlagResult(flags *pflag.FlagSet) []cmdOption { 86 result := []cmdOption{} 87 88 flags.VisitAll(func(flag *pflag.Flag) { 89 // Todo, when we mark a shorthand is deprecated, but specify an empty message. 90 // The flag.ShorthandDeprecated is empty as the shorthand is deprecated. 91 // Using len(flag.ShorthandDeprecated) > 0 can't handle this, others are ok. 92 if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 { 93 opt := cmdOption{ 94 flag.Name, 95 flag.Shorthand, 96 flag.DefValue, 97 forceMultiLine(flag.Usage), 98 } 99 result = append(result, opt) 100 } else { 101 opt := cmdOption{ 102 Name: flag.Name, 103 DefaultValue: forceMultiLine(flag.DefValue), 104 Usage: forceMultiLine(flag.Usage), 105 } 106 result = append(result, opt) 107 } 108 }) 109 110 return result 111 } 112 113 func genYaml(command *cobra.Command, parent, docsDir string) { 114 doc := cmdDoc{} 115 116 doc.Name = command.Name() 117 doc.Synopsis = forceMultiLine(command.Short) 118 doc.Description = forceMultiLine(command.Long) 119 120 flags := command.NonInheritedFlags() 121 if flags.HasFlags() { 122 doc.Options = genFlagResult(flags) 123 } 124 flags = command.InheritedFlags() 125 if flags.HasFlags() { 126 doc.InheritedOptions = genFlagResult(flags) 127 } 128 129 if len(command.Example) > 0 { 130 doc.Example = command.Example 131 } 132 133 if len(command.Commands()) > 0 || len(parent) > 0 { 134 result := []string{} 135 if len(parent) > 0 { 136 result = append(result, parent) 137 } 138 for _, c := range command.Commands() { 139 result = append(result, c.Name()) 140 } 141 doc.SeeAlso = result 142 } 143 144 final, err := yaml.Marshal(&doc) 145 if err != nil { 146 fmt.Println(err) 147 os.Exit(1) 148 } 149 150 var filename string 151 152 if parent == "" { 153 filename = docsDir + doc.Name + ".yaml" 154 } else { 155 filename = docsDir + parent + "_" + doc.Name + ".yaml" 156 } 157 158 outFile, err := os.Create(filename) 159 if err != nil { 160 fmt.Println(err) 161 os.Exit(1) 162 } 163 defer outFile.Close() 164 _, err = outFile.Write(final) 165 if err != nil { 166 fmt.Println(err) 167 os.Exit(1) 168 } 169 }