mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-28 11:25:20 +01:00
99 lines
2.0 KiB
Go
99 lines
2.0 KiB
Go
|
// Package choice implements a flag.Value type that accepts a set of choices.
|
||
|
//
|
||
|
// See test cases or grep the code base for usage hints.
|
||
|
package choices
|
||
|
|
||
|
import (
|
||
|
"flag"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type Choices struct {
|
||
|
choices map[string]interface{}
|
||
|
typeString string
|
||
|
value interface{}
|
||
|
}
|
||
|
|
||
|
var _ flag.Value = (*Choices)(nil)
|
||
|
|
||
|
func new(pairs ...interface{}) Choices {
|
||
|
if (len(pairs) % 2) != 0 {
|
||
|
panic("must provide a sequence of key value pairs")
|
||
|
}
|
||
|
c := Choices{
|
||
|
choices: make(map[string]interface{}, len(pairs)/2),
|
||
|
value: nil,
|
||
|
}
|
||
|
for i := 0; i < len(pairs); {
|
||
|
key, ok := pairs[i].(string)
|
||
|
if !ok {
|
||
|
panic(fmt.Sprintf("argument %d is %T but should be a string, value: %#v", i, pairs[i], pairs[i]))
|
||
|
}
|
||
|
c.choices[key] = pairs[i+1]
|
||
|
i += 2
|
||
|
}
|
||
|
c.typeString = strings.Join(c.choicesList(true), ",") // overrideable by setter
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (c *Choices) Init(pairs ...interface{}) {
|
||
|
*c = new(pairs...)
|
||
|
}
|
||
|
|
||
|
func (c Choices) choicesList(escaped bool) []string {
|
||
|
keys := make([]string, len(c.choices))
|
||
|
i := 0
|
||
|
for k := range c.choices {
|
||
|
e := k
|
||
|
if escaped {
|
||
|
e = fmt.Sprintf("%q", k)
|
||
|
}
|
||
|
keys[i] = e
|
||
|
i += 1
|
||
|
}
|
||
|
return keys
|
||
|
}
|
||
|
|
||
|
func (c Choices) Usage() string {
|
||
|
return fmt.Sprintf("one of %s", strings.Join(c.choicesList(true), ","))
|
||
|
}
|
||
|
|
||
|
func (c Choices) InputForChoice(v interface{}) (string, error) {
|
||
|
for input, choice := range c.choices {
|
||
|
if choice == v {
|
||
|
return input, nil
|
||
|
}
|
||
|
}
|
||
|
return "", fmt.Errorf("choice not registered at .Init(): %v", v)
|
||
|
}
|
||
|
|
||
|
func (c *Choices) SetDefaultValue(v interface{}) {
|
||
|
c.value = v
|
||
|
}
|
||
|
|
||
|
func (c Choices) Value() interface{} {
|
||
|
return c.value
|
||
|
}
|
||
|
|
||
|
func (c *Choices) Set(input string) error {
|
||
|
v, ok := c.choices[input]
|
||
|
if !ok {
|
||
|
return fmt.Errorf("invalid value %q: must be one of %s", input, c.Usage())
|
||
|
}
|
||
|
c.value = v
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *Choices) String() string {
|
||
|
return "" // c.value.(fmt.Stringer).String()
|
||
|
}
|
||
|
|
||
|
func (c *Choices) SetTypeString(ts string) {
|
||
|
c.typeString = ts
|
||
|
}
|
||
|
|
||
|
func (c *Choices) Type() string {
|
||
|
return c.typeString
|
||
|
}
|