将资源从命令传递到 urfave/cli/v2 中的子命令

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.Contextcontext.WithValue 然后使用该上下文创建第二个 cli.App 来解析其余参数。我相信有更好的方法。

非常感谢您的帮助!

您可以使用上下文值来实现这一点。您在父 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) // remember to assert to original type
                            fmt.Println("sub command:", db)
                            return nil
                        },
                    },
                },
            },
        },
    }

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

这个主要使用 string 以便您可以复制粘贴和 运行 它。您可以用您的数据库对象替换字符串。

如何测试:

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