diff --git a/README.md b/README.md index 574ffd0..5681a59 100644 --- a/README.md +++ b/README.md @@ -176,15 +176,18 @@ If you specify description in description tag (`desc` by default) it will be use ```golang Addr string `desc:"HTTP host"` +```` +This description produces something like: ```sh -this description produces something like: -``` -addr value HTTP host (default 127.0.0.1) ``` ## Options for env tag - +If you specify environment variable name in `env` tag, it will be used to set the value of the field. +```golang +SSL bool `env:"HTTP_SSL_VALUE"` +``` ## Options for Parse function: @@ -212,8 +215,14 @@ func EnvDivider(val string) // Check existed validators in sflags/validator package. func Validator(val ValidateFunc) -// Set to false if you don't want anonymous structure fields to be flatten. +// Set to false if you don't want anonymous structure fields to be flattened. func Flatten(val bool) + +// InheritHidden sets if fields should inherit the value of the hidden tag from parent structs. +func InheritHidden() + +// InheritDeprecated sets if fields should inherit the value of the deprecated tag from parent structs. +func InheritDeprecated() ``` diff --git a/parser.go b/parser.go index 47a7c60..dcd7b4f 100644 --- a/parser.go +++ b/parser.go @@ -7,12 +7,16 @@ import ( ) const ( - defaultDescTag = "desc" - defaultFlagTag = "flag" - defaultEnvTag = "env" - defaultFlagDivider = "-" - defaultEnvDivider = "_" - defaultFlatten = true + defaultDescTag = "desc" + defaultFlagTag = "flag" + defaultEnvTag = "env" + defaultFlagDivider = "-" + defaultEnvDivider = "_" + defaultFlatten = true + defaultInheritHidden = false + defaultHidden = false + defaultInheritDeprecated = false + defaultDeprecated = false ) // ValidateFunc describes a validation func, @@ -22,14 +26,18 @@ const ( type ValidateFunc func(val string, field reflect.StructField, cfg interface{}) error type opts struct { - descTag string - flagTag string - prefix string - envPrefix string - flagDivider string - envDivider string - flatten bool - validator ValidateFunc + descTag string + flagTag string + prefix string + envPrefix string + flagDivider string + envDivider string + flatten bool + validator ValidateFunc + inheritHidden bool + hidden bool + inheritDeprecated bool + deprecated bool } func (o opts) apply(optFuncs ...OptFunc) opts { @@ -51,6 +59,22 @@ func FlagTag(val string) OptFunc { return func(opt *opts) { opt.flagTag = val } // Prefix sets prefix that will be applied for all flags (if they are not marked as ~). func Prefix(val string) OptFunc { return func(opt *opts) { opt.prefix = val } } +// InheritHidden enables inheriting the hidden flag for all nested flags if set for a parent flag +func InheritHidden() OptFunc { return func(opt *opts) { opt.inheritHidden = true } } + +// hidden sets the hidden flag for all nested flags if set for a parent flag +func hidden(val bool) OptFunc { + return func(opt *opts) { opt.hidden = val } +} + +// InheritDeprecated enables inheriting the deprecated flag for all nested flags if set for a parent flag +func InheritDeprecated() OptFunc { return func(opt *opts) { opt.inheritDeprecated = true } } + +// deprecated sets the deprecated flag for all nested flags if set for a parent flag +func deprecated(val bool) OptFunc { + return func(opt *opts) { opt.deprecated = val } +} + // EnvPrefix sets prefix that will be applied for all environment variables (if they are not marked as ~). func EnvPrefix(val string) OptFunc { return func(opt *opts) { opt.envPrefix = val } } @@ -82,11 +106,15 @@ func hasOption(options []string, option string) bool { func defOpts() opts { return opts{ - descTag: defaultDescTag, - flagTag: defaultFlagTag, - flagDivider: defaultFlagDivider, - envDivider: defaultEnvDivider, - flatten: defaultFlatten, + descTag: defaultDescTag, + flagTag: defaultFlagTag, + flagDivider: defaultFlagDivider, + envDivider: defaultEnvDivider, + flatten: defaultFlatten, + inheritHidden: defaultInheritHidden, + hidden: defaultHidden, + inheritDeprecated: defaultInheritDeprecated, + deprecated: defaultDeprecated, } } @@ -120,6 +148,13 @@ func parseFlagTag(field reflect.StructField, opt opts) *Flag { if opt.prefix != "" && !ignoreFlagPrefix { flag.Name = opt.prefix + flag.Name } + + if opt.deprecated { + flag.Deprecated = opt.deprecated + } + if opt.hidden { + flag.Hidden = opt.hidden + } return &flag } @@ -264,9 +299,16 @@ fields: prefix = opt.prefix } + nestedOpts := []OptFunc{copyOpts(opt), Prefix(prefix)} + if opt.inheritHidden { + nestedOpts = append(nestedOpts, hidden(flag.Hidden)) + } + if opt.inheritDeprecated { + nestedOpts = append(nestedOpts, deprecated(flag.Deprecated)) + } + nestedFlags, val := parseVal(fieldValue, - copyOpts(opt), - Prefix(prefix), + nestedOpts..., ) // field contains a simple value. diff --git a/parser_test.go b/parser_test.go index 8cf3a2f..0a5f586 100644 --- a/parser_test.go +++ b/parser_test.go @@ -96,6 +96,58 @@ func TestParseStruct(t *testing.T) { }, }, } + hiddenNestedCfg := &struct { + Sub struct { + Name string + Sub2 struct { + Name string + } + } `flag:",hidden"` + Sub3 struct { + Name string + } + }{ + Sub: struct { + Name string + Sub2 struct { + Name string + } + }{ + Name: "name_value", + Sub2: struct{ Name string }{ + Name: "other_value", + }, + }, + Sub3: struct{ Name string }{ + Name: "name_value", + }, + } + deprecatedNestedCfg := &struct { + Sub struct { + Name string + Sub2 struct { + Name string + } + } `flag:",deprecated"` + Sub3 struct { + Name string + } + }{ + Sub: struct { + Name string + Sub2 struct { + Name string + } + }{ + Name: "name_value", + Sub2: struct{ Name string }{ + Name: "other_value", + }, + }, + Sub3: struct{ Name string }{ + Name: "name_value", + }, + } descCfg := &struct { Name string `desc:"name description"` Name2 string `description:"name2 description"` @@ -347,6 +399,60 @@ func TestParseStruct(t *testing.T) { }, expErr: nil, }, + { + name: "Inherit hidden parent flag", + cfg: hiddenNestedCfg, + optFuncs: []OptFunc{InheritHidden()}, + expFlagSet: []*Flag{ + { + Name: "sub-name", + EnvNames: []string{"SUB_NAME"}, + DefValue: "name_value", + Value: newStringValue(&hiddenNestedCfg.Sub.Name), + Hidden: true, + }, + { + Name: "sub-sub2-name", + EnvNames: []string{"SUB_SUB2_NAME"}, + DefValue: "other_value", + Value: newStringValue(&hiddenNestedCfg.Sub.Sub2.Name), + Hidden: true, + }, + { + Name: "sub3-name", + EnvNames: []string{"SUB3_NAME"}, + DefValue: "name_value", + Value: newStringValue(&hiddenNestedCfg.Sub3.Name), + }, + }, + }, + { + name: "Inherit deprecated parent flag", + cfg: deprecatedNestedCfg, + optFuncs: []OptFunc{InheritDeprecated()}, + expFlagSet: []*Flag{ + { + Name: "sub-name", + EnvNames: []string{"SUB_NAME"}, + DefValue: "name_value", + Value: newStringValue(&deprecatedNestedCfg.Sub.Name), + Deprecated: true, + }, + { + Name: "sub-sub2-name", + EnvNames: []string{"SUB_SUB2_NAME"}, + DefValue: "other_value", + Value: newStringValue(&deprecatedNestedCfg.Sub.Sub2.Name), + Deprecated: true, + }, + { + Name: "sub3-name", + EnvNames: []string{"SUB3_NAME"}, + DefValue: "name_value", + Value: newStringValue(&deprecatedNestedCfg.Sub3.Name), + }, + }, + }, { name: "DescCfg with custom desc tag", cfg: descCfg,