Skip to content

Commit

Permalink
Merge pull request #47 from crazy-max/reflect-time
Browse files Browse the repository at this point in the history
handle time.Time reflection
  • Loading branch information
crazy-max committed May 5, 2023
2 parents 1d79a6d + 88a2348 commit 5591457
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 76 deletions.
13 changes: 7 additions & 6 deletions _example/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package config

// Config holds configuration details
type Config struct {
Timezone string `yaml:"timezone,omitempty" json:"timezone,omitempty"`
LogLevel string `yaml:"logLevel,omitempty" json:"logLevel,omitempty"`
LogJSON bool `yaml:"logJSON,omitempty" json:"logJSON,omitempty"`
Db *Db `yaml:"db,omitempty" json:"db,omitempty"`
Server *Server `yaml:"server,omitempty" json:"server,omitempty"`
Notif *Notif `yaml:"notif,omitempty" json:"notif,omitempty"`
Timezone string `yaml:"timezone,omitempty" json:"timezone,omitempty"`
LogLevel string `yaml:"logLevel,omitempty" json:"logLevel,omitempty"`
LogJSON bool `yaml:"logJSON,omitempty" json:"logJSON,omitempty"`
Db *Db `yaml:"db,omitempty" json:"db,omitempty"`
Server *Server `yaml:"server,omitempty" json:"server,omitempty"`
Download *Download `yaml:"download,omitempty" json:"download,omitempty" validate:"required"`
Notif *Notif `yaml:"notif,omitempty" json:"notif,omitempty"`
}
42 changes: 42 additions & 0 deletions _example/config/config_download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package config

import (
"os"
"time"
)

// Download holds download configuration details
type Download struct {
Output string `yaml:"output,omitempty" json:"output,omitempty" validate:"required,dir"`
UID int `yaml:"uid,omitempty" json:"uid,omitempty"`
GID int `yaml:"gid,omitempty" json:"gid,omitempty"`
ChmodFile os.FileMode `yaml:"chmodFile,omitempty" json:"chmodFile,omitempty"`
ChmodDir os.FileMode `yaml:"chmodDir,omitempty" json:"chmodDir,omitempty"`
Include []string `yaml:"include,omitempty" json:"include,omitempty"`
Exclude []string `yaml:"exclude,omitempty" json:"exclude,omitempty"`
Since string `yaml:"since,omitempty" json:"since,omitempty"`
SinceTime time.Time `yaml:"-" json:"-" label:"-" file:"-"`
Retry int `yaml:"retry,omitempty" json:"retry,omitempty"`
HideSkipped *bool `yaml:"hideSkipped,omitempty" json:"hideSkipped,omitempty"`
TempFirst *bool `yaml:"tempFirst,omitempty" json:"tempFirst,omitempty"`
CreateBaseDir *bool `yaml:"createBaseDir,omitempty" json:"createBaseDir,omitempty"`
}

// GetDefaults gets the default values
func (s *Download) GetDefaults() *Download {
n := &Download{}
n.SetDefaults()
return n
}

// SetDefaults sets the default values
func (s *Download) SetDefaults() {
s.UID = os.Getuid()
s.GID = os.Getgid()
s.ChmodFile = 0o644
s.ChmodDir = 0o755
s.Retry = 3
s.HideSkipped = NewFalse()
s.TempFirst = NewFalse()
s.CreateBaseDir = NewFalse()
}
16 changes: 13 additions & 3 deletions _example/config/config_server_ftp.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package config

import "time"
import (
"time"
)

