diff --git a/import.go b/import.go index 28bc4657d5640fa1bdb6a4e98e17397eaa711a0f..6234a0bf196233b370a1551711fc485bd681f992 100644 --- a/import.go +++ b/import.go @@ -94,40 +94,123 @@ func (s *Settings[C]) importStreams() { } } -func replacePath(p string, c any) { - - if reflect.TypeOf(c).Kind() != reflect.Ptr { +//// replacePath replaces all pathInterface fields in the struct with the given path +//func replacePath(p string, c any) { +// +// if reflect.TypeOf(c).Kind() != reflect.Ptr { +// panic("c must be a pointer") +// } +// +// if reflect.TypeOf(c).Elem().Kind() != reflect.Struct { +// panic("c must be a pointer to a struct") +// } +// +// fields := reflect.VisibleFields(reflect.TypeOf(c).Elem()) +// for _, field := range fields { +// +// r := reflect.ValueOf(c).Elem().FieldByName(field.Name) +// if field.Type.Kind() == reflect.Struct { +// if r.CanAddr() { +// replacePath(p, r.Addr().Interface()) +// } +// continue +// } +// +// _, ok := r.Interface().(pathInterface) +// if ok { +// +// if r.CanSet() { +// if !path.IsAbs(r.String()) { +// r.SetString(path.Join(p, r.String())) +// } +// } +// continue +// +// } +// +// if r.Kind() == reflect.Slice { +// for i := 0; i < r.Len(); i++ { +// if r.Index(i).CanAddr() { +// replacePath(p, r.Index(i).Addr().Interface()) +// } +// } +// } else if r.Kind() == reflect.Map { +// for _, k := range r.MapKeys() { +// if r.MapIndex(k).CanAddr() { +// replacePath(p, r.MapIndex(k).Addr().Interface()) +// } +// } +// } else if r.Kind() == reflect.Ptr { +// if r.Elem().CanAddr() { +// replacePath(p, r.Elem().Addr().Interface()) +// } +// } else if r.Kind() == reflect.Interface { +// if r.Elem().CanAddr() { +// replacePath(p, r.Elem().Addr().Interface()) +// } +// } +// +// } +// +//} + +func replacePath(p string, c interface{}) { + cValue := reflect.ValueOf(c) + cType := cValue.Type() + + if cType.Kind() != reflect.Ptr { panic("c must be a pointer") } - if reflect.TypeOf(c).Elem().Kind() != reflect.Struct { + if cType.Elem().Kind() != reflect.Struct { panic("c must be a pointer to a struct") } - fields := reflect.VisibleFields(reflect.TypeOf(c).Elem()) + fields := reflect.VisibleFields(cType.Elem()) for _, field := range fields { + r := cValue.Elem().FieldByName(field.Name) + handleField(p, r) + } +} - r := reflect.ValueOf(c).Elem().FieldByName(field.Name) - if field.Type.Kind() == reflect.Struct { - if r.CanAddr() { - replacePath(p, r.Addr().Interface()) - } - continue +func handleField(p string, r reflect.Value) { + switch r.Kind() { + case reflect.Struct: + if r.CanAddr() { + replacePath(p, r.Addr().Interface()) } - - _, ok := r.Interface().(pathInterface) - if ok { - - if r.CanSet() { - if !path.IsAbs(r.String()) { - r.SetString(path.Join(p, r.String())) - } + case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface: + forEachElem(r, func(e reflect.Value) { + if e.CanAddr() { + replacePath(p, e.Addr().Interface()) + } + }) + default: + // Check for pathInterface + if v, ok := r.Interface().(pathInterface); ok { + currentPath := v.String() + if r.CanSet() && !path.IsAbs(currentPath) { + r.SetString(path.Join(p, currentPath)) } - } - } +} +func forEachElem(r reflect.Value, fn func(e reflect.Value)) { + switch r.Kind() { + case reflect.Slice: + for i := 0; i < r.Len(); i++ { + fn(r.Index(i)) + } + case reflect.Map: + for _, k := range r.MapKeys() { + fn(r.MapIndex(k)) + } + case reflect.Ptr, reflect.Interface: + if !r.IsNil() { + fn(r.Elem()) + } + } } func (s *Settings[C]) importFiles() { @@ -148,7 +231,7 @@ func (s *Settings[C]) importFiles() { f, err := s.files.fs.Open(fn) if os.IsNotExist(err) { - f.Close() + _ = f.Close() continue } @@ -156,7 +239,7 @@ func (s *Settings[C]) importFiles() { s.importStream(reader{s.files.format, r}, func(c *C) { replacePath(d, c) }) - f.Close() + _ = f.Close() } for _, f := range s.files.files { @@ -164,7 +247,7 @@ func (s *Settings[C]) importFiles() { if err != nil { s.errors = append(s.errors, err) - r.Close() + _ = r.Close() continue } @@ -173,7 +256,7 @@ func (s *Settings[C]) importFiles() { replacePath(d, c) }) - r.Close() + _ = r.Close() } } diff --git a/import_test.go b/import_test.go index f282f9701a1bfd87c507f57de691b61ea92d70ae..490d2e7c96ce0e291653c18822a486e0d8a8b20e 100644 --- a/import_test.go +++ b/import_test.go @@ -24,8 +24,6 @@ func TestReadExample3(t *testing.T) { c.SetDefaultDirectories() c.Import() - //fmt.Println(c.Config().Host) - assert.Equal(t, c.Config().Host, "localhost") } diff --git a/issue-7_test.go b/issue-7_test.go new file mode 100644 index 0000000000000000000000000000000000000000..887e7143c52f34167870be2dc728f9406400c6cf --- /dev/null +++ b/issue-7_test.go @@ -0,0 +1,73 @@ +// Copyright 2022 schukai GmbH +// SPDX-License-Identifier: AGPL-3.0 + +package configuration + +import ( + "github.com/stretchr/testify/assert" + "io/ioutil" + "os" + "path" + "path/filepath" + "testing" +) + +type Issue7Routing struct { + P PathValue `json:"p" yaml:"p"` +} + +type Issue7Server struct { + Routing []Issue7Routing `json:"routing" yaml:"routing"` +} + +type Issue7Config struct { + Server Issue7Server `json:"server" yaml:"server"` +} + +func createIssue7TempFile(content string) (string, error) { + file, err := ioutil.TempFile("", "tempfile") + if err != nil { + return "", err + } + defer func() { + _ = file.Close() + }() + + _, err = file.WriteString(content) + if err != nil { + return "", err + } + + return file.Name(), nil +} + +func TestPathRewrite(t *testing.T) { + + c := New(Issue7Config{}) + + n, err := createIssue7TempFile(`{ + "server": { + "routing": [ + { + "p": "./test" + } + ] + } + }`) + + if err != nil { + t.Fatal(err) + } + + c.SetMnemonic("my-app") + c.AddFile(n) + c.Import() + + _ = os.Remove(n) + + //fmt.Println(c.Config().Host) + expected := path.Join(filepath.Dir(n), "test") + + assert.Equal(t, expected, c.Config().Server.Routing[0].P.String()) + +}