github.com/itscaro/cli@v0.0.0-20190705081621-c9db0fe93829/docs/yaml/generate.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "path/filepath" 9 "strings" 10 11 "github.com/docker/cli/cli/command" 12 "github.com/docker/cli/cli/command/commands" 13 "github.com/spf13/cobra" 14 "github.com/spf13/pflag" 15 ) 16 17 const descriptionSourcePath = "docs/reference/commandline/" 18 19 func generateCliYaml(opts *options) error { 20 dockerCli, err := command.NewDockerCli() 21 if err != nil { 22 return err 23 } 24 cmd := &cobra.Command{Use: "docker"} 25 commands.AddCommands(cmd, dockerCli) 26 disableFlagsInUseLine(cmd) 27 source := filepath.Join(opts.source, descriptionSourcePath) 28 if err := loadLongDescription(cmd, source); err != nil { 29 return err 30 } 31 32 cmd.DisableAutoGenTag = true 33 return GenYamlTree(cmd, opts.target) 34 } 35 36 func disableFlagsInUseLine(cmd *cobra.Command) { 37 visitAll(cmd, func(ccmd *cobra.Command) { 38 // do not add a `[flags]` to the end of the usage line. 39 ccmd.DisableFlagsInUseLine = true 40 }) 41 } 42 43 // visitAll will traverse all commands from the root. 44 // This is different from the VisitAll of cobra.Command where only parents 45 // are checked. 46 func visitAll(root *cobra.Command, fn func(*cobra.Command)) { 47 for _, cmd := range root.Commands() { 48 visitAll(cmd, fn) 49 } 50 fn(root) 51 } 52 53 func loadLongDescription(cmd *cobra.Command, path ...string) error { 54 for _, cmd := range cmd.Commands() { 55 if cmd.Name() == "" { 56 continue 57 } 58 fullpath := filepath.Join(path[0], strings.Join(append(path[1:], cmd.Name()), "_")+".md") 59 60 if cmd.HasSubCommands() { 61 loadLongDescription(cmd, path[0], cmd.Name()) 62 } 63 64 if _, err := os.Stat(fullpath); err != nil { 65 log.Printf("WARN: %s does not exist, skipping\n", fullpath) 66 continue 67 } 68 69 content, err := ioutil.ReadFile(fullpath) 70 if err != nil { 71 return err 72 } 73 description, examples := parseMDContent(string(content)) 74 cmd.Long = description 75 cmd.Example = examples 76 } 77 return nil 78 } 79 80 type options struct { 81 source string 82 target string 83 } 84 85 func parseArgs() (*options, error) { 86 opts := &options{} 87 cwd, _ := os.Getwd() 88 flags := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError) 89 flags.StringVar(&opts.source, "root", cwd, "Path to project root") 90 flags.StringVar(&opts.target, "target", "/tmp", "Target path for generated yaml files") 91 err := flags.Parse(os.Args[1:]) 92 return opts, err 93 } 94 95 func main() { 96 opts, err := parseArgs() 97 if err != nil { 98 fmt.Fprintln(os.Stderr, err.Error()) 99 } 100 fmt.Printf("Project root: %s\n", opts.source) 101 fmt.Printf("Generating yaml files into %s\n", opts.target) 102 if err := generateCliYaml(opts); err != nil { 103 fmt.Fprintf(os.Stderr, "Failed to generate yaml files: %s\n", err.Error()) 104 } 105 }