// ServerFTP holds ftp server configuration
type ServerFTP struct {
Host string `yaml:"host,omitempty" json:"host,omitempty"`
Port int `yaml:"port,omitempty" json:"port,omitempty"`
Host string `yaml:"host,omitempty" json:"host,omitempty" validate:"required"`
Port int `yaml:"port,omitempty" json:"port,omitempty" validate:"required,min=1"`
Username string `yaml:"username,omitempty" json:"username,omitempty"`
UsernameFile string `yaml:"usernameFile,omitempty" json:"usernameFile,omitempty" validate:"omitempty,file"`
Password string `yaml:"password,omitempty" json:"password,omitempty"`
PasswordFile string `yaml:"passwordFile,omitempty" json:"passwordFile,omitempty" validate:"omitempty,file"`
Sources []string `yaml:"sources,omitempty" json:"sources,omitempty"`
Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty"`
DisableUTF8 *bool `yaml:"disableUTF8,omitempty" json:"disableUTF8,omitempty"`
DisableEPSV *bool `yaml:"disableEPSV,omitempty" json:"disableEPSV,omitempty"`
DisableMLSD *bool `yaml:"disableMLSD,omitempty" json:"disableMLSD,omitempty"`
EscapeRegexpMeta *bool `yaml:"escapeRegexpMeta,omitempty" json:"escapeRegexpMeta,omitempty"`
TLS *bool `yaml:"tls,omitempty" json:"tls,omitempty"`
InsecureSkipVerify *bool `yaml:"insecureSkipVerify,omitempty" json:"insecureSkipVerify,omitempty"`
LogTrace *bool `yaml:"logTrace,omitempty" json:"logTrace,omitempty"`
Expand All @@ -28,7 +35,10 @@ func (s *ServerFTP) SetDefaults() {
s.Port = 21
s.Sources = []string{}
s.Timeout = NewDuration(5 * time.Second)
s.DisableUTF8 = NewFalse()
s.DisableEPSV = NewFalse()
s.DisableMLSD = NewFalse()
s.EscapeRegexpMeta = NewFalse()
s.TLS = NewFalse()
s.InsecureSkipVerify = NewFalse()
s.LogTrace = NewFalse()
Expand Down
7 changes: 7 additions & 0 deletions file/raw_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"sort"
"strconv"
"strings"
"time"

"github.com/crazy-max/gonfig/parser"
)
Expand Down Expand Up @@ -121,6 +122,12 @@ func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) error
if err != nil {
return err
}
case reflect.Struct:
if value.Type() == reflect.TypeOf(time.Time{}) {
child.Value = value.Interface().(time.Time).Format(time.RFC3339Nano)
} else {
return fmt.Errorf("field %s uses unsupported type: %s", child.Name, value.Kind().String())
}
default:
return fmt.Errorf("field %s uses unsupported type: %s", child.Name, value.Kind().String())
}
Expand Down
21 changes: 19 additions & 2 deletions fixtures/config.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,32 @@ server:
sources:
- /
timeout: 5s
disableUTF8: true
disableEPSV: false
disableMLSD: false
tls: false
insecureSkipVerify: false
logTrace: false

download:
output: ./fixtures/downloads
uid: 1000
gid: 1000
chmodFile: 0o644
chmodDir: 0o755
include:
- ^Foo\.Bar\.S01.+(VOSTFR|SUBFRENCH).+(720p).+(HDTV|WEB-DL|WEBRip).+
exclude:
- \.nfo$
since: 2019-02-01T18:50:05Z
retry: 3
hideSkipped: false
createBaseDir: false

notif:
mail:
host: localhost
port: 25
host: smtp.example.com
port: 587
ssl: false
insecureSkipVerify: false
from: from@example.com
Expand Down
83 changes: 26 additions & 57 deletions loader_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gonfig

