mcfg: use merr for returned errors, and make help output prioritize required params towards the top

This commit is contained in:
Brian Picciano 2019-01-24 22:02:04 -05:00
parent ef2e76de45
commit 05a69589bc
5 changed files with 25 additions and 9 deletions

View File

@ -7,6 +7,8 @@ import (
"reflect" "reflect"
"sort" "sort"
"strings" "strings"
"github.com/mediocregopher/mediocre-go-lib/merr"
) )
// SourceCLI is a Source which will parse configuration from the CLI. // SourceCLI is a Source which will parse configuration from the CLI.
@ -86,7 +88,8 @@ func (cli SourceCLI) Parse(params []Param) ([]ParamValue, error) {
break break
} }
if !pvOk { if !pvOk {
return nil, fmt.Errorf("unexpected config parameter %q", arg) err := merr.New("unexpected config parameter")
return nil, merr.WithValue(err, "param", arg, true)
} }
} }
@ -114,7 +117,8 @@ func (cli SourceCLI) Parse(params []Param) ([]ParamValue, error) {
pvStrValOk = false pvStrValOk = false
} }
if pvOk && !pvStrValOk { if pvOk && !pvStrValOk {
return nil, fmt.Errorf("param %q expected a value", key) err := merr.New("param expected a value")
return nil, merr.WithValue(err, "param", key, true)
} }
return pvs, nil return pvs, nil
} }
@ -140,6 +144,9 @@ func (cli SourceCLI) printHelp(w io.Writer, pM map[string]Param) {
} }
sort.Slice(pA, func(i, j int) bool { sort.Slice(pA, func(i, j int) bool {
if pA[i].Required != pA[j].Required {
return pA[i].Required
}
return pA[i].arg < pA[j].arg return pA[i].arg < pA[j].arg
}) })
@ -161,6 +168,8 @@ func (cli SourceCLI) printHelp(w io.Writer, pM map[string]Param) {
fmt.Fprintf(w, "\n%s", p.arg) fmt.Fprintf(w, "\n%s", p.arg)
if p.IsBool { if p.IsBool {
fmt.Fprintf(w, " (Flag)") fmt.Fprintf(w, " (Flag)")
} else if p.Required {
fmt.Fprintf(w, " (Required)")
} else if defVal := fmtDefaultVal(p.Into); defVal != "" { } else if defVal := fmtDefaultVal(p.Into); defVal != "" {
fmt.Fprintf(w, " (Default: %s)", defVal) fmt.Fprintf(w, " (Default: %s)", defVal)
} }

View File

@ -18,7 +18,8 @@ func TestSourceCLIHelp(t *T) {
Int(ctx, "foo", 5, "Test int param") Int(ctx, "foo", 5, "Test int param")
Bool(ctx, "bar", "Test bool param") Bool(ctx, "bar", "Test bool param")
String(ctx, "baz", "baz", "Test string param") String(ctx, "baz", "baz", "Test string param")
String(ctx, "baz2", "", "") RequiredString(ctx, "baz2", "")
RequiredString(ctx, "baz3", "")
src := SourceCLI{} src := SourceCLI{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
@ -27,14 +28,16 @@ func TestSourceCLIHelp(t *T) {
SourceCLI{}.printHelp(buf, pM) SourceCLI{}.printHelp(buf, pM)
exp := ` exp := `
--baz2 (Required)
--baz3 (Required)
--bar (Flag) --bar (Flag)
Test bool param Test bool param
--baz (Default: "baz") --baz (Default: "baz")
Test string param Test string param
--baz2
--foo (Default: 5) --foo (Default: 5)
Test int param Test int param

View File

@ -1,9 +1,10 @@
package mcfg package mcfg
import ( import (
"fmt"
"os" "os"
"strings" "strings"
"github.com/mediocregopher/mediocre-go-lib/merr"
) )
// SourceEnv is a Source which will parse configuration from the process // SourceEnv is a Source which will parse configuration from the process
@ -56,7 +57,8 @@ func (env SourceEnv) Parse(params []Param) ([]ParamValue, error) {
for _, kv := range kvs { for _, kv := range kvs {
split := strings.SplitN(kv, "=", 2) split := strings.SplitN(kv, "=", 2)
if len(split) != 2 { if len(split) != 2 {
return nil, fmt.Errorf("malformed environment kv %q", kv) err := merr.New("malformed environment key/value pair")
return nil, merr.WithValue(err, "kv", kv, true)
} }
k, v := split[0], split[1] k, v := split[0], split[1]
if p, ok := pM[k]; ok { if p, ok := pM[k]; ok {

View File

@ -4,10 +4,10 @@ package mcfg
import ( import (
"encoding/json" "encoding/json"
"fmt"
"sort" "sort"
"github.com/mediocregopher/mediocre-go-lib/mctx" "github.com/mediocregopher/mediocre-go-lib/mctx"
"github.com/mediocregopher/mediocre-go-lib/merr"
) )
// TODO Sources: // TODO Sources:
@ -97,7 +97,8 @@ func populate(params []Param, src Source) error {
if !param.Required { if !param.Required {
continue continue
} else if _, ok := pvM[param.hash()]; !ok { } else if _, ok := pvM[param.hash()]; !ok {
return fmt.Errorf("param %q is required", param.fullName()) err := merr.New("required parameter is not set")
return merr.WithValue(err, "param", param.fullName(), true)
} }
} }

View File

@ -44,6 +44,7 @@ func (ss Sources) Parse(params []Param) ([]ParamValue, error) {
// variables. // variables.
type SourceMap map[string]string type SourceMap map[string]string
// Parse implements the method for the Source interface.
func (m SourceMap) Parse(params []Param) ([]ParamValue, error) { func (m SourceMap) Parse(params []Param) ([]ParamValue, error) {
pvs := make([]ParamValue, 0, len(m)) pvs := make([]ParamValue, 0, len(m))
for _, p := range params { for _, p := range params {