How does cobra commander for go (golang) work?

huangapple go评论76阅读模式
英文:

How does cobra commander for go (golang) work?

问题

我正在尝试理解如何使用cobra(和viper)库创建自定义命令,并能够使用它们。

具体来说,我试图理解并使它们提供的示例工作。示例代码如下:

import (
    "github.com/spf13/cobra"
    "fmt"
    "strings"
)

func main() {

    var echoTimes int

    var cmdPrint = &cobra.Command{
        Use:   "print [string to print]",
        Short: "Print anything to the screen",
        Long:  `print is for printing anything back to the screen.
        For many years people have printed back to the screen.
        `,
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Println("Print: " + strings.Join(args, " "))
        },
    }

    var cmdEcho = &cobra.Command{
        Use:   "echo [string to echo]",
        Short: "Echo anything to the screen",
        Long:  `echo is for echoing anything back.
        Echo works a lot like print, except it has a child command.
        `,
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Println("Print: " + strings.Join(args, " "))
        },
    }

    var cmdTimes = &cobra.Command{
        Use:   "times [# times] [string to echo]",
        Short: "Echo anything to the screen more times",
        Long:  `echo things multiple times back to the user by providing
        a count and a string.`,
        Run: func(cmd *cobra.Command, args []string) {
            for i:=0; i < echoTimes; i++ {
                fmt.Println("Echo: " + strings.Join(args, " "))
            }
        },
    }

    cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")

    var rootCmd = &cobra.Command{Use: "app"}
    rootCmd.AddCommand(cmdPrint, cmdEcho)
    cmdEcho.AddCommand(cmdTimes)
    rootCmd.Execute()
}

然而,我已经创建了名为cobra.go的文件,并且似乎无法使其正常工作。我确实理解rootCmd不应该是可执行的。然而,根据我所知,Use字段的行为似乎不一致。我试图理解命令在命令行中实际运行的方式,并以不同的方式编译文件以进行实验。

例如,我使用go build cobra.go编译了这个文件,现在我有一个可执行文件cobra

如果我运行./name,它的行为与./name help相同,并打印出:

Usage:
app [command]
Available Commands:
print [string to print]   Print anything to the screen
echo [string to echo]     Echo anything to the screen
help [command]            Help about any command
Available Flags:
--help=false: help for app
Use "app help [command]" for more information about that command.

然而,描述错误地说必须使用app help [command]来使用它。

如果我运行./app help print(当然只有cobra可执行文件),它会打印出:

zsh: no such file or directory: ./app

如果我运行app help print,它也不起作用(因为在PATH中找不到):

zsh: command not found: app

所以我的理解是,除非我使用与根命令相同的名称构建它,否则cobra会表现出奇怪的行为。

这意味着Use字段必须匹配输出的文件名,才能使帮助信息有意义,并且能够正确运行其子命令,对吗?

另外,如果只允许一个package main,那么如何在同一个项目中拥有(编译)多个不同的“根”命令呢?如果在main下有多个“根”命令,它应该不起作用,对吗?我很快会尝试一些这样的想法。

英文:

I am trying to understand how to create costume commands for go using the cobra (and viper) libraries and be able to use them.

Specifically I was trying to understand and make the example they provide work. The example is the following:

import(
&quot;github.com/spf13/cobra&quot;
&quot;fmt&quot;
&quot;strings&quot;
)
func main() {
var echoTimes int
var cmdPrint = &amp;cobra.Command{
Use:   &quot;print [string to print]&quot;,
Short: &quot;Print anything to the screen&quot;,
Long:  `print is for printing anything back to the screen.
For many years people have printed back to the screen.
`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(&quot;Print: &quot; + strings.Join(args, &quot; &quot;))
},
}
var cmdEcho = &amp;cobra.Command{
Use:   &quot;echo [string to echo]&quot;,
Short: &quot;Echo anything to the screen&quot;,
Long:  `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.
`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(&quot;Print: &quot; + strings.Join(args, &quot; &quot;))
},
}
var cmdTimes = &amp;cobra.Command{
Use:   &quot;times [# times] [string to echo]&quot;,
Short: &quot;Echo anything to the screen more times&quot;,
Long:  `echo things multiple times back to the user by providing
a count and a string.`,
Run: func(cmd *cobra.Command, args []string) {
for i:=0; i &lt; echoTimes; i++ {
fmt.Println(&quot;Echo: &quot; + strings.Join(args, &quot; &quot;))
}
},
}
cmdTimes.Flags().IntVarP(&amp;echoTimes, &quot;times&quot;, &quot;t&quot;, 1, &quot;times to echo the input&quot;)
var rootCmd = &amp;cobra.Command{Use: &quot;app&quot;}
rootCmd.AddCommand(cmdPrint, cmdEcho)
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
}

