简体   繁体   English

如何提供 JSON 数组作为 cobra cli 的参数

[英]How can I provide JSON array as argument to cobra cli

I'm building a CLI using Go and Cobra library.我正在使用 Go 和 Cobra 库构建一个 CLI。 I've the following JSON that needs to be deserialized in the corresponding struct.我有以下 JSON 需要在相应的结构中反序列化。 Argument as JSON array:参数为 JSON 数组:

"[
    (stringA, stringB), 
    stringC
 ]"

Struct结构

type MyStruct struct {
    StringArray []string
}

I'm using Cobra's StringSicceVarP as follows to我正在使用 Cobra 的StringSicceVarP如下

cmd.PersistentFlags().StringSliceVarP(&opts.StringParam, "paramname", "", nil, `this is the description`)

But cobra is reading the incoming json as one single string [(stringA, stringB), stringC] whereas I want the array to be of length 2, such that StringArray[0]: (stringA, stringB) and StringArray[1]: stringC .但是 cobra 正在将传入的 json 作为单个字符串[(stringA, stringB), stringC]而我希望数组的长度为 2,这样 StringArray[0]: (stringA, stringB)和 StringArray[1]: stringC .

I can't use the StringSliceVarP as it will split based on , which I don't want as my array string could itself has a , .我不能使用StringSliceVarP ,因为它将基于 进行拆分,我不希望这样做,因为我的数组字符串本身可能有,

How can I achieve this?我怎样才能做到这一点?

I personally advice you against this option.我个人建议您不要使用此选项。 Supplying formatted data is conventionally done through reading STDIN or from a file.提供格式化数据通常是通过读取 STDIN 或从文件中完成的。 Such solution is usually more flexible by allowing you to add flags to specify the file's format (JSON, XML, etc.).这种解决方案通常更灵活,允许您添加标志来指定文件的格式(JSON、XML 等)。

Supplying a filename instead of the raw JSON string in the arguments adds better interoperability with other software, and other benefits such as using the computer's disk for buffering data instead of the computer's memory/RAM.在 arguments 中提供文件名而不是原始 JSON 字符串可以增加与其他软件的更好互操作性,以及其他好处,例如使用计算机磁盘而不是计算机内存/RAM 来缓冲数据。

My personal recommendations is that:我个人的建议是:

  • Use flags for options and configs, similar to a HTTP's query parameters.对选项和配置使用标志,类似于 HTTP 的查询参数。
  • Use stdin/file handles for data, similar to a HTTP's request body.对数据使用标准输入/文件句柄,类似于 HTTP 的请求正文。

However, if you insist on using a flag:但是,如果您坚持使用标志:

Cobra does not have built-in support for JSON structures. Cobra 没有对 JSON 结构的内置支持。 However, the pflag package (the flag library used by Cobra) allows you to define custom value types to be used as flags through the pflag.(*FlagSet).Var() method.但是, pflag package(Cobra 使用的标志库)允许您通过pflag.(*FlagSet).Var()方法定义要用作标志的自定义值类型。 You have to make a new type that implements the pflag.Value interface:您必须创建一个实现pflag.Value接口的新类型:

type Value interface {
    String() string
    Set(string) error
    Type() string
}

To make a custom JSON-parsing type, you could write the following to use the built-in encoding/json package:要制作自定义 JSON 解析类型,您可以编写以下代码以使用内置encoding/json package:

import (
    "encoding/json"
)

type JSONFlag struct {
    Target interface{}
}

// String is used both by fmt.Print and by Cobra in help text
func (f *JSONFlag) String() string {
    b, err := json.Marshal(f.Target)
    if err != nil {
        return "failed to marshal object"
    }
    return string(b)
}

// Set must have pointer receiver so it doesn't change the value of a copy
func (f *JSONFlag) Set(v string) error {
    return json.Unmarshal([]byte(v), f.Target)
}

// Type is only used in help text
func (f *JSONFlag) Type() string {
    return "json"
}

Then to use this new pflag.Value -compatible type, you may write something like this:然后要使用这个新的pflag.Value兼容类型,你可以这样写:

import (
    "fmt"

    "github.com/spf13/cobra"
)

type MyStruct struct {
    StringArray []string
}

func init() {
    var flagMyStringArray []string

    var myCmd = &cobra.Command{
        Use:   "mycmd",
        Short: "A brief description of your command",
        Run: func(cmd *cobra.Command, args []string) {
            myStruct := MyStruct{StringArray: flagMyStringArray}
            fmt.Printf("myStruct.StringArray contains %d elements:\n", len(myStruct.StringArray))
            for i, s := range myStruct.StringArray {
                fmt.Printf("idx=%d: %q", i, s)
            }
        },
    }

    rootCmd.AddCommand(myCmd)

    myCmd.Flags().Var(&JSONFlag{&flagMyStringArray}, "paramname", `this is the description`)
}

Example usage:示例用法:

$ go run . mycmd --paramname 'hello'
Error: invalid argument "hello" for "--paramname" flag: invalid character 'h' looking for beginning of value
Usage:
  test mycmd [flags]

Flags:
  -h, --help             help for mycmd
      --paramname json   this is the description

exit status 1
$ go run . mycmd --paramname '["(stringA, stringB)", "stringC"]'
myStruct.StringArray contains 2 elements:
idx=0: "(stringA, stringB)"
idx=1: "stringC"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM