pflag

POSIX/GNU形式のフラグをサポートするGoライブラリ。Goの標準flagパッケージのドロップイン代替品です。

gocliposixgnuflags

フレームワーク

pflag

概要

pflagは、POSIX/GNU形式のフラグをサポートするGoライブラリです。Goの標準flagパッケージのドロップイン代替品として設計されており、より柔軟なフラグ処理が可能です。Cobraと組み合わせて使用されることが多く、モダンなCLIアプリケーションの構築に適しています。

詳細

pflagは、標準のflagパッケージでは提供されないPOSIX/GNU形式のコマンドラインフラグを扱うために開発されました。--flag(長い形式)と-f(短い形式)の両方をサポートし、標準のflagパッケージと互換性を保ちながら、より豊富な機能を提供します。spf13/cobraライブラリの内部でも使用されており、Goエコシステムで広く採用されています。

主な特徴

  • POSIX/GNU準拠: --flag-f形式の両方をサポート
  • ドロップイン代替: 標準flagパッケージの直接的な置き換えが可能
  • 豊富なフラグタイプ: String、Int、Bool、Duration、Sliceなど多様な型に対応
  • ショートハンド: 単一文字のエイリアスを定義可能
  • FlagSet: 独立したフラグセットによるサブコマンドサポート
  • カスタムフラグ: pflag.Valueインターフェースによる独自フラグ型の実装
  • 互換性: 標準flagパッケージで定義されたフラグの組み込みが可能

メリット・デメリット

メリット

  • 標準的なフラグ形式: POSIX/GNU規約に準拠した親しみやすいインターフェース
  • 高い互換性: 既存のflagコードからの移行が容易
  • 柔軟性: 様々なフラグタイプとカスタマイズオプション
  • エコシステム: Cobraなど他のCLIライブラリとの優れた統合
  • 軽量: 最小限のオーバーヘッドで高機能を提供

デメリット

  • 単独利用: 単体では高度なCLI機能(サブコマンド、ヘルプ生成)は限定的
  • 学習コスト: 標準flagから移行する際の微細な違い
  • 依存関係: 外部ライブラリへの依存が発生
  • 複雑な構造: 大規模なCLIには追加のフレームワークが必要

主要リンク

書き方の例

package main

import (
	"fmt"
	"os"

	"github.com/spf13/pflag"
)

func main() {
	// 基本的なフラグ定義
	var name = pflag.String("name", "World", "あなたの名前")
	var age = pflag.IntP("age", "a", 0, "あなたの年齢") // ショートハンド 'a'
	var verbose = pflag.BoolP("verbose", "v", false, "詳細出力を有効にする")
	var tags = pflag.StringSlice("tags", []string{}, "タグのリスト")
	
	// ヘルプとバージョンフラグ
	var help = pflag.BoolP("help", "h", false, "ヘルプを表示")
	var version = pflag.Bool("version", false, "バージョンを表示")
	
	// フラグの解析
	pflag.Parse()
	
	// ヘルプ表示
	if *help {
		pflag.Usage()
		return
	}
	
	// バージョン表示
	if *version {
		fmt.Println("myapp version 1.0.0")
		return
	}
	
	// フラグ値の使用
	fmt.Printf("こんにちは、%s!\n", *name)
	
	if *age > 0 {
		fmt.Printf("あなたは%d歳です。\n", *age)
	}
	
	if *verbose {
		fmt.Println("詳細出力が有効です。")
		fmt.Printf("タグ: %v\n", *tags)
	}
	
	// フラグ以外の引数
	if pflag.NArg() > 0 {
		fmt.Printf("残りの引数: %v\n", pflag.Args())
	}
}

// FlagSetを使用したサブコマンドの例
func withFlagSet() {
	// メインコマンドのフラグ
	mainFlags := pflag.NewFlagSet("main", pflag.ExitOnError)
	debug := mainFlags.Bool("debug", false, "デバッグモードを有効にする")
	
	// サブコマンド用のFlagSet
	createFlags := pflag.NewFlagSet("create", pflag.ExitOnError)
	createName := createFlags.String("name", "", "作成するリソースの名前")
	createType := createFlags.String("type", "default", "リソースのタイプ")
	
	deleteFlags := pflag.NewFlagSet("delete", pflag.ExitOnError)
	deleteForce := deleteFlags.Bool("force", false, "強制削除")
	deleteName := deleteFlags.String("name", "", "削除するリソースの名前")
	
	// メインフラグの解析
	mainFlags.Parse(os.Args[1:])
	
	if *debug {
		fmt.Println("デバッグモードが有効です")
	}
	
	// サブコマンドの処理
	args := mainFlags.Args()
	if len(args) == 0 {
		fmt.Println("サブコマンドを指定してください: create, delete")
		return
	}
	
	switch args[0] {
	case "create":
		createFlags.Parse(args[1:])
		fmt.Printf("リソース作成: 名前=%s, タイプ=%s\n", *createName, *createType)
		
	case "delete":
		deleteFlags.Parse(args[1:])
		if *deleteForce {
			fmt.Printf("強制削除: %s\n", *deleteName)
		} else {
			fmt.Printf("削除: %s\n", *deleteName)
		}
		
	default:
		fmt.Printf("不明なサブコマンド: %s\n", args[0])
	}
}