Cobra: Documenting a positional argument and suppressing `[flags]` when appropriate

Created on 27 Feb 2017  路  12Comments  路  Source: spf13/cobra

The readme references an example command that has a positional argument:

git clone URL --bare

To document that in Hugo, here's what I would start with:

cloneCmd := &cobra.Command{
    Use:   "clone",
    Short: "Clone a repository into a new directory",
    Run: func(cmd *cobra.Command, args []string) {
        // stub
    },
}

Which produces:

$ example clone --help
Clone a repository into a new directory

Usage:
  example clone [flags]

This stub could use a few improvements:

  1. The positional parameter URL is not specified in the help.
  2. I'd have to manually check the args array for URL, invent some error messages, etc.
  3. The documentation specifies [flags], but there are no flags!

Any ideas on how I could tackle these improvements?

The first one could probably be fixed by setting Use to "clone [URL]", but the third one is the real pickle. As far as I can tell I'd have to copy and modify the default template, at which point I'm detached from the official version and I'd have to maintain my "fork" of the template, which I'd rather avoid.

Most helpful comment

Yes! Give or take. Thank you for reminding me.

The first problem is handled by manually typing a positional argument in the usage string, the second problem is handled by #284 landing, and the third problem is small enough to be ignored.

Thanks to everyone who helped. Here is a complete solution for anyone who was following along:

package main

import (
    . "fmt"
    "os"

    "github.com/spf13/cobra"
)

func main() {
    RootCmd := &cobra.Command{
        Use:   "example",
        Short: "An example cobra command",
    }

    var bare bool
    CloneCmd := &cobra.Command{
        Use:   "clone [URL]",
        Short: "Clone a repository into a new directory",

        Args:  cobra.ExactArgs(1),

        Run: func(cmd *cobra.Command, args []string) {

            // This is guaranteed to work, due to ExactArgs above
            url := args[0]

            Println("Cloning from", url, "with bare =", bare)
        },
    }
    CloneCmd.Flags().BoolVar(&bare, "bare", false, "Make a bare Git repository.")

    RootCmd.AddCommand(CloneCmd)

    err := RootCmd.Execute()
    if err != nil {
        Println(err)
        os.Exit(1)
    }
}

In action:

$ example clone --help
Clone a repository into a new directory

Usage:
  example clone [URL] [flags]

Flags:
      --bare   Make a bare Git repository.
  -h, --help   help for clone


$ example clone github --bare
Cloning from github with bare = true

All 12 comments

Fixing the default template to not say [flags] if there are no flags fixes the second problem for everyone, no? It doesn't seem like something that wouldn't be universal...

I think you meant the third problem, but yes! That would work.

Looking at the default template I linked, my guess is using HasAvailableLocalFlags instead of HasAvailableFlags would work. Might cause other issues though, I'm not sure.

Yes, the third problem.

284 is one approach to the second problem

That looks great! I would prefer to use the main source, but it looks like that PR has been hanging out for awhile. Would you mind merging upstream master into your fork again? If not, no worries, I can maintain my own fork if necessary.

This branch is 16 commits ahead, 6 commits behind spf13:master.

I've rebased it with master

  1. You can specify it in Use like in my project.
  2. There is a help flag, but there is a bug with showing help flag in usage. #414 fixes it.

Nice. It sounds like the current solutions to the three problems mentioned in the ticket are:

  1. Write the positional argument in the Use field, ~or use the fork from #284~
  2. Manually parse + validate the positional argument, or wait for / use #284
  3. Wait for #414 and see how that affects things, or possibly develop the fix that @eparis mentioned.

I think once the behavior on master satisfies these points, I'll add a comment with a new cobra.Command example and close the ticket :slightly_smiling_face:

284 will not solve first problem. Only second

@kofalt, is your problem solved?

Yes! Give or take. Thank you for reminding me.

The first problem is handled by manually typing a positional argument in the usage string, the second problem is handled by #284 landing, and the third problem is small enough to be ignored.

Thanks to everyone who helped. Here is a complete solution for anyone who was following along:

package main

import (
    . "fmt"
    "os"

    "github.com/spf13/cobra"
)

func main() {
    RootCmd := &cobra.Command{
        Use:   "example",
        Short: "An example cobra command",
    }

    var bare bool
    CloneCmd := &cobra.Command{
        Use:   "clone [URL]",
        Short: "Clone a repository into a new directory",

        Args:  cobra.ExactArgs(1),

        Run: func(cmd *cobra.Command, args []string) {

            // This is guaranteed to work, due to ExactArgs above
            url := args[0]

            Println("Cloning from", url, "with bare =", bare)
        },
    }
    CloneCmd.Flags().BoolVar(&bare, "bare", false, "Make a bare Git repository.")

    RootCmd.AddCommand(CloneCmd)

    err := RootCmd.Execute()
    if err != nil {
        Println(err)
        os.Exit(1)
    }
}

In action:

$ example clone --help
Clone a repository into a new directory

Usage:
  example clone [URL] [flags]

Flags:
      --bare   Make a bare Git repository.
  -h, --help   help for clone


$ example clone github --bare
Cloning from github with bare = true

To 1.) Documentation of positional arguments in an automated manner is tracked in https://github.com/spf13/cobra/issues/378

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jjzcru picture jjzcru  路  3Comments

diwakergupta picture diwakergupta  路  5Comments

andygrunwald picture andygrunwald  路  6Comments

anentropic picture anentropic  路  4Comments

anuraaga picture anuraaga  路  5Comments