import (
"os"
"strings"
"testing"
"time"
Expand All @@ -13,8 +12,6 @@ import (
)

func TestEnvLoader(t *testing.T) {
defer UnsetEnv(env.DefaultNamePrefix)

testCases := []struct {
desc string
cfgfile string
Expand Down Expand Up @@ -50,7 +47,10 @@ func TestEnvLoader(t *testing.T) {
"/",
},
Timeout: example.NewDuration(5 * time.Second),
DisableUTF8: example.NewFalse(),
DisableEPSV: example.NewFalse(),
DisableMLSD: example.NewFalse(),
EscapeRegexpMeta: example.NewFalse(),
TLS: example.NewFalse(),
InsecureSkipVerify: example.NewFalse(),
LogTrace: example.NewFalse(),
Expand All @@ -63,12 +63,10 @@ func TestEnvLoader(t *testing.T) {

for _, tt := range testCases {
t.Run(tt.desc, func(t *testing.T) {
UnsetEnv(env.DefaultNamePrefix)

if tt.environ != nil {
for _, environ := range tt.environ {
n := strings.SplitN(environ, "=", 2)
os.Setenv(n[0], n[1])
t.Setenv(n[0], n[1])
}
}

Expand Down Expand Up @@ -125,16 +123,33 @@ func TestFileLoader(t *testing.T) {
"/",
},
Timeout: example.NewDuration(5 * time.Second),
DisableUTF8: example.NewTrue(),
DisableEPSV: example.NewFalse(),
DisableMLSD: example.NewFalse(),
EscapeRegexpMeta: example.NewFalse(),
TLS: example.NewFalse(),
InsecureSkipVerify: example.NewFalse(),
LogTrace: example.NewFalse(),
},
},
Download: &example.Download{
Output: "./fixtures/downloads",
UID: 1000,
GID: 1000,
ChmodFile: 0o644,
ChmodDir: 0o755,
Include: []string{`^Foo\.Bar\.S01.+(VOSTFR|SUBFRENCH).+(720p).+(HDTV|WEB-DL|WEBRip).+`},
Exclude: []string{`\.nfo$`},
Since: "2019-02-01T18:50:05Z",
Retry: 3,
HideSkipped: example.NewFalse(),
TempFirst: example.NewFalse(),
CreateBaseDir: example.NewFalse(),
},
Notif: &example.Notif{
Mail: &example.NotifMail{
Host: "localhost",
Port: 25,
Host: "smtp.example.com",
Port: 587,
SSL: example.NewFalse(),
InsecureSkipVerify: example.NewFalse(),
From: "from@example.com",
Expand Down Expand Up @@ -211,7 +226,10 @@ func TestFlagLoader(t *testing.T) {
"/src2",
},
Timeout: example.NewDuration(5 * time.Second),
DisableUTF8: example.NewFalse(),
DisableEPSV: example.NewTrue(),
DisableMLSD: example.NewFalse(),
EscapeRegexpMeta: example.NewFalse(),
TLS: example.NewFalse(),
InsecureSkipVerify: example.NewFalse(),
LogTrace: example.NewFalse(),
Expand Down Expand Up @@ -241,52 +259,3 @@ func TestFlagLoader(t *testing.T) {
})
}
}

func UnsetEnv(prefix string) (restore func()) {
before := map[string]string{}

for _, e := range os.Environ() {
if !strings.HasPrefix(e, prefix) {
continue
}

parts := strings.SplitN(e, "=", 2)
before[parts[0]] = parts[1]

os.Unsetenv(parts[0])
}

return func() {
after := map[string]string{}

for _, e := range os.Environ() {
if !strings.HasPrefix(e, prefix) {
continue
}

parts := strings.SplitN(e, "=", 2)
after[parts[0]] = parts[1]

// Check if the envar previously existed
v, ok := before[parts[0]]
if !ok {
// This is a newly added envar with prefix, zap it
os.Unsetenv(parts[0])
continue
}

if parts[1] != v {
// If the envar value has changed, set it back
os.Setenv(parts[0], v)
}
}

// Still need to check if there have been any deleted envars
for k, v := range before {
if _, ok := after[k]; !ok {
// k is not present in after, so we set it.
os.Setenv(k, v)
}
}
}
}
21 changes: 13 additions & 8 deletions parser/nodes_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"reflect"
"strings"
"time"
)

// MetadataOpts Options for the metadata.
Expand Down Expand Up @@ -75,13 +76,15 @@ func (m metadata) add(rootType reflect.Type, node *Node) error {
node.Kind = fType.Kind()
node.Tag = field.Tag

if fType.Kind() == reflect.Struct || fType.Kind() == reflect.Pointer && fType.Elem().Kind() == reflect.Struct ||
fType.Kind() == reflect.Map {
if len(node.Children) == 0 && !(field.Tag.Get(m.TagName) == TagLabelAllowEmpty || field.Tag.Get(m.TagName) == "-") {
return fmt.Errorf("%s cannot be a standalone element (type %s)", node.Name, fType)
}
if fType != reflect.TypeOf(time.Time{}) {
if fType.Kind() == reflect.Struct || fType.Kind() == reflect.Pointer && fType.Elem().Kind() == reflect.Struct ||
fType.Kind() == reflect.Map {
if len(node.Children) == 0 && !(field.Tag.Get(m.TagName) == TagLabelAllowEmpty || field.Tag.Get(m.TagName) == "-") {
return fmt.Errorf("%s cannot be a standalone element (type %s)", node.Name, fType)
}

node.Disabled = len(node.Value) > 0 && !strings.EqualFold(node.Value, "true") && field.Tag.Get(m.TagName) == TagLabelAllowEmpty
node.Disabled = len(node.Value) > 0 && !strings.EqualFold(node.Value, "true") && field.Tag.Get(m.TagName) == TagLabelAllowEmpty
}
}

node.Disabled = node.Disabled || field.Tag.Get(m.TagName) == "-"
Expand All @@ -90,8 +93,10 @@ func (m metadata) add(rootType reflect.Type, node *Node) error {
return nil
}

if fType.Kind() == reflect.Struct || fType.Kind() == reflect.Pointer && fType.Elem().Kind() == reflect.Struct {
return m.browseChildren(fType, node)
if fType != reflect.TypeOf(time.Time{}) {
if fType.Kind() == reflect.Struct || fType.Kind() == reflect.Pointer && fType.Elem().Kind() == reflect.Struct {
return m.browseChildren(fType, node)
}
}

if fType.Kind() == reflect.Map {
Expand Down

0 comments on commit 5591457

Please sign in to comment.