A collection of CLI argument types for the flag package.
import "github.com/sgreben/flagvar"Or just copy & paste what you need. It's public domain.
package main
import (
	"flag"
	"fmt"
	"github.com/sgreben/flagvar"
)
var (
	fruit    = flagvar.Enum{Choices: []string{"apple", "banana"}}
	urls     flagvar.URLs
	settings flagvar.Assignments
)
func main() {
	flag.Var(&fruit, "fruit", fmt.Sprintf("set a fruit (%s)", fruit.Help()))
	flag.Var(&urls, "url", "add a URL")
	flag.Var(&settings, "set", fmt.Sprintf("specify a setting (%s)", settings.Help()))
	flag.Parse()
}$ go run main.go -set abc=xyz -url https://github.com
# no error
$ go run main.go -set abc=xyz -url ://github.com
invalid value "://github.com" for flag -url: parse ://github.com: missing protocol scheme
$ go run main.go -fruit kiwi
invalid value "kiwi" for flag -fruit: "kiwi" must be one of [apple banana]
$ go run main.go -h
Usage:
  -fruit value
        set a fruit (one of [apple banana])
  -set value
        specify a setting (a key/value pair KEY=VALUE)
  -url value
        add a URL- Pluralized argument types (e.g. Strings,Assignments) can be specified repeatedly, the values are collected in a slice.
- The resulting value is stored in .Valuefor singular types and in.Valuesfor plural types
- The original argument string is stored in .Textfor singular types and in.Textsfor plural types
- -Set types (EnumSet,StringSet) de-duplicate provided values.
- -CSV types (IntsCSV,EnumsCSV) accept comma-separated values and accumulate values across flag instances if their.Accumulatefield is set totrue.
- Most types implement interface{ Help() string }, which produces a string suitable for inclusion in a help message.
Here's a compact overview:
| flagvartype | example CLI arg | type of resulting Go value | 
|---|---|---|
| Alternative | ||
| Assignment | KEY=VALUE | struct{Key,Value} | 
| Assignments | KEY=VALUE | []struct{Key,Value} | 
| AssignmentsMap | KEY=VALUE | map[string]string | 
| CIDR | 127.0.0.1/24 | struct{IPNet,IP} | 
| CIDRs | 127.0.0.1/24 | []struct{IPNet,IP} | 
| CIDRsCSV | 127.0.0.1/16,10.1.2.3/8 | []struct{IPNet,IP} | 
| Enum | apple | string | 
| Enums | apple | []string | 
| EnumsCSV | apple,banana | []string | 
| EnumSet | apple | []string | 
| EnumSetCSV | apple,banana | []string | 
| File | ./README.md | string | 
| Files | ./README.md | []string | 
| Floats | 1.234 | []float64 | 
| FloatsCSV | 1.234,5.0 | []float64 | 
| Glob | src/**.js | glob.Glob | 
| Globs | src/**.js | []glob.Glob | 
| Ints | 1002 | []int64 | 
| IntsCSV | 123,1002 | []int64 | 
| IP | 127.0.0.1 | net.IP | 
| IPs | 127.0.0.1 | []net.IP | 
| IPsCSV | 127.0.0.1,10.1.2.3 | []net.IP | 
| JSON | '{"a":1}' | interface{} | 
| JSONs | '{"a":1}' | []interface{} | 
| Regexp | [a-z]+ | *regexp.Regexp | 
| Regexps | [a-z]+ | []*regexp.Regexp | 
| Strings | "xyxy" | []string | 
| StringSet | "xyxy" | []string | 
| StringSetCSV | y,x,y | []string | 
| TCPAddr | 127.0.0.1:10 | net.TCPAddr | 
| TCPAddrs | 127.0.0.1:10 | []net.TCPAddr | 
| TCPAddrsCSV | 127.0.0.1:10,:123 | []net.TCPAddr | 
| Template | "{{.Size}}" | *template.Template | 
| Templates | "{{.Size}}" | []*template.Template | 
| TemplateFile | "/path/to/template.file" | string | 
| Time | "10:30 AM" | time.Time | 
| Times | "10:30 AM" | []time.Time | 
| TimeFormat | "RFC3339" | string | 
| UDPAddr | 127.0.0.1:10 | net.UDPAddr | 
| UDPAddrs | 127.0.0.1:10 | []net.UDPAddr | 
| UDPAddrsCSV | 127.0.0.1:10,:123 | []net.UDPAddr | 
| UnixAddr | /example.sock | net.UnixAddr | 
| UnixAddrs | /example.sock | []net.UnixAddr | 
| UnixAddrsCSV | /example.sock,/other.sock | []net.UnixAddr | 
| URL | https://github.com | *url.URL | 
| URLs | https://github.com | []*url.URL | 
| Wrap | ||
| WrapCSV | ||
| WrapFunc | ||
| WrapPointer | 
- Help avoid dependencies
- Self-contained > DRY
- Explicitly support copy & paste workflow
- Copyable units should be easy to determine
- Anonymous structs > shared types
 
- "Code-you-own" feeling, even when imported as a package
- No private fields / methods
- No magic
- Simple built-in types used wherever possible
- Avoid introducing new concepts
 
- Support "blind" usage
- Zero values should be useful
- Avoid introducing failure cases, handle any combination of parameters gracefully.
- All "obvious things to try" should work.