github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/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/app/internal/commands" 12 clicommand "github.com/docker/cli/cli/command" 13 "github.com/spf13/cobra" 14 "github.com/spf13/pflag" 15 ) 16 17 const descriptionSourcePath = "docs/reference/" 18 19 func generateCliYaml(opts *options) error { 20 dockerCLI, err := clicommand.NewDockerCli() 21 if err != nil { 22 return err 23 } 24 cmd := &cobra.Command{Use: "docker"} 25 cmd.AddCommand(commands.NewRootCmd("app", 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 if err := loadLongDescription(cmd, path[0], cmd.Name()); err != nil { 62 return err 63 } 64 } 65 66 if _, err := os.Stat(fullpath); err != nil { 67 log.Printf("WARN: %s does not exist, skipping\n", fullpath) 68 continue 69 } 70 71 content, err := ioutil.ReadFile(fullpath) 72 if err != nil { 73 return err 74 } 75 description, examples := parseMDContent(string(content)) 76 cmd.Long = description 77 cmd.Example = examples 78 } 79 return nil 80 } 81 82 type options struct { 83 source string 84 target string 85 } 86 87 func parseArgs() (*options, error) { 88 opts := &options{} 89 cwd, _ := os.Getwd() 90 flags := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError) 91 flags.StringVar(&opts.source, "root", cwd, "Path to project root") 92 flags.StringVar(&opts.target, "target", "/tmp", "Target path for generated yaml files") 93 err := flags.Parse(os.Args[1:]) 94 return opts, err 95 } 96 97 func main() { 98 opts, err := parseArgs() 99 if err != nil { 100 fmt.Fprintln(os.Stderr, err.Error()) 101 } 102 fmt.Printf("Project root: %s\n", opts.source) 103 fmt.Printf("Generating yaml files into %s\n", opts.target) 104 if err := generateCliYaml(opts); err != nil { 105 fmt.Fprintf(os.Stderr, "Failed to generate yaml files: %s\n", err.Error()) 106 } 107 }