// GenManTree will generate a man page for this command and all decendants // in the directory given. The header may be nil. This function may not work // correctly if your command names have - in them. If you have `cmd` with two // subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third` // it is undefined which help output will be in the file `cmd-sub-third.1`. func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) { if header == nil { header = &GenManHeader{} } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } GenManTree(c, header, dir) } out := new(bytes.Buffer) needToResetTitle := header.Title == "" GenMan(cmd, header, out) if needToResetTitle { header.Title = "" } filename := cmd.CommandPath() filename = dir + strings.Replace(filename, " ", "-", -1) + ".1" outFile, err := os.Create(filename) if err != nil { fmt.Println(err) os.Exit(1) } defer outFile.Close() _, err = outFile.Write(out.Bytes()) if err != nil { fmt.Println(err) os.Exit(1) } }
// Parse the Commands func NewSubCommands(c *cobra.Command, path string) Commands { subCommands := Commands{NewCommand(c, path+c.Name())} for _, subCommand := range c.Commands() { subCommands = append(subCommands, NewSubCommands(subCommand, path+c.Name()+" ")...) } return subCommands }
func genMarkdown(command *cobra.Command, parent, docsDir string) { dparent := strings.Replace(parent, " ", "-", -1) name := command.Name() dname := name if len(parent) > 0 { dname = dparent + "-" + name name = parent + " " + name } out := new(bytes.Buffer) short := command.Short long := command.Long if len(long) == 0 { long = short } fmt.Fprintf(out, "## %s\n\n", name) fmt.Fprintf(out, "%s\n\n", short) fmt.Fprintf(out, "### Synopsis\n\n") fmt.Fprintf(out, "\n%s\n\n", long) if command.Runnable() { fmt.Fprintf(out, "```\n%s\n```\n\n", command.UseLine()) } if len(command.Example) > 0 { fmt.Fprintf(out, "### Examples\n\n") fmt.Fprintf(out, "```\n%s\n```\n\n", command.Example) } printOptions(out, command, name) if len(command.Commands()) > 0 || len(parent) > 0 { fmt.Fprintf(out, "### SEE ALSO\n") if len(parent) > 0 { link := dparent + ".md" fmt.Fprintf(out, "* [%s](%s)\n", dparent, link) } for _, c := range command.Commands() { child := dname + "-" + c.Name() link := child + ".md" fmt.Fprintf(out, "* [%s](%s)\n", child, link) genMarkdown(c, name, docsDir) } fmt.Fprintf(out, "\n") } filename := docsDir + dname + ".md" outFile, err := os.Create(filename) if err != nil { fmt.Println(err) os.Exit(1) } defer outFile.Close() _, err = outFile.Write(out.Bytes()) if err != nil { fmt.Println(err) os.Exit(1) } }
func genCmdMan(cmdName string, cmd *cobra.Command) { // use os.Args instead of "flags" because "flags" will mess up the man pages! path := "docs/man/" + cmdName if len(os.Args) == 3 { path = os.Args[1] } else if len(os.Args) > 3 { fmt.Fprintf(os.Stderr, "usage: %s [output directory]\n", os.Args[0]) os.Exit(1) } outDir, err := genutils.OutDir(path) if err != nil { fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err) os.Exit(1) } // Set environment variables used by openshift so the output is consistent, // regardless of where we run. os.Setenv("HOME", "/home/username") // TODO os.Stdin should really be something like ioutil.Discard, but a Reader genMarkdown(cmd, "", outDir) for _, c := range cmd.Commands() { genMarkdown(c, cmdName, outDir) } }
func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string, linkHandler func(string) string) { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler) } out := new(bytes.Buffer) GenMarkdownCustom(cmd, out, linkHandler) filename := cmd.CommandPath() filename = dir + strings.Replace(filename, " ", "_", -1) + ".md" outFile, err := os.Create(filename) if err != nil { fmt.Println(err) os.Exit(1) } defer outFile.Close() _, err = outFile.WriteString(filePrepender(filename)) if err != nil { fmt.Println(err) os.Exit(1) } _, err = outFile.Write(out.Bytes()) if err != nil { fmt.Println(err) os.Exit(1) } }
func collectFlags(v *viper.Viper, cmd *cobra.Command) { v.BindPFlags(cmd.PersistentFlags()) v.BindPFlags(cmd.Flags()) for _, cmd := range cmd.Commands() { collectFlags(v, cmd) } }
func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil { return err } } basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".md" filename := filepath.Join(dir, basename) f, err := os.Create(filename) if err != nil { return err } defer f.Close() if _, err := io.WriteString(f, filePrepender(filename)); err != nil { return err } if err := GenMarkdownCustom(cmd, f, linkHandler); err != nil { return err } return nil }
func CheckCmdTree(cmd *cobra.Command, checks []CmdCheck, skip []string) []error { cmdPath := cmd.CommandPath() for _, skipCmdPath := range skip { if cmdPath == skipCmdPath { fmt.Fprintf(os.Stdout, "-----+ skipping command %s\n", cmdPath) return []error{} } } errors := []error{} if cmd.HasSubCommands() { for _, subCmd := range cmd.Commands() { errors = append(errors, CheckCmdTree(subCmd, checks, skip)...) } } fmt.Fprintf(os.Stdout, "-----+ checking command %s\n", cmdPath) for _, check := range checks { if err := check(cmd); err != nil && len(err) > 0 { errors = append(errors, err...) } } return errors }
func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) { cmd.Flags().VisitAll(func(f *pflag.Flag) { // hide experimental flags if !hasExperimental { if _, ok := f.Annotations["experimental"]; ok { f.Hidden = true } } // hide flags not supported by the server if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) { f.Hidden = true } }) for _, subcmd := range cmd.Commands() { // hide experimental subcommands if !hasExperimental { if _, ok := subcmd.Tags["experimental"]; ok { subcmd.Hidden = true } } // hide subcommands not supported by the server if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) { subcmd.Hidden = true } } }
// Namespace enables namespacing for a sub-commmand and its immediated children. It returns an error if the command does not have a parent. func (n *CobraNamespace) Namespace(cmd *cobra.Command) error { if !cmd.HasParent() { return errors.New("cmdns: command requires a parent") } // Do not bind if there are not available sub commands if !cmd.HasAvailableSubCommands() { return nil } if n.OverrideUsageFunc { cmd.SetUsageFunc(n.UsageFunc()) } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() { continue } // copy the command add it to the root command with a prefix of its parent. nc := *c nc.Use = cmd.Name() + DefaultNamespaceSeparator + c.Use // add this command to the root and hide it so it does not show in available commands list c.Parent().Parent().AddCommand(&nc) c.Hidden = true n.commands = append(n.commands, &nc) } n.cmd = cmd return nil }
// ReplaceCommandName recursively processes the examples in a given command to change a hardcoded // command name (like 'kubectl' to the appropriate target name). It returns c. func ReplaceCommandName(from, to string, c *cobra.Command) *cobra.Command { c.Example = strings.Replace(c.Example, from, to, -1) for _, sub := range c.Commands() { ReplaceCommandName(from, to, sub) } return c }
// GenManTree will generate a man page for this command and all descendants // in the directory given. The header may be nil. This function may not work // correctly if your command names have - in them. If you have `cmd` with two // subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third` // it is undefined which help output will be in the file `cmd-sub-third.1`. func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { if header == nil { header = &GenManHeader{} } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } if err := GenManTree(c, header, dir); err != nil { return err } } needToResetTitle := header.Title == "" basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".1" filename := filepath.Join(dir, basename) f, err := os.Create(filename) if err != nil { return err } defer f.Close() if err := GenMan(cmd, header, f); err != nil { return err } if needToResetTitle { header.Title = "" } return nil }
// GenManTreeFromOpts generates a man page for the command and all descendants. // The pages are written to the opts.Path directory. func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { header := opts.Header if header == nil { header = &GenManHeader{} } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } if err := GenManTreeFromOpts(c, opts); err != nil { return err } } section := "1" if header.Section != "" { section = header.Section } separator := "_" if opts.CommandSeparator != "" { separator = opts.CommandSeparator } basename := strings.Replace(cmd.CommandPath(), " ", separator, -1) filename := filepath.Join(opts.Path, basename+"."+section) f, err := os.Create(filename) if err != nil { return err } defer f.Close() headerCopy := *header return GenMan(cmd, &headerCopy, f) }
func genMarkdown(command *cobra.Command, parent, docsDir string) { dparent := strings.Replace(parent, " ", "-", -1) name := command.Name() dname := name cmdName := name if len(parent) > 0 { dname = dparent + "-" + name name = parent + " " + name cmdName = parent } out := new(bytes.Buffer) short := command.Short long := command.Long if len(long) == 0 { long = short } preamble(out, cmdName, name, short, long) printOptions(out, command) if len(command.Example) > 0 { fmt.Fprintf(out, "# EXAMPLE\n") fmt.Fprintf(out, "```\n%s\n```\n", command.Example) } if len(command.Commands()) > 0 || len(parent) > 0 { fmt.Fprintf(out, "# SEE ALSO\n") if len(parent) > 0 { fmt.Fprintf(out, "**%s(1)**, ", dparent) } for _, c := range command.Commands() { fmt.Fprintf(out, "**%s-%s(1)**, ", dname, c.Name()) genMarkdown(c, name, docsDir) } fmt.Fprintf(out, "\n") } out.WriteString(` # HISTORY June 2016, Ported from the Kubernetes man-doc generator `) final := mangen.Render(out.Bytes()) filename := docsDir + dname + ".1" outFile, err := os.Create(filename) if err != nil { fmt.Println(err) os.Exit(1) } defer outFile.Close() _, err = outFile.Write(final) if err != nil { fmt.Println(err) os.Exit(1) } }
func getSubCommands(cCmd *cobra.Command) []*cobra.Command { var subCommands []*cobra.Command for _, subCmd := range cCmd.Commands() { subCommands = append(subCommands, subCmd) subCommands = append(subCommands, getSubCommands(subCmd)...) } return subCommands }
func genMarkdown(command *cobra.Command, parent, docsDir string) { dparent := strings.Replace(parent, " ", "-", -1) name := command.Name() dname := name if len(parent) > 0 { dname = dparent + "-" + name name = parent + " " + name } out := new(bytes.Buffer) short := command.Short long := command.Long if len(long) == 0 { long = short } preamble(out, name, short, long) printOptions(out, command) if len(command.Example) > 0 { fmt.Fprintf(out, "# EXAMPLE\n") fmt.Fprintf(out, "```\n%s\n```\n", command.Example) } if len(command.Commands()) > 0 || len(parent) > 0 { fmt.Fprintf(out, "# SEE ALSO\n") if len(parent) > 0 { fmt.Fprintf(out, "**%s(1)**, ", dparent) } for _, c := range command.Commands() { fmt.Fprintf(out, "**%s-%s(1)**, ", dname, c.Name()) genMarkdown(c, name, docsDir) } fmt.Fprintf(out, "\n") } out.WriteString(` # HISTORY January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since! `) final := mangen.Render(out.Bytes()) filename := docsDir + dname + ".1" outFile, err := os.Create(filename) if err != nil { fmt.Println(err) os.Exit(1) } defer outFile.Close() _, err = outFile.Write(final) if err != nil { fmt.Println(err) os.Exit(1) } }
func GenMarkdownCustom(cmd *cobra.Command, out io.Writer, linkHandler func(string) string) { name := cmd.CommandPath() short := cmd.Short long := cmd.Long if len(long) == 0 { long = short } fmt.Fprintf(out, "## %s\n\n", name) fmt.Fprintf(out, "%s\n\n", short) fmt.Fprintf(out, "### Synopsis\n\n") fmt.Fprintf(out, "\n%s\n\n", long) if cmd.Runnable() { fmt.Fprintf(out, "```\n%s\n```\n\n", cmd.UseLine()) } if len(cmd.Example) > 0 { fmt.Fprintf(out, "### Examples\n\n") fmt.Fprintf(out, "```\n%s\n```\n\n", cmd.Example) } printOptions(out, cmd, name) if hasSeeAlso(cmd) { fmt.Fprintf(out, "### SEE ALSO\n") if cmd.HasParent() { parent := cmd.Parent() pname := parent.CommandPath() link := pname + ".md" link = strings.Replace(link, " ", "_", -1) fmt.Fprintf(out, "* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short) cmd.VisitParents(func(c *cobra.Command) { if c.DisableAutoGenTag { cmd.DisableAutoGenTag = c.DisableAutoGenTag } }) } children := cmd.Commands() sort.Sort(byName(children)) for _, child := range children { if !child.IsAvailableCommand() || child.IsHelpCommand() { continue } cname := name + " " + child.Name() link := cname + ".md" link = strings.Replace(link, " ", "_", -1) fmt.Fprintf(out, "* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short) } fmt.Fprintf(out, "\n") } if !cmd.DisableAutoGenTag { fmt.Fprintf(out, "###### Auto generated by spf13/cobra on %s\n", time.Now().Format("2-Jan-2006")) } }
// NormalizeAll perform all required normalizations in the entire command tree. func NormalizeAll(cmd *cobra.Command) *cobra.Command { if cmd.HasSubCommands() { for _, subCmd := range cmd.Commands() { NormalizeAll(subCmd) } } Normalize(cmd) return cmd }
func managementSubCommands(cmd *cobra.Command) []*cobra.Command { cmds := []*cobra.Command{} for _, sub := range cmd.Commands() { if sub.IsAvailableCommand() && sub.HasSubCommands() { cmds = append(cmds, sub) } } return cmds }
func genYaml(command *cobra.Command, parent, docsDir string) { doc := cmdDoc{} doc.Name = command.Name() doc.Synopsis = forceMultiLine(command.Short) doc.Description = forceMultiLine(command.Long) flags := command.NonInheritedFlags() if flags.HasFlags() { doc.Options = genFlagResult(flags) } flags = command.InheritedFlags() if flags.HasFlags() { doc.InheritedOptions = genFlagResult(flags) } if len(command.Example) > 0 { doc.Example = command.Example } if len(command.Commands()) > 0 || len(parent) > 0 { result := make([]string, 0) if len(parent) > 0 { result = append(result, parent) } for _, c := range command.Commands() { result = append(result, c.Name()) } doc.SeeAlso = result } final, err := yaml.Marshal(&doc) if err != nil { fmt.Println(err) os.Exit(1) } var filename string if parent == "" { filename = docsDir + doc.Name + ".yaml" } else { filename = docsDir + parent + "_" + doc.Name + ".yaml" } outFile, err := os.Create(filename) if err != nil { fmt.Println(err) os.Exit(1) } defer outFile.Close() _, err = outFile.Write(final) if err != nil { fmt.Println(err) os.Exit(1) } }
func NewTopLevelCommand(c *cobra.Command) TopLevelCommand { result := TopLevelCommand{ MainCommand: NewCommand(c, ""), } for _, sub := range c.Commands() { result.SubCommands = append(result.SubCommands, NewSubCommands(sub, "")...) } sort.Sort(result.SubCommands) return result }
func genCmdList(cmd *cobra.Command) (cmds []*cobra.Command) { cmds = append(cmds, cmd) for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } cmds = append(cmds, genCmdList(c)...) } return cmds }
func ensureLocalFlagOnChildren(t *testing.T, c *cobra.Command, prefix string) { for _, cmd := range c.Commands() { name := prefix + cmd.Name() if localFlagExceptions.Has(name) { continue } if localFlag := cmd.Flag("local"); localFlag == nil { t.Errorf("Command %s does not implement the --local flag", name) } ensureLocalFlagOnChildren(t, cmd, name+".") } }
// Test to see if we have a reason to print See Also information in docs // Basically this is a test for a parent commend or a subcommand which is // both not deprecated and not the autogenerated help command. func hasSeeAlso(cmd *cobra.Command) bool { if cmd.HasParent() { return true } for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } return true } return false }
func ensureLocalAndDryRunFlagsOnChildren(t *testing.T, c *cobra.Command, prefix string) { for _, cmd := range c.Commands() { name := prefix + cmd.Name() if localFlag := cmd.Flag("local"); localFlag == nil { t.Errorf("Command %s does not implement the --local flag", name) } if dryRunFlag := cmd.Flag("dry-run"); dryRunFlag == nil { t.Errorf("Command %s does not implement the --dry-run flag", name) } ensureLocalAndDryRunFlagsOnChildren(t, cmd, name+".") } }
func genMan(cmd *cobra.Command, header *GenManHeader) []byte { // something like `rootcmd subcmd1 subcmd2` commandName := cmd.CommandPath() // something like `rootcmd-subcmd1-subcmd2` dashCommandName := strings.Replace(commandName, " ", "-", -1) fillHeader(header, commandName) buf := new(bytes.Buffer) short := cmd.Short long := cmd.Long if len(long) == 0 { long = short } manPreamble(buf, header, commandName, short, long) manPrintOptions(buf, cmd) if len(cmd.Example) > 0 { fmt.Fprintf(buf, "# EXAMPLE\n") fmt.Fprintf(buf, "```\n%s\n```\n", cmd.Example) } if hasSeeAlso(cmd) { fmt.Fprintf(buf, "# SEE ALSO\n") seealsos := make([]string, 0) if cmd.HasParent() { parentPath := cmd.Parent().CommandPath() dashParentPath := strings.Replace(parentPath, " ", "-", -1) seealso := fmt.Sprintf("**%s(%s)**", dashParentPath, header.Section) seealsos = append(seealsos, seealso) cmd.VisitParents(func(c *cobra.Command) { if c.DisableAutoGenTag { cmd.DisableAutoGenTag = c.DisableAutoGenTag } }) } children := cmd.Commands() sort.Sort(byName(children)) for _, c := range children { if !c.IsAvailableCommand() || c.IsHelpCommand() { continue } seealso := fmt.Sprintf("**%s-%s(%s)**", dashCommandName, c.Name(), header.Section) seealsos = append(seealsos, seealso) } fmt.Fprintf(buf, "%s\n", strings.Join(seealsos, ", ")) } if !cmd.DisableAutoGenTag { fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006")) } return buf.Bytes() }
func adjustCmdExamples(cmd *cobra.Command, parentName string, name string) { for _, subCmd := range cmd.Commands() { adjustCmdExamples(subCmd, parentName, cmd.Name()) } cmd.Example = strings.Replace(cmd.Example, "kubectl", parentName, -1) tabbing := " " examples := []string{} scanner := bufio.NewScanner(strings.NewReader(cmd.Example)) for scanner.Scan() { examples = append(examples, tabbing+strings.TrimSpace(scanner.Text())) } cmd.Example = strings.Join(examples, "\n") }
func commands(cmd *cobra.Command) []*cobra.Command { if cmd.HasParent() { return cmd.Commands() } cArr := []*cobra.Command{} for _, c := range cmd.Commands() { if m, _ := rx.MatchString("((re)?start)|stop|status|((un)?install)", c.Name()); !m { cArr = append(cArr, c) } } return cArr }
func (t *templater) cmdGroupsString(c *cobra.Command) string { groups := []string{} for _, cmdGroup := range t.cmdGroups(c, c.Commands()) { cmds := []string{cmdGroup.Message} for _, cmd := range cmdGroup.Commands { if cmd.Runnable() { cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short) } } groups = append(groups, strings.Join(cmds, "\n")) } return strings.Join(groups, "\n\n") }
// Namespace enables namespacing for the command's subcommands func (c *CobraNamespacer) Namespace(cmd *cobra.Command) error { if cmd == nil { return errors.New("cmdns: cmd cannot be nil") } for _, child := range cmd.Commands() { n := NewCobraNamespace() n.OverrideUsageFunc = c.OverrideUsageFunc c.Namespaces = append(c.Namespaces, n) if err := n.Namespace(child); err != nil { return err } } return nil }