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  }