mirror of
https://github.com/spf13/cobra
synced 2025-05-02 19:37:22 +00:00
Generated Documentation
This commit is contained in:
parent
16f7019823
commit
ea92b272f6
2 changed files with 66 additions and 173 deletions
|
@ -30,11 +30,15 @@ import (
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenManTree will generate a man page for this command and all descendants
|
// GenManTree generates a man page for the provided command and all its descendants in the specified directory.
|
||||||
// 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
|
// It takes a cobra.Command pointer representing the root command, an optional GenManHeader pointer to customize the header information, and a string specifying the output directory.
|
||||||
// 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`.
|
// The function assumes that command names do not contain hyphens (`-`). If they do, unexpected behavior may occur.
|
||||||
|
//
|
||||||
|
// Note: If a command named `cmd` has subcommands `sub` and `sub-third`, and `sub` itself has a subcommand called `third`, it is undefined which help output will be written to the file `cmd-sub-third.1`.
|
||||||
|
//
|
||||||
|
// Returns an error if the generation process encounters any issues, such as invalid input or permission errors when writing files to the specified directory.
|
||||||
func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
|
func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
|
||||||
return GenManTreeFromOpts(cmd, GenManTreeOptions{
|
return GenManTreeFromOpts(cmd, GenManTreeOptions{
|
||||||
Header: header,
|
Header: header,
|
||||||
|
@ -44,7 +48,15 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenManTreeFromOpts generates a man page for the command and all descendants.
|
// GenManTreeFromOpts generates a man page for the command and all descendants.
|
||||||
// The pages are written to the opts.Path directory.
|
// The pages are written to the opts.Path directory. It recursively processes each command in the tree,
|
||||||
|
// skipping non-available or additional help topic commands. Each man page is saved with a filename based on the command path and section.
|
||||||
|
|
||||||
|
// Parameters:
|
||||||
|
// - cmd: A pointer to the root cobra.Command for which man pages need to be generated.
|
||||||
|
// - opts: A GenManTreeOptions struct containing options for generating the man pages, such as header details, output directory, and separators.
|
||||||
|
|
||||||
|
// Returns:
|
||||||
|
// - error: If any error occurs during the generation of the man pages, it is returned.
|
||||||
func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error {
|
func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error {
|
||||||
header := opts.Header
|
header := opts.Header
|
||||||
if header == nil {
|
if header == nil {
|
||||||
|
@ -100,8 +112,15 @@ type GenManHeader struct {
|
||||||
Manual string
|
Manual string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenMan will generate a man page for the given command and write it to
|
// GenMan generates a man page for the given command and writes it to the specified writer.
|
||||||
// w. The header argument may be nil, however obviously w may not.
|
//
|
||||||
|
// Parameters:
|
||||||
|
// cmd - The cobra.Command for which to generate the man page.
|
||||||
|
// header - A pointer to a GenManHeader that contains additional information for the man page. If nil, a default header will be used.
|
||||||
|
// w - The io.Writer to which the generated man page will be written.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// error - If an error occurs during the generation of the man page, it will be returned here.
|
||||||
func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
|
func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
header = &GenManHeader{}
|
header = &GenManHeader{}
|
||||||
|
@ -115,6 +134,15 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fillHeader populates the GenManHeader with default values if they are not already set.
|
||||||
|
//
|
||||||
|
// It sets the title to the uppercase version of `name`, replacing spaces with hyphens.
|
||||||
|
// If the section is empty, it defaults to "1".
|
||||||
|
// If the date is nil, it sets the date to the current time or a time specified by the SOURCE_DATE_EPOCH environment variable.
|
||||||
|
// The formatted date is stored in header.date.
|
||||||
|
// If source is empty and auto-generation is not disabled, it sets the source to "Auto generated by spf13/cobra".
|
||||||
|
//
|
||||||
|
// It returns an error if there is an issue parsing the SOURCE_DATE_EPOCH environment variable.
|
||||||
func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error {
|
func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error {
|
||||||
if header.Title == "" {
|
if header.Title == "" {
|
||||||
header.Title = strings.ToUpper(strings.ReplaceAll(name, " ", "\\-"))
|
header.Title = strings.ToUpper(strings.ReplaceAll(name, " ", "\\-"))
|
||||||
|
@ -140,6 +168,17 @@ func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// manPreamble writes the preamble for a manual page to the given buffer.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// buf - the io.StringWriter to write the preamble to.
|
||||||
|
// header - a pointer to a GenManHeader containing metadata for the manual page.
|
||||||
|
// cmd - a pointer to a cobra.Command representing the command being documented.
|
||||||
|
// dashedName - the dash-separated name of the command.
|
||||||
|
//
|
||||||
|
// This function constructs the preamble section of a man page, including
|
||||||
|
// the title, section, date, source, and manual. It also includes the command's
|
||||||
|
// short description and synopsis.
|
||||||
func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, dashedName string) {
|
func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, dashedName string) {
|
||||||
description := cmd.Long
|
description := cmd.Long
|
||||||
if len(description) == 0 {
|
if len(description) == 0 {
|
||||||
|
@ -156,6 +195,12 @@ func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command,
|
||||||
cobra.WriteStringAndCheck(buf, description+"\n\n")
|
cobra.WriteStringAndCheck(buf, description+"\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// manPrintFlags prints the flags in a format suitable for a man page.
|
||||||
|
//
|
||||||
|
// It takes an io.StringWriter to write to and a pflag.FlagSet containing the flags to print.
|
||||||
|
// For each flag, it checks if it is deprecated or hidden. If not, it formats the flag name,
|
||||||
|
// shorthand, and usage information according to its type (string or other) and whether it has
|
||||||
|
// a default value. The formatted string is then written to the provided writer.
|
||||||
func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) {
|
func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) {
|
||||||
flags.VisitAll(func(flag *pflag.Flag) {
|
flags.VisitAll(func(flag *pflag.Flag) {
|
||||||
if len(flag.Deprecated) > 0 || flag.Hidden {
|
if len(flag.Deprecated) > 0 || flag.Hidden {
|
||||||
|
@ -184,6 +229,8 @@ func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// manPrintOptions writes the options for a command to a StringWriter.
|
||||||
|
// It includes both non-inherited and inherited flags, if available.
|
||||||
func manPrintOptions(buf io.StringWriter, command *cobra.Command) {
|
func manPrintOptions(buf io.StringWriter, command *cobra.Command) {
|
||||||
flags := command.NonInheritedFlags()
|
flags := command.NonInheritedFlags()
|
||||||
if flags.HasAvailableFlags() {
|
if flags.HasAvailableFlags() {
|
||||||
|
@ -199,6 +246,17 @@ func manPrintOptions(buf io.StringWriter, command *cobra.Command) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// genMan generates a man page for the given Cobra command and header.
|
||||||
|
// It initializes default help commands and flags, processes the command path,
|
||||||
|
// and constructs the man page content including preamble, options, examples,
|
||||||
|
// see also sections, and history.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// - cmd: The Cobra command for which to generate the man page.
|
||||||
|
// - header: Header information for the man page, such as section and date.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// - A byte slice containing the generated man page content.
|
||||||
func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
|
func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
|
||||||
cmd.InitDefaultHelpCmd()
|
cmd.InitDefaultHelpCmd()
|
||||||
cmd.InitDefaultHelpFlag()
|
cmd.InitDefaultHelpFlag()
|
||||||
|
|
|
@ -1,165 +0,0 @@
|
||||||
// Copyright 2013-2023 The Cobra Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package cobra
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestCompleteNoDesCmdInFishScript tests the completion functionality for a command without descriptions in a Fish shell script.
|
|
||||||
//
|
|
||||||
// It sets up a root command and a child command, adds the child to the root, generates Fish completion script,
|
|
||||||
// and checks if the output contains the expected completion information without descriptions.
|
|
||||||
func TestCompleteNoDesCmdInFishScript(t *testing.T) {
|
|
||||||
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
|
||||||
child := &Command{
|
|
||||||
Use: "child",
|
|
||||||
ValidArgsFunction: validArgsFunc,
|
|
||||||
Run: emptyRun,
|
|
||||||
}
|
|
||||||
rootCmd.AddCommand(child)
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
|
|
||||||
output := buf.String()
|
|
||||||
|
|
||||||
check(t, output, ShellCompNoDescRequestCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestCompleteCmdInFishScript tests the generation of fish completion script for a command.
|
|
||||||
func TestCompleteCmdInFishScript(t *testing.T) {
|
|
||||||
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
|
||||||
child := &Command{
|
|
||||||
Use: "child",
|
|
||||||
ValidArgsFunction: validArgsFunc,
|
|
||||||
Run: emptyRun,
|
|
||||||
}
|
|
||||||
rootCmd.AddCommand(child)
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, true))
|
|
||||||
output := buf.String()
|
|
||||||
|
|
||||||
check(t, output, ShellCompRequestCmd)
|
|
||||||
checkOmit(t, output, ShellCompNoDescRequestCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestProgWithDash tests the generation of fish completion for a command with a hyphen in its name.
|
|
||||||
// It verifies that the hyphen is replaced in function names but remains intact in the command name.
|
|
||||||
func TestProgWithDash(t *testing.T) {
|
|
||||||
rootCmd := &Command{Use: "root-dash", Args: NoArgs, Run: emptyRun}
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
|
|
||||||
output := buf.String()
|
|
||||||
|
|
||||||
// Functions name should have replace the '-'
|
|
||||||
check(t, output, "__root_dash_perform_completion")
|
|
||||||
checkOmit(t, output, "__root-dash_perform_completion")
|
|
||||||
|
|
||||||
// The command name should not have replaced the '-'
|
|
||||||
check(t, output, "-c root-dash")
|
|
||||||
checkOmit(t, output, "-c root_dash")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestProgWithColon tests the generation of Fish completion for a command with a colon in its name.
|
|
||||||
func TestProgWithColon(t *testing.T) {
|
|
||||||
rootCmd := &Command{Use: "root:colon", Args: NoArgs, Run: emptyRun}
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
|
|
||||||
output := buf.String()
|
|
||||||
|
|
||||||
// Functions name should have replace the ':'
|
|
||||||
check(t, output, "__root_colon_perform_completion")
|
|
||||||
checkOmit(t, output, "__root:colon_perform_completion")
|
|
||||||
|
|
||||||
// The command name should not have replaced the ':'
|
|
||||||
check(t, output, "-c root:colon")
|
|
||||||
checkOmit(t, output, "-c root_colon")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestFishCompletionNoActiveHelp tests the generation of Fish completion script without active help enabled.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - t: A testing.T instance for assertions and logging.
|
|
||||||
//
|
|
||||||
// The function creates a new Command, generates its Fish completion script with active help disabled,
|
|
||||||
// and asserts that the output does not include an active help variable set to 1.
|
|
||||||
func TestFishCompletionNoActiveHelp(t *testing.T) {
|
|
||||||
c := &Command{Use: "c", Run: emptyRun}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
assertNoErr(t, c.GenFishCompletion(buf, true))
|
|
||||||
output := buf.String()
|
|
||||||
|
|
||||||
// check that active help is being disabled
|
|
||||||
activeHelpVar := activeHelpEnvVar(c.Name())
|
|
||||||
check(t, output, fmt.Sprintf("%s=0", activeHelpVar))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGenFishCompletionFile tests the generation of a Fish completion file for a Cobra command.
|
|
||||||
// It creates a temporary file, sets up a Cobra command hierarchy, and asserts that no errors occur during the completion file generation process.
|
|
||||||
func TestGenFishCompletionFile(t *testing.T) {
|
|
||||||
tmpFile, err := os.CreateTemp("", "cobra-test")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
defer os.Remove(tmpFile.Name())
|
|
||||||
|
|
||||||
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
|
||||||
child := &Command{
|
|
||||||
Use: "child",
|
|
||||||
ValidArgsFunction: validArgsFunc,
|
|
||||||
Run: emptyRun,
|
|
||||||
}
|
|
||||||
rootCmd.AddCommand(child)
|
|
||||||
|
|
||||||
assertNoErr(t, rootCmd.GenFishCompletionFile(tmpFile.Name(), false))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestFailGenFishCompletionFile tests the GenFishCompletionFile method for permission errors.
|
|
||||||
//
|
|
||||||
// It creates a temporary directory and file, sets up a command structure,
|
|
||||||
// and attempts to generate Fish completion file. It checks if the error returned
|
|
||||||
// matches os.ErrPermission as expected. If not, it fails the test with an error message.
|
|
||||||
func TestFailGenFishCompletionFile(t *testing.T) {
|
|
||||||
tmpDir, err := os.MkdirTemp("", "cobra-test")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
defer os.RemoveAll(tmpDir)
|
|
||||||
|
|
||||||
f, _ := os.OpenFile(filepath.Join(tmpDir, "test"), os.O_CREATE, 0400)
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
|
||||||
child := &Command{
|
|
||||||
Use: "child",
|
|
||||||
ValidArgsFunction: validArgsFunc,
|
|
||||||
Run: emptyRun,
|
|
||||||
}
|
|
||||||
rootCmd.AddCommand(child)
|
|
||||||
|
|
||||||
got := rootCmd.GenFishCompletionFile(f.Name(), false)
|
|
||||||
if !errors.Is(got, os.ErrPermission) {
|
|
||||||
t.Errorf("got: %s, want: %s", got.Error(), os.ErrPermission.Error())
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue