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
  • master
  • v1.0.0
  • v1.1.0
  • v1.1.1
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.11.0
  • v1.12.0
  • v1.13.0
  • v1.13.1
  • v1.13.2
  • v1.14.0
  • v1.15.0
  • v1.16.0
  • v1.16.1
  • v1.16.2
  • v1.16.3
  • v1.16.4
  • v1.16.5
  • v1.2.0
  • v1.2.1
  • v1.2.2
  • v1.2.3
  • v1.3.0
  • v1.3.1
  • v1.4.0
  • v1.5.0
  • v1.6.0
  • v1.7.0
  • v1.8.0
  • v1.8.1
  • v1.8.2
  • v1.8.3
  • v1.9.0
35 results

Target

Select target project
  • oss/libraries/go/application/xflags
1 result
Select Git revision
  • master
  • v1.0.0
  • v1.1.0
  • v1.1.1
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.11.0
  • v1.12.0
  • v1.13.0
  • v1.13.1
  • v1.13.2
  • v1.14.0
  • v1.15.0
  • v1.16.0
  • v1.16.1
  • v1.16.2
  • v1.16.3
  • v1.16.4
  • v1.16.5
  • v1.2.0
  • v1.2.1
  • v1.2.2
  • v1.2.3
  • v1.3.0
  • v1.3.1
  • v1.4.0
  • v1.5.0
  • v1.6.0
  • v1.7.0
  • v1.8.0
  • v1.8.1
  • v1.8.2
  • v1.8.3
  • v1.9.0
