Go
golang

urfave/cliのグローバルオプションへのアクセス方法

urfave/cli: A simple, fast, and fun package for building command line apps in Go

結論

Actionではc.Stringなどで取得できる。
Commandではc.GlobalStringGlobalを付ける。

事象

USAGE:
   mycommand [global options] command [command options] [arguments...]

global optionsを渡しているのにcommandアクションからc.フラグで参照できなかった。

コード

package main

import (
        "fmt"
        "github.com/codegangsta/cli"
        "os"
)

func main() {
        app := cli.NewApp()
        app.Name = "test"
        app.Usage = "test"
        app.Version = "1.0.0"

        app.Flags = []cli.Flag{
                cli.BoolFlag{
                        Name: "b",
                },
                cli.StringFlag{
                        Name: "s",
                },
        }

        app.Commands = []cli.Command{
                {
                        Name:   "test",
                        Action: testAction,
                },
        }

        app.Action = func(c *cli.Context) {
                fmt.Printf("c.GlobalFlagNames()  : %+v\n", c.GlobalFlagNames())
                fmt.Printf("c.String(\"s\")        : %+v\n", c.String("s"))
                fmt.Printf("c.Bool(\"b\")          : %+v\n", c.Bool("b"))
                fmt.Printf("c.GlobalString(\"s\")  : %+v\n", c.GlobalString("s"))
                fmt.Printf("c.GlobalBool(\"b\")    : %+v\n", c.GlobalBool("b"))
        }

        app.Run(os.Args)
}

func testAction(c *cli.Context) {
        fmt.Printf("c.GlobalFlagNames()  : %+v\n", c.GlobalFlagNames())
        fmt.Printf("c.String(\"s\")        : %+v\n", c.String("s"))
        fmt.Printf("c.Bool(\"b\")          : %+v\n", c.Bool("b"))
        fmt.Printf("c.GlobalString(\"s\")  : %+v\n", c.GlobalString("s"))
        fmt.Printf("c.GlobalBool(\"b\")    : %+v\n", c.GlobalBool("b"))
}

結果

> ./testgo -h
NAME:
   test - test

USAGE:
   testgo [global options] command [command options] [arguments...]

VERSION:
   1.0.0

COMMANDS:
     test
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   -b
   -s value
   --help, -h     show help
   --version, -v  print the version
> ./testgo -b -s text
c.GlobalFlagNames()  : [b s]
c.String("s")        : text
c.Bool("b")          : true
c.GlobalString("s")  : text
c.GlobalBool("b")    : true
> ./testgo -b -s text test
c.GlobalFlagNames()  : [b s]
c.String("s")        :
c.Bool("b")          : false
c.GlobalString("s")  : text
c.GlobalBool("b")    : true

commandオプションとの住み分けのためだろう。
オプションの取得方法がわからず、(コマンドなしのfuncなら)c.フラグ形式で取れると判明。軽くた範囲でコマンドからグローバルオプションを参照するコードがなくこっち原因とハマリ。

参考

Go言語でサクッとコマンドラインツールをつくる | eureka tech blog

グローバルオプションを扱うときはGlobalなしで動くところであってもGlobalを必ずつけるようにすると、初心者のうちは混乱しないかも。