However, I have made the file for it, in package main and I can't seem to make it work properly. I do understand that the rootCmd is not suppose to be executable. However, it seems to me that the Use field behaves inconsistently (as far as I can tell). I was trying to understand how commands actually run in the command line and compile the file in different ways to experiment this.

For example I compiled this file I named as cobra.go with go build cobra.go and now I have an executable cobra.

If I do ./name it behaves the same way as ./name help and prints:

Usage:
app [command]
Available Commands:
print [string to print]   Print anything to the screen
echo [string to echo]     Echo anything to the screen
help [command]            Help about any command
Available Flags:
--help=false: help for app
Use &quot;app help [command]&quot; for more information about that command.

However the description incorrectly says that to use it you must do "app help [command]".

If I do that ./app help print (with only the cobra executable of course) it prints:

zsh: no such file or directory: ./app

if I do app help print it also doesn't work (since it isn't found in PATH):

zsh: command not found: app

So my understanding is that, unless I build it with the same name as root, cobra will act funny.

So it means that the use field has to match the file name for the output of help to make sense and for us to be able to run its sub commands properly, right?

Also, how is one able to have (compile) multiple different "root" commands in the same project, if only one package main is allowed? If one has multiple "root" commands under main, it shouldn't work, right? I will try some of these ideas soon.

答案1

得分: 7

你可以查看其他项目中如何使用 cobra(go-search)。

例如,bitballoon-cli 项目将多个命令定义在各自的文件中,每个文件都在主包中。就像 create.go 文件一样:

package main
import (
"github.com/BitBalloon/bitballoon-go"
"github.com/spf13/cobra"
"log"
)
var createCmd = &cobra.Command{
Use:   "create",
Short: "create a new BitBalloon site",
Long:  "creates a new BitBalloon site and returns an ID you can deploy to",
}
var siteName, customDomain, password, notificationEmail string
func init() {
createCmd.Run = create
createCmd.Flags().StringVarP(&siteName, "name", "n", "", "Name of the site (must be a valid subdomain: <name>.bitballoon.com)")
createCmd.Flags().StringVarP(&customDomain, "domain", "d", "", "Custom domain for the site (only works for premium sites)")
createCmd.Flags().StringVarP(&password, "password", "p", "", "Password for the site")
createCmd.Flags().StringVarP(&notificationEmail, "email", "e", "", "Notification email for form submissions (only works for premium sites)")
}
func create(cmd *cobra.Command, args []string) {
// 这个命令的函数逻辑
}

你可以检查一下在你的项目中是否可以按照这种方式定义和添加命令。


4年后,可以观看 Francesc Campoy 的视频 "justforfunc #32: CLI tools with Cobra"。

英文:

You could check how cobra is used is other projects (go-search).

For instance, the bitballoon-cli project defines multiple commands, each in their own file, each in the main package. Like create.go:

package main
import (
&quot;github.com/BitBalloon/bitballoon-go&quot;
&quot;github.com/spf13/cobra&quot;
&quot;log&quot;
)
var createCmd = &amp;cobra.Command{
Use:   &quot;create&quot;,
Short: &quot;create a new BitBalloon site&quot;,
Long:  &quot;creates a new BitBalloon site and returns an ID you can deploy to&quot;,
}
var siteName, customDomain, password, notificationEmail string
func init() {
createCmd.Run = create
createCmd.Flags().StringVarP(&amp;siteName, &quot;name&quot;, &quot;n&quot;, &quot;&quot;, &quot;Name of the site (must be a valid subdomain: &lt;name&gt;.bitballoon.com)&quot;)
createCmd.Flags().StringVarP(&amp;customDomain, &quot;domain&quot;, &quot;d&quot;, &quot;&quot;, &quot;Custom domain for the site (only works for premium sites)&quot;)
createCmd.Flags().StringVarP(&amp;password, &quot;password&quot;, &quot;p&quot;, &quot;&quot;, &quot;Password for the site&quot;)
createCmd.Flags().StringVarP(&amp;notificationEmail, &quot;email&quot;, &quot;e&quot;, &quot;&quot;, &quot;Notification email for form submissions (only works for premium sites)&quot;)
}
func create(cmd *cobra.Command, args []string) {
// your function for this command
}

You could check if that way of defining and adding a command to your project works in your case.


4 years later, see the video "justforfunc #32: CLI tools with Cobra", by Francesc Campoy.

huangapple
  • 本文由 发表于 2014年7月17日 06:26:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/24791878.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定