35 results
Show changes
Commits on Source (3)
<a name="v1.10.0"></a>
## [v1.10.0] - 2022-10-15
### Code Refactoring
- refactor functions moved to a separate repos
<a name="v1.9.0"></a>
## [v1.9.0] - 2022-10-15
### Add Features
......@@ -108,6 +114,7 @@
<a name="v1.0.0"></a>
## v1.0.0 - 2022-10-04
[v1.10.0]: https://gitlab.schukai.com/oss/libraries/go/application/xflags/compare/v1.9.0...v1.10.0
[v1.9.0]: https://gitlab.schukai.com/oss/libraries/go/application/xflags/compare/v1.8.3...v1.9.0
[v1.8.3]: https://gitlab.schukai.com/oss/libraries/go/application/xflags/compare/v1.8.2...v1.8.3
[v1.8.2]: https://gitlab.schukai.com/oss/libraries/go/application/xflags/compare/v1.8.1...v1.8.2
......
......@@ -8,5 +8,6 @@ require (
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.3.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
......@@ -5,6 +5,7 @@ package xflags
import (
"flag"
"gitlab.schukai.com/oss/libraries/go/utilities/pathfinder"
"reflect"
"strings"
)
......@@ -47,7 +48,7 @@ func (s *Settings[C]) assignValues(c cmd[C]) {
pa := append(c.valuePath, k)
p := strings.Join(pa, ".")
err := SetValueUsingPath(&s.definitions, p, value)
err := pathfinder.SetValue(&s.definitions, p, value)
if err != nil {
s.errors = append(s.errors, err)
}
......
......@@ -5,6 +5,7 @@ package xflags
import (
"github.com/stretchr/testify/assert"
"gitlab.schukai.com/oss/libraries/go/utilities/pathfinder"
"testing"
)
......@@ -39,8 +40,8 @@ func TestFlagCopyToShadow(t *testing.T) {
}
func (s *ConfigStruct6) Copy(m map[string]any) {
SetValueUsingPath(s, "ValGlobal1", (m["Global1"]))
SetValueUsingPath(s, "ValCommand1Flag2", (m["Command1.Command1Flag2"]))
pathfinder.SetValue(s, "ValGlobal1", (m["Global1"]))
pathfinder.SetValue(s, "ValCommand1Flag2", (m["Command1.Command1Flag2"]))
}
func TestCopyable(t *testing.T) {
......
// Copyright 2022 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0
package xflags
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// This function returns the value of a field in a struct, given a path to the field.
func GetValueFrom[D any](obj D, keyWithDots string) (any, error) {
keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(obj)
for _, key := range keySlice[0 : len(keySlice)-1] {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return nil, newUnsupportedTypePathError(keyWithDots, v.Type())
}
v = v.FieldByName(key)
}
if v.Kind() == reflect.Invalid {
return nil, newInvalidPathError(keyWithDots)
}
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
// non-supporter type at the top of the path
if v.Kind() != reflect.Struct {
return nil, newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type())
}
v = v.FieldByName(keySlice[len(keySlice)-1])
if !v.IsValid() {
return nil, newInvalidPathError(keyWithDots)
}
return v.Interface(), nil
}
// This function sets the value of a field in a struct, given a path to the field.
func SetValueUsingPath[D any](obj D, keyWithDots string, newValue any) error {
keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(obj)
for _, key := range keySlice[0 : len(keySlice)-1] {
for v.Kind() != reflect.Ptr {
v = v.Addr()
}
if v.Kind() != reflect.Ptr {
return newUnsupportedTypePathError(keyWithDots, v.Type())
}
elem := v.Elem()
if elem.Kind() != reflect.Struct {
return newUnsupportedTypePathError(keyWithDots, v.Type())
}
v = elem.FieldByName(key)
}
if v.Kind() == reflect.Invalid {
return newInvalidPathError(keyWithDots)
}
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
// non-supporter type at the top of the path
if v.Kind() != reflect.Struct {
return newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type())
}
v = v.FieldByName(keySlice[len(keySlice)-1])
if !v.IsValid() {
return newInvalidPathError(keyWithDots)
}
if !v.CanSet() {
return newCannotSetError(keyWithDots)
}
switch v.Kind() {
case reflect.Ptr:
if newValue == nil {
v.Set(reflect.Zero(v.Type()))
} else {
v.Set(reflect.ValueOf(&newValue))
}
return nil
}
newValueType := reflect.TypeOf(newValue)
if newValueType == nil {
return newUnsupportedTypePathError(keyWithDots, v.Type())
}
newValueKind := reflect.TypeOf(newValue).Kind()
switch v.Kind() {
case reflect.String:
if newValueKind == reflect.String {
v.SetString(newValue.(string))
} else {
v.SetString(fmt.Sprintf("%v", newValue))
}
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
if newValueKind == reflect.Int {
v.SetInt(int64(newValue.(int)))
} else {
s, err := strconv.ParseInt(newValue.(string), 10, 64)
if err != nil {
return err
}
v.SetInt(s)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if newValueKind == reflect.Int {
v.SetUint(uint64(newValue.(int)))
} else {
s, err := strconv.ParseInt(newValue.(string), 10, 64)
if err != nil {
return err
}
v.SetUint(uint64(s))
}
case reflect.Bool:
if newValueKind == reflect.Bool {
v.SetBool(newValue.(bool))
} else {
b, err := strconv.ParseBool(newValue.(string))
if err != nil {
return err
}
v.SetBool(b)
}
case reflect.Float64, reflect.Float32:
if newValueKind == reflect.Float64 {
v.SetFloat(newValue.(float64))
} else {
s, err := strconv.ParseFloat(newValue.(string), 64)
if err != nil {
return err
}
v.SetFloat(s)
}
default:
return newInvalidTypeForPathError(keyWithDots, v.Type().String(), newValueKind.String())
}
return nil
}
// Copyright 2022 schukai GmbH
// SPDX-License-Identifier: AGPL-3.0
package xflags
import "testing"
type PathfindTestStruct1 struct {
A bool
Sub1 struct {
B bool
Bi int
Bs string
Bf float64
Sub2 struct {
C bool
Ci int
Cs string
Cf float64
Sub3 struct {
D bool
Di int
Ds string
Df float64
}
}
}
}
func TestPathFindError(t *testing.T) {
s := PathfindTestStruct1{}
_, err := GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.XX")
if err == nil {
t.Error("err == nil")
}
}
func TestPathFindSetValueString(t *testing.T) {
testData := map[string]string{
"Sub1.B": "true",
"Sub1.Bi": "2",
"Sub1.Bs": "3",
"Sub1.Bf": "4.0",
"Sub1.Sub2.C": "true",
"Sub1.Sub2.Ci": "2",
"Sub1.Sub2.Cs": "3",
"Sub1.Sub2.Cf": "4.0",
"Sub1.Sub2.Sub3.D": "true",
"Sub1.Sub2.Sub3.Di": "2",
"Sub1.Sub2.Sub3.Ds": "3",
"Sub1.Sub2.Sub3.Df": "4.0",
}
for k, v := range testData {
s := &PathfindTestStruct1{}
err := SetValueUsingPath[*PathfindTestStruct1](s, k, v)
if err != nil {
t.Error(err)
}
}
}
func TestPathFindGetValueFrom(t *testing.T) {
s := PathfindTestStruct1{}
s.Sub1.B = true
s.Sub1.Bi = 2
s.Sub1.Bs = "3"
s.Sub1.Bf = 4.0
v, err := GetValueFrom[PathfindTestStruct1](s, "Sub1.B")
if err != nil {
t.Error(err)
}
if v != true {
t.Error("v != true")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Bi")
if err != nil {
t.Error(err)
}
if v != 2 {
t.Error("v != 2")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Bs")
if err != nil {
t.Error(err)
}
if v != "3" {
t.Error("v != 3")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Bf")
if err != nil {
t.Error(err)
}
if v != 4.0 {
t.Error("v != 4.0")
}
s.Sub1.Sub2.C = true
s.Sub1.Sub2.Ci = 2
s.Sub1.Sub2.Cs = "3"
s.Sub1.Sub2.Cf = 4.0
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.C")
if err != nil {
t.Error(err)
}
if v != true {
t.Error("v != true")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Ci")
if err != nil {
t.Error(err)
}
if v != 2 {
t.Error("v != 2")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Cs")
if err != nil {
t.Error(err)
}
if v != "3" {
t.Error("v != 3")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Cf")
if err != nil {
t.Error(err)
}
if v != 4.0 {
t.Error("v != 4.0")
}
s.Sub1.Sub2.Sub3.D = true
s.Sub1.Sub2.Sub3.Di = 2
s.Sub1.Sub2.Sub3.Ds = "3"
s.Sub1.Sub2.Sub3.Df = 4.0
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.D")
if err != nil {
t.Error(err)
}
if v != true {
t.Error("v != true")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Di")
if err != nil {
t.Error(err)
}
if v != 2 {
t.Error("v != 2")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Ds")
if err != nil {
t.Error(err)
}
if v != "3" {
t.Error("v != 3")
}
v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Df")
if err != nil {
t.Error(err)
}
if v != 4.0 {
t.Error("v != 4.0")
}
}
func TestPathFindSetValueFrom(t *testing.T) {
s := &PathfindTestStruct1{}
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.B", "true")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bi", "2")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bs", "3")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bf", "4.0")
if s.Sub1.B != true {
t.Error("s.Sub1.B != true")
}
if s.Sub1.Bi != 2 {
t.Error("s.Sub1.Bi != 2")
}
if s.Sub1.Bs != "3" {
t.Error("s.Sub1.Bs != 3")
}
if s.Sub1.Bf != 4.0 {
t.Error("s.Sub1.Bf != 4.0")
}
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.C", "true")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Ci", "2")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Cs", "3")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Cf", "4.0")
if s.Sub1.Sub2.C != true {
t.Error("s.Sub1.Sub2.C != true")
}
if s.Sub1.Sub2.Ci != 2 {
t.Error("s.Sub1.Sub2.Ci != 2")
}
if s.Sub1.Sub2.Cs != "3" {
t.Error("s.Sub1.Sub2.Cs != 3")
}
if s.Sub1.Sub2.Cf != 4.0 {
t.Error("s.Sub1.Sub2.Cf != 4.0")
}
if s.Sub1.Sub2.Sub3.D != false {
t.Error("s.Sub1.Sub2.Sub3.D != false")
}
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.D", "true")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Di", "2")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Ds", "3")
SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Df", "4.0")
if s.Sub1.Sub2.Sub3.D != true {
t.Error("s.Sub1.Sub2.Sub3.D != true")
}
if s.Sub1.Sub2.Sub3.Di != 2 {
t.Error("s.Sub1.Sub2.Sub3.Di != 2")
}
if s.Sub1.Sub2.Sub3.Ds != "3" {
t.Error("s.Sub1.Sub2.Sub3.Ds != 3")
}
if s.Sub1.Sub2.Sub3.Df != 4.0 {
t.Error("s.Sub1.Sub2.Sub3.Df != 4.0")
}
}
{"version":"1.9.0"}
{"version":"1.10.0"}