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:
flagvar type |
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.