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  }