Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • oss/libraries/go/application/configuration
1 result
Select Git revision
Show changes
Commits on Source (4)
<a name="v1.14.0"></a>
## [v1.14.0] - 2022-10-24
### Add Features
- feat add path value [#1](https://gitlab.schukai.com/oss/libraries/go/application/configuration/issues/1)
### Changes
- chore add licenses
<a name="v1.13.0"></a>
## [v1.13.0] - 2022-10-24
### Bug Fixes
......@@ -152,6 +161,7 @@
<a name="v1.0.0"></a>
## v1.0.0 - 2022-09-18
[v1.14.0]: https://gitlab.schukai.com/oss/libraries/go/application/configuration/compare/v1.13.0...v1.14.0
[v1.13.0]: https://gitlab.schukai.com/oss/libraries/go/application/configuration/compare/v1.12.0...v1.13.0
[v1.12.0]: https://gitlab.schukai.com/oss/libraries/go/application/configuration/compare/v1.11.4...v1.12.0
[v1.11.4]: https://gitlab.schukai.com/oss/libraries/go/application/configuration/compare/v1.11.3...v1.11.4
......
......@@ -360,6 +360,7 @@ C:
})
}
func addSample2() {
e := &mockFile{}
......
......@@ -6,6 +6,7 @@ package configuration
import (
"bytes"
"encoding/json"
"reflect"
"github.com/imdario/mergo"
"github.com/magiconair/properties"
......@@ -46,7 +47,7 @@ func importProperties[C any](config *C, reader io.Reader) error {
}
func (s *Settings[C]) importStream(r reader) {
func (s *Settings[C]) importStream(r reader, f ...func(n *C)) {
var c C
var err error
......@@ -79,6 +80,12 @@ func (s *Settings[C]) importStream(r reader) {
s.errors = append(s.errors, err)
}
if f != nil {
for _, fn := range f {
fn(&c)
}
}
if err := mergo.Merge(&s.config, c); err != nil {
s.errors = append(s.errors, err)
}
......@@ -90,6 +97,42 @@ func (s *Settings[C]) importStreams() {
}
}
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()))
}
}
}
}
}
func (s *Settings[C]) importFiles() {
s.fileWatch.Lock()
......@@ -116,7 +159,9 @@ func (s *Settings[C]) importFiles() {
}
r := (io.Reader)(f)
s.importStream(reader{s.files.format, r})
s.importStream(reader{s.files.format, r}, func(c *C) {
replacePath(d, c)
})
f.Close()
}
......@@ -129,7 +174,10 @@ func (s *Settings[C]) importFiles() {
continue
}
s.importStream(reader{f.format, r})
s.importStream(reader{f.format, r}, func(c *C) {
d := path.Dir(f.path)
replacePath(d, c)
})
r.Close()
}
......
// Copyright 2022 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0
package configuration
import (
"bytes"
"github.com/stretchr/testify/assert"
"path"
"testing"
"time"
)
type ConfigIssue1SubStruct struct {
DA PathValue `yaml:"DA"`
}
type ConfigIssue1Struct struct {
A string `yaml:"A"`
B PathValue `yaml:"B"`
C PathValue `yaml:"C"`
D ConfigIssue1SubStruct `yaml:"D"`
}
func addSampleIssue1() {
e := &mockFile{}
content := []byte(
`---
A: "Hello!"
B: "/tmp"
C: "xyz.html"
D:
DA: "tmp.xyz"
...
`)
e.buffer = bytes.NewBuffer(content)
e.FileInfo = mockFileInfo{
name: "test",
size: int64(len(content)),
mode: 0,
mod: time.Now(),
dir: false,
sys: nil,
}
fileSamples = append(fileSamples, fileSample{
file: e,
})
}
func TestIssue1(t *testing.T) {
fileSamples = []fileSample{}
defer func() { fileSamples = nil }()
addSampleIssue1()
defaults := ConfigIssue1Struct{}
mockFs := mockFS{}
c := New(defaults)
c.SetMnemonic("test")
c.SetFileFormat(Yaml)
c.SetFilesystem(mockFs)
// setDefaultdirectories can be returned errors
c.SetDefaultDirectories().ResetErrors()
c.Import()
if c.HasErrors() {
t.Error("Expected not error", c.Errors())
}
assert.Equal(t, c.Config().A, "Hello!")
assert.Equal(t, c.Config().B, PathValue("/tmp"))
if !path.IsAbs(string(c.Config().C)) {
t.Error("Expected absolute path got ", c.Config().C)
}
if !path.IsAbs(string(c.Config().D.DA)) {
t.Error("Expected absolute path got ", c.Config().D.DA)
}
}
// Copyright 2022 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0
package configuration
import "path"
type pathInterface interface {
String() string
Dir() string
Ext() string
Base() string
}
type PathValue string
func (p PathValue) Dir() string {
return path.Dir(string(p))
}
func (p PathValue) Ext() string {
return path.Ext(string(p))
}
func (p PathValue) String() string {
return string(p)
}
func (p PathValue) Base() string {
return path.Base(string(p))
}
// Copyright 2022 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0
package configuration
import (
"path"
"testing"
)
func TestPathValue(t *testing.T) {
data := []struct {
path string
expected string
base string
}{
{"/a/b/c", "/a/b", "c"},
{"/a/b/c/", "/a/b/c", "c"}, // trailing slash are ignored
{"/a/b/c/d.txt", "/a/b/c", "d.txt"},
{"/a/b/c/d/", "/a/b/c/d", "d"},
{"/a/b/c/d/e", "/a/b/c/d", "e"},
{"/a/b/../c/d/e", "/a/c/d", "e"},
}
for _, d := range data {
t.Run("Dir-"+d.path, func(t *testing.T) {
p := PathValue(d.path)
if p.Dir() != d.expected {
t.Errorf("Expected %s, got %s", d.expected, p.Dir())
}
})
}
for _, d := range data {
t.Run("Base-"+d.path, func(t *testing.T) {
p := PathValue(d.path)
if p.Base() != d.base {
t.Errorf("Expected %s, got %s", d.base, p.Base())
}
})
}
for _, d := range data {
t.Run("String-"+d.path, func(t *testing.T) {
p := PathValue(d.path)
if p.String() != string(p) {
t.Errorf("Expected %s, got %s", string(p), p.String())
}
})
}
for _, d := range data {
t.Run("Ext-"+d.path, func(t *testing.T) {
p := PathValue(d.path)
if p.Ext() != path.Ext(d.path) {
t.Errorf("Expected %s, got %s", path.Ext(d.path), p.Ext())
}
})
}
}
{"version":"1.13.0"}
{"version":"1.14.0"}