在urfave/cli/v2中将资源从命令传递给子命令

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

Pass resource from Command To Subcommands in urfave/cli/v2

问题

是否可能,并且如果可能的话,如何让一个Command初始化一个资源并将其传递给其Subcommands。想象一个以以下方式接收参数的应用程序:

$ mycmd db --connect <...> create <...>
$ mycmd db --connect <...> update <...>

这可能不是一个很好的例子,但它说明了这个概念。这里的db是所有子命令都依赖的某个资源。我希望有一个单独的函数负责初始化db资源,然后将初始化后的资源传递给子命令。我无法弄清楚如何在urfave/cli/v2中实现这一点。

你可以通过创建两个独立的cli.App来实现,一个用于解析参数中的db部分,只是为了创建一个带有context.WithValuecontext.Context,然后使用该上下文创建第二个cli.App,用于解析剩余的参数。我相信有更好的方法来实现这一点。

非常感谢任何帮助!

英文:

Is is possible, and if so how, to let a Command initialize a resource and pass it down to its Subcommands. Image an application that takes its arguments like

$ mycmd db --connect &lt;...&gt; create &lt;...&gt;
$ mycmd db --connect &lt;...&gt; update &lt;...&gt;

This may not be a great example but it illustrates the concept. Here db is some resource that all the subcommands depend on. I would like a single function to be responsible for the initialization of the db resource and then pass the initialized resource down to the subcommands. I can't figure out how to do this with urfave/cli/v2 .

You could do it by creating two separate cli.Apps, one that parses the db part of the arguments just to create a context.Context with context.WithValue and then use that context to create the second cli.App which would parse the remainder of the arguments. I'm sure there's a better way to do it.

I'm grateful for any help!

答案1

得分: 1

你可以通过上下文值来实现这一点。你可以在父级CommandBefore回调中设置该值。下面的代码是从subcommands示例中复制并修改的:

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/urfave/cli/v2"
)

func main() {
	app := &cli.App{
		Commands: []*cli.Command{
			{
				Name:   "db",
				Before: func(c *cli.Context) error {
					db := "example"
					c.Context = context.WithValue(c.Context, "db", db)
					return nil
				},
				Subcommands: []*cli.Command{
					{
						Name:  "connect",
						Action: func(c *cli.Context) error {
							db := c.Context.Value("db").(string) // 记得断言为原始类型
							fmt.Println("sub command:", db)
							return nil
						},
					},
				},
			},
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

这个示例使用了一个string,这样你就可以复制粘贴并运行它。你可以用你的DB对象替换字符串。

如何测试:

$ go build -o example
$ ./example db connect
sub command: example
英文:

You can achieve this with context values. You set the value in the Before callback of the parent Command. Below code is copied and modified from the subcommands example:

package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;os&quot;

	&quot;github.com/urfave/cli/v2&quot;
)

func main() {
	app := &amp;cli.App{
		Commands: []*cli.Command{
			{
				Name:   &quot;db&quot;,
				Before: func(c *cli.Context) error {
					db := &quot;example&quot;
					c.Context = context.WithValue(c.Context, &quot;db&quot;, db)
					return nil
				},
				Subcommands: []*cli.Command{
					{
						Name:  &quot;connect&quot;,
						Action: func(c *cli.Context) error {
							db := c.Context.Value(&quot;db&quot;).(string) // remember to assert to original type
							fmt.Println(&quot;sub command:&quot;, db)
							return nil
						},
					},
				},
			},
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

This main uses a string so that you can copy paste and run it. You can replace string with your DB object.

How to test:

$ go build -o example
$ ./example db connect
sub command: example

huangapple
  • 本文由 发表于 2021年11月15日 15:16:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/69970608.html
匿名

发表评论

匿名网友

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

确定