iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
💻

Replacing the Standard flag Package with pflag

に公開

Just another quick tip.

Replacing the Standard flag Package with the pflag Package

The standard Go flag package for evaluating command-line arguments is simple and well-designed, but have you ever wished you could use GNU-style syntax?

For example, wanting to use -f as a shorthand for a --foo parameter, or specifying -a -b -c together as -abc.

The github.com/spf13/pflag package allows you to implement this. You can write it like this:

sample1.go
package main

import (
    "fmt"

    "github.com/spf13/pflag"
)

func main() {
    f := pflag.BoolP("foo", "f", false, "option foo")
    b := pflag.BoolP("bar", "b", false, "option bar")
    pflag.Parse()

    fmt.Println("foo = ", *f)
    fmt.Println("bar = ", *b)
}

Running this results in:

$ go run sample1.go
foo =  false
bar =  false

$ go run sample1.go --foo --bar
foo =  true
bar =  true

$ go run sample1.go --foo=true
foo =  true
bar =  false

$ go run sample1.go -fb
foo =  true
bar =  true

...and you can specify command-line arguments like this.

pflag is compatible with the standard flag, so you can replace it by writing:

sample2.go
package main

import (
    "fmt"

    flag "github.com/spf13/pflag"
)

func main() {
    f := flag.Bool("foo", false, "option foo")
    b := flag.Bool("bar", false, "option bar")
    flag.Parse()

    fmt.Println("foo = ", *f)
    fmt.Println("bar = ", *b)
}

However, since the behavior follows the pflag specification:

$ go run sample2.go --foo
foo =  true
bar =  false

$ go run sample2.go -foo
unknown shorthand flag: 'f' in -foo
Usage of /tmp/go-build421334830/b001/exe/sample2:
      --bar   option bar
      --foo   option foo
unknown shorthand flag: 'f' in -foo

As shown above, if you use -foo as an argument, it will complain that it's an unknown shorthand flag (lol).

[Bonus] Setting Custom Command-Line Parameters for go test

I am embarrassed to admit that I only recently learned at the “Distributed Services with Go” Reading Group that you can use the standard flag package to set custom command-line parameters for go test. You can write it like this:

sample3_test.go
package sample3

import (
    "flag"
    "testing"
)

var foo = flag.Bool("foo", false, "option foo")

func TestMain(m *testing.M) {
    flag.Parse()
    m.Run()
}

func TestFlag(t *testing.T) {
    if !*foo {
        t.Errorf("option foo = %v, want %v.", *foo, true)
    }
}

Running this results in:

$ go test --shuffle on
-test.shuffle 1665227879001765953
--- FAIL: TestFlag (0.00s)
    sample3_test.go:17: option foo = false, want true.
FAIL
exit status 1
FAIL	pflag-sample/sample3.go	0.001s

$ go test --shuffle on --foo
-test.shuffle 1665227866801533228
PASS
ok  	pflag-sample/sample3.go	0.001s

Note that the specified flags are only valid within the package.

Well, changing test conditions via command-line arguments might not be common, but I thought it was clever how the sample code in Chapter 6 of Distributed Services with Go sets a --debug flag to output trace logs when specified via the command line.

I wondered if I could do this with pflag as well, but it didn't work out. Too bad. Let's use the standard flag for go test.

GitHubで編集を提案

Discussion