This document covers integration between pflag and Go's standard library flag package, allowing applications to use both packages together and support third-party libraries that use standard Go flags.
import (
goflag "flag"
"github.com/spf13/pflag"
)func (f *FlagSet) AddGoFlag(goflag *goflag.Flag)Add a single flag from Go's flag package to a pflag FlagSet.
Usage:
import (
goflag "flag"
"github.com/spf13/pflag"
)
// Define a Go flag
var goVerbose = goflag.Bool("goverbose", false, "go verbose mode")
// Add it to pflag
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
goFlag := goflag.CommandLine.Lookup("goverbose")
fs.AddGoFlag(goFlag)
fs.Parse(os.Args[1:])func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet)Add all flags from a Go flag.FlagSet to a pflag FlagSet.
Usage:
import (
goflag "flag"
"github.com/spf13/pflag"
)
// Define Go flags
var (
goHost = goflag.String("gohost", "localhost", "host address")
goPort = goflag.Int("goport", 8080, "port number")
)
// Create pflag FlagSet and add all Go flags
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
fs.AddGoFlagSet(goflag.CommandLine)
// Now can use both pflag and Go flags together
fs.StringP("output", "o", "out.txt", "output file")
fs.Parse(os.Args[1:])package main
import (
"fmt"
goflag "flag"
"os"
"github.com/spf13/pflag"
)
func main() {
// pflag flags
var ip = pflag.IntP("port", "p", 8080, "server port")
// Import flags from Go's flag package
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// Parse using pflag
pflag.Parse()
fmt.Printf("Server will run on port %d\n", *ip)
}func PFlagFromGoFlag(goflag *goflag.Flag) *FlagCreate a pflag Flag from a Go flag.Flag. This allows manual conversion and inspection of Go flags.
Usage:
import (
goflag "flag"
"github.com/spf13/pflag"
)
// Define a Go flag
goTimeout := goflag.Duration("timeout", 30*time.Second, "request timeout")
// Convert to pflag Flag
goFlag := goflag.CommandLine.Lookup("timeout")
pflags := pflag.PFlagFromGoFlag(goFlag)
fmt.Printf("pflag Name: %s\n", pflags.Name)
fmt.Printf("pflag Usage: %s\n", pflags.Usage)
fmt.Printf("pflag Value: %s\n", pflags.Value.String())func (f *FlagSet) CopyToGoFlagSet(newSet *goflag.FlagSet)Copy all flags from a pflag FlagSet to a Go flag.FlagSet. This is useful when interfacing with APIs that require Go's flag.FlagSet.
Usage:
import (
goflag "flag"
"github.com/spf13/pflag"
)
// Define pflag flags
pfs := pflag.NewFlagSet("myapp", pflag.ExitOnError)
pfs.Int("port", 8080, "server port")
pfs.String("host", "localhost", "server host")
pfs.Parse(os.Args[1:])
// Copy to Go flag set (e.g., for a library that needs goflag.FlagSet)
goFs := goflag.NewFlagSet("goflags", goflag.ExitOnError)
pfs.CopyToGoFlagSet(goFs)
// Now goFs contains equivalent Go flagsMany Go libraries use the standard flag package. Here's how to integrate them with pflag.
package main
import (
goflag "flag"
"fmt"
"os"
"github.com/golang/glog"
"github.com/spf13/pflag"
)
func main() {
// Define your pflag flags
port := pflag.IntP("port", "p", 8080, "server port")
config := pflag.String("config", "default.conf", "config file")
// Add Go flags (glog uses these) to pflag
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// Parse with pflag
pflag.Parse()
// Initialize glog (it uses Go flags internally)
defer glog.Flush()
glog.Info("Starting server")
fmt.Printf("Server running on port %d with config %s\n", *port, *config)
}
// Now can use both pflag and glog flags:
// myapp -p 9090 --config=prod.conf -logtostderr=true -v=2package main
import (
goflag "flag"
"os"
"github.com/spf13/pflag"
)
// Simulate third-party package flags
var thirdPartyDebug = goflag.Bool("tpdebug", false, "third party debug mode")
func main() {
// Your application flags
fs := pflag.NewFlagSet("app", pflag.ExitOnError)
appPort := fs.IntP("port", "p", 8080, "application port")
appVerbose := fs.Bool("verbose", false, "verbose output")
// Add third-party library flags
fs.AddGoFlagSet(goflag.CommandLine)
// Parse everything together
fs.Parse(os.Args[1:])
// All flags are now available
// *appPort, *appVerbose, *thirdPartyDebug
}pflag skips over Go test's built-in flags (starting with -test.) by default. Use ParseSkippedFlags to parse them separately.
func ParseSkippedFlags(osArgs []string, goFlagSet *goflag.FlagSet) errorExplicitly parse go test flags (starting with -test.) using goflag.Parse(), since pflag.Parse() skips them by default.
Usage:
import (
goflag "flag"
"os"
"testing"
"github.com/spf13/pflag"
)
func TestMain(m *testing.M) {
// Define custom test flags
var customFlag = pflag.String("custom", "", "custom test flag")
// Add Go flags to pflag
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// Parse pflag flags
pflag.Parse()
// Parse skipped Go test flags
pflag.ParseSkippedFlags(os.Args[1:], goflag.CommandLine)
// Run tests
os.Exit(m.Run())
}
// Now you can use both custom flags and go test flags:
// go test ./your/tests -run ^YourTest$ -v --custom=valueBy default, pflag doesn't parse shorthand versions of go test flags. This causes issues with commands like:
go test -v --custom-flag=valueThe -v flag is skipped by pflag. Use ParseSkippedFlags to handle it:
func TestMain(m *testing.M) {
pflag.String("custom", "", "custom flag")
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// Parse pflag flags first
pflag.Parse()
// Then parse skipped go test flags
pflag.ParseSkippedFlags(os.Args[1:], goflag.CommandLine)
os.Exit(m.Run())
}The simplest way to migrate from Go's flag package to pflag is the drop-in replacement pattern:
// Before (using standard flag package)
import "flag"
var port = flag.Int("port", 8080, "server port")
func main() {
flag.Parse()
// ...
}// After (using pflag as drop-in replacement)
import flag "github.com/spf13/pflag"
var port = flag.Int("port", 8080, "server port")
func main() {
flag.Parse()
// ...
}If you directly instantiate the Flag struct, you need to add the Shorthand field:
// Standard flag package
flag := &flag.Flag{
Name: "myflag",
Usage: "my flag",
Value: myValue,
}
// pflag (note additional Shorthand field)
flag := &pflag.Flag{
Name: "myflag",
Shorthand: "", // Add this field
Usage: "my flag",
Value: myValue,
}Here's a complete example showing various integration patterns:
package main
import (
"fmt"
goflag "flag"
"os"
"time"
"github.com/spf13/pflag"
)
// Third-party library flags (simulated)
var (
libTimeout = goflag.Duration("lib-timeout", 10*time.Second, "library timeout")
libRetries = goflag.Int("lib-retries", 3, "library retry count")
)
func main() {
// Application flags using pflag
port := pflag.IntP("port", "p", 8080, "server port")
host := pflag.StringP("host", "h", "localhost", "server host")
verbose := pflag.BoolP("verbose", "v", false, "verbose output")
config := pflag.String("config", "default.conf", "config file path")
// Add Go flags from third-party libraries
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// Parse all flags together
pflag.Parse()
// Check for required values
if *config == "" {
fmt.Fprintln(os.Stderr, "Error: --config is required")
pflag.Usage()
os.Exit(1)
}
// Use flags from both sources
if *verbose {
fmt.Printf("Starting server on %s:%d\n", *host, *port)
fmt.Printf("Config file: %s\n", *config)
fmt.Printf("Library timeout: %v\n", *libTimeout)
fmt.Printf("Library retries: %d\n", *libRetries)
}
// Process remaining arguments
files := pflag.Args()
if len(files) > 0 {
fmt.Printf("Processing %d files: %v\n", len(files), files)
}
}
// Usage:
// myapp -p 9090 -h 0.0.0.0 -v --config=prod.conf --lib-timeout=30s --lib-retries=5 file1.txt file2.txt-flag), pflag uses double dash (--flag)-f)-abc)--, Go flag stops at first non-flagShorthand field to Flag structParse(), Args(), Arg(), NArg() functionsimport flag "github.com/spf13/pflag"AddGoFlagSet to maintain compatibility with dependencies