Skip to content

Commit

Permalink
env.* support and possible to check require field after all config lo…
Browse files Browse the repository at this point in the history
…ading
  • Loading branch information
JohnJ255 committed Apr 9, 2024
1 parent 8ca6c6a commit c2eda10
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 12 deletions.
48 changes: 41 additions & 7 deletions cleanenv.go
Expand Up @@ -53,6 +53,10 @@ const (
TagEnvPrefix = "env-prefix"
)

var (
RequiredCheck = true
)

// Setter is an interface for a custom value setter.
//
// To implement a custom value setter you need to add a SetValue function to your type that will receive a string raw value:
Expand All @@ -75,6 +79,20 @@ type Updater interface {
Update() error
}

type unsupportedFileFormat struct {
ftype string
}

func (e *unsupportedFileFormat) Error() string {
return fmt.Sprintf("file format '%s' doesn't supported by the parser", e.ftype)
}

func newErrorUnsupportedFileFormat(ftype string) *unsupportedFileFormat {
return &unsupportedFileFormat{
ftype: ftype,
}
}

// ReadConfig reads configuration file and parses it depending on tags in structure provided.
// Then it reads and parses
//
Expand Down Expand Up @@ -134,8 +152,27 @@ func parseFile(path string, cfg interface{}) error {
}
defer f.Close()

ftype := "."
for ftype != "" {
ftype = strings.ToLower(filepath.Ext(path))
err = parseFileByType(ftype, f, cfg)
if err != nil {
if _, ok := err.(*unsupportedFileFormat); ok {
path = strings.TrimSuffix(path, filepath.Ext(path))
} else {
return fmt.Errorf("config file parsing error: %s", err.Error())
}
} else {
ftype = ""
}
}

return nil
}

func parseFileByType(ftype string, f *os.File, cfg interface{}) (err error) {
// parse the file depending on the file type
switch ext := strings.ToLower(filepath.Ext(path)); ext {
switch ftype {
case ".yaml", ".yml":
err = ParseYAML(f, cfg)
case ".json":
Expand All @@ -147,12 +184,9 @@ func parseFile(path string, cfg interface{}) error {
case ".env":
err = parseENV(f, cfg)
default:
return fmt.Errorf("file format '%s' doesn't supported by the parser", ext)
}
if err != nil {
return fmt.Errorf("config file parsing error: %s", err.Error())
return newErrorUnsupportedFileFormat(ftype)
}
return nil
return err
}

// ParseYAML parses YAML from reader to data structure
Expand Down Expand Up @@ -428,7 +462,7 @@ func readEnvVars(cfg interface{}, update bool) error {
}
}

if rawValue == nil && meta.required && meta.isFieldValueZero() {
if RequiredCheck && rawValue == nil && meta.required && meta.isFieldValueZero() {
return fmt.Errorf(
"field %q is required but the value is not provided",
meta.fieldName,
Expand Down
2 changes: 2 additions & 0 deletions example/parse_multiple_files/.env.local
@@ -0,0 +1,2 @@
DB_PORT=5435
DB_PASSWORD=password
2 changes: 1 addition & 1 deletion example/parse_multiple_files/README.md
@@ -1,5 +1,5 @@
# Parse multiple files for configuration

This example shows how the package can be used to read from mutiple configuration files and assign them to the same structure.
This example shows how the package can be used to read from multiple configuration files and assign them to the same structure.

In this example, the configuration is read from ```db_config.yaml```,```email_config.yaml``` and ```general_config.yaml``` and the values are stored in the ```config``` struct.
1 change: 0 additions & 1 deletion example/parse_multiple_files/db_config.yaml
@@ -1,7 +1,6 @@
database:
host: "localhost"
user: "root"
password: "password"
name: "cleanenv"
port: "5432"
ssl_mode: "disable"
6 changes: 3 additions & 3 deletions example/parse_multiple_files/main.go
Expand Up @@ -15,10 +15,10 @@ type config struct {

type databaseConfig struct {
User string `yaml:"user"`
Password string `yaml:"password"`
Password string `env-required:"true" yaml:"password" env:"DB_PASSWORD"`
Name string `yaml:"name"`
Host string `yaml:"host"`
Port string `yaml:"port"`
Port string `yaml:"port" env:"DB_PORT"`
SSLMode string `yaml:"ssl_mode"`
}

Expand All @@ -28,7 +28,7 @@ type emailService struct {
}

func main() {
cfg, err := ParseConfigFiles("./db_config.yaml", "./email_config.yaml", "./general_config.yaml")
cfg, err := ParseConfigFiles("./db_config.yaml", "./email_config.yaml", "./general_config.yaml", "./.env.local")
if err != nil {
log.Printf("Error parsing config files: %v", err)
return
Expand Down

0 comments on commit c2eda10

Please sign in to comment.