web-dev-qa-db-ja.com

Goのコマンドラインフラグを必須に設定できますか?

特定のフラグが必須であることを設定する方法はありますか、それとも自分でフラグの存在を確認する必要がありますか?

34
Petr Pudlák

flag パッケージは、必須フラグまたは必須フラグをサポートしていません(フラグは明示的に指定する必要があります)。

できることは、(すべての)フラグに適切なデフォルト値を使用することです。そして、フラグが適切なデフォルトがないようなものである場合は、アプリケーションの開始時に値を確認し、エラーメッセージで停止します。とにかく(必要なフラグだけでなく)フラグ値の検証を行う必要があります。したがって、これは(大きな)オーバーヘッドを意味するものではなく、これは一般的に良い習慣です。

24
icza

既に述べた のように、flagパッケージはこの機能を直接提供せず、通常は賢明なデフォルトを提供することができます(そしてそうすべきです)。少数の明示的な引数(たとえば、入力ファイル名と出力ファイル名)のみが必要な場合は、位置引数を使用できます(たとえば、flag.Parse()の後にflag.NArg()==2を確認してからinput, output := flag.Arg(0), flag.Arg(1))。

ただし、これが理にかなっていない場合があります。任意の順序で受け入れたいいくつかの整数フラグを言います。整数値は妥当ですが、デフォルトはありません。次に、 flag.Visit 関心のあるフラグが明示的に設定されているかどうかを確認する機能。これは、フラグがデフォルト値に明示的に設定されているかどうかを判断する唯一の方法だと思います(カスタムflag.Value状態を保持するSet実装を持つタイプ。

たとえば、次のようなものです。

    required := []string{"b", "s"}
    flag.Parse()

    seen := make(map[string]bool)
    flag.Visit(func(f *flag.Flag) { seen[f.Name] = true })
    for _, req := range required {
        if !seen[req] {
            // or possibly use `log.Fatalf` instead of:
            fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
            os.Exit(2) // the same exit code flag.Parse uses
        }
    }

Playground

「-b」または「-s」フラグが明示的に設定されていない場合、これはエラーを生成します。

7
Dave C

go-flags を使用すると、必要なフラグと必要な位置引数の両方を宣言できます。

var opts struct {
    Flag string `short:"f" required:"true" name:"a flag"`
    Args struct {
        First   string `positional-arg-name:"first arg"`
        Sencond string `positional-arg-name:"second arg"`
    } `positional-args:"true" required:"2"`
}
args, err := flags.Parse(&opts)
6
iKanor

好き - github.com/jessevdk/go-flags CLIで使用するパッケージ。フラグを必須に設定するには、required属性を提供します。そのように:

var opts struct {
...
    // Example of a required flag
    Name string `short:"n" long:"name" description:"A name" required:"true"`
...
}
6
RoninDev

フラグパスがある場合は、* pathに値が含まれているかどうかを確認するだけです

var path = flag.String("f", "", "/path/to/access.log")
flag.Parse()
if *path == "" {
    usage()
    os.Exit(1)
}
3
ivan73

このソリューション に同意しますが、私の場合、デフォルト値は通常環境値です。例えば、

dsn := flag.String("dsn", os.Getenv("MYSQL_DSN"), "data source name")

この場合、値が呼び出し(通常はローカル開発)または環境変数(prod環境)から設定されているかどうかを確認します。

そのため、いくつかの小さな変更を加えて、私の場合はうまくいきました。

flag.VisitAll を使用して、すべてのフラグの値を確認します。

required := []string{"b", "s"}
flag.Parse()

seen := make(map[string]bool)
flag.VisitAll(func(f *flag.Flag) {
    if f.Value.String() != "" {
        seen[f.Name] = true
    }
})
for _, req := range required {
    if !seen[req] {
        // or possibly use `log.Fatalf` instead of:
        fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
        os.Exit(2) // the same exit code flag.Parse uses
    }
}

Test example in plauground

0
canhizares