@@ -57,11 +57,11 @@ import (
5757
5858// ErrInvalidArgument is the error returned by [ParseFlags] or [FromYAMLFile] if
5959// its parsing result cannot be stored in the value pointed to by the designated passed argument which
60- // must be a non-nil pointer.
60+ // must be a non-nil struct pointer.
6161var ErrInvalidArgument = stderrors .New ("invalid argument" )
6262
6363// FromYAMLFile parses the given YAML file and stores the result
64- // in the value pointed to by v. If v is nil or not a pointer,
64+ // in the value pointed to by v. If v is nil or not a struct pointer,
6565// FromYAMLFile returns an [ErrInvalidArgument] error.
6666// It is possible to define default values via the struct tag `default`.
6767// The function also validates the configuration using the Validate method
@@ -91,12 +91,11 @@ var ErrInvalidArgument = stderrors.New("invalid argument")
9191// // ...
9292// }
9393func FromYAMLFile (name string , v Validator ) error {
94- rv := reflect .ValueOf (v )
95- if rv .Kind () != reflect .Pointer || rv .IsNil () {
96- return errors .Wrapf (ErrInvalidArgument , "non-nil pointer expected, got %T" , v )
94+ if err := validateNonNilStructPointer (v ); err != nil {
95+ return errors .WithStack (err )
9796 }
9897
99- // #nosec G304 -- Potential file inclusion via variable - Its purpose is to load any file name that is passed to it, so doesn't need to validate anything .
98+ // #nosec G304 -- Accept user-controlled input for config file.
10099 f , err := os .Open (name )
101100 if err != nil {
102101 return errors .Wrap (err , "can't open YAML file " + name )
@@ -125,11 +124,10 @@ func FromYAMLFile(name string, v Validator) error {
125124type EnvOptions = env.Options
126125
127126// FromEnv parses environment variables and stores the result in the value pointed to by v.
128- // If v is nil or not a pointer, FromEnv returns an [ErrInvalidArgument] error.
127+ // If v is nil or not a struct pointer, FromEnv returns an [ErrInvalidArgument] error.
129128func FromEnv (v Validator , options EnvOptions ) error {
130- rv := reflect .ValueOf (v )
131- if rv .Kind () != reflect .Ptr || rv .IsNil () {
132- return errors .Wrapf (ErrInvalidArgument , "non-nil pointer expected, got %T" , v )
129+ if err := validateNonNilStructPointer (v ); err != nil {
130+ return errors .WithStack (err )
133131 }
134132
135133 if err := defaults .Set (v ); err != nil {
@@ -148,7 +146,7 @@ func FromEnv(v Validator, options EnvOptions) error {
148146}
149147
150148// ParseFlags parses CLI flags and stores the result
151- // in the value pointed to by v. If v is nil or not a pointer,
149+ // in the value pointed to by v. If v is nil or not a struct pointer,
152150// ParseFlags returns an [ErrInvalidArgument] error.
153151// ParseFlags adds a default Help Options group,
154152// which contains the options -h and --help.
@@ -172,17 +170,16 @@ func FromEnv(v Validator, options EnvOptions) error {
172170// // ...
173171// }
174172func ParseFlags (v any ) error {
175- rv := reflect .ValueOf (v )
176- if rv .Kind () != reflect .Pointer || rv .IsNil () {
177- return errors .Wrapf (ErrInvalidArgument , "non-nil pointer expected, got %T" , v )
173+ if err := validateNonNilStructPointer (v ); err != nil {
174+ return errors .WithStack (err )
178175 }
179176
180177 parser := flags .NewParser (v , flags .Default ^ flags .PrintErrors )
181178
182179 if _ , err := parser .Parse (); err != nil {
183180 var flagErr * flags.Error
184- if errors .As (err , & flagErr ) && flagErr .Type == flags .ErrHelp {
185- fmt .Fprintln (os .Stdout , flagErr )
181+ if errors .As (err , & flagErr ) && errors . Is ( flagErr .Type , flags .ErrHelp ) {
182+ _ , _ = fmt .Fprintln (os .Stdout , flagErr )
186183 os .Exit (0 )
187184 }
188185
@@ -191,3 +188,14 @@ func ParseFlags(v any) error {
191188
192189 return nil
193190}
191+
192+ // validateNonNilStructPointer checks if the provided value is a non-nil pointer to a struct.
193+ // It returns an error if the value is not a pointer, is nil, or does not point to a struct.
194+ func validateNonNilStructPointer (v any ) error {
195+ rv := reflect .ValueOf (v )
196+ if rv .Kind () != reflect .Pointer || rv .IsNil () || rv .Elem ().Kind () != reflect .Struct {
197+ return errors .Wrapf (ErrInvalidArgument , "non-nil struct pointer expected, got %T" , v )
198+ }
199+
200+ return nil
201+ }
0 commit comments