Rename libs/config -> libs/dyn (#1086)

## Changes

The name "dynamic value", or "dyn" for short, is more descriptive than
the opaque "config". Also, it conveniently does not alias with other
packages in the repository, or (popular ones) elsewhere.

(discussed with @andrewnester)

## Tests

n/a
This commit is contained in:
Pieter Noordhuis 2023-12-22 14:20:45 +01:00 committed by GitHub
parent a1297d71fd
commit 938eb1600c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 600 additions and 600 deletions

View File

@ -1,76 +0,0 @@
package config_test
import (
"testing"
"github.com/databricks/cli/libs/config"
"github.com/stretchr/testify/assert"
)
func TestPathAppend(t *testing.T) {
p := config.NewPath(config.Key("foo"))
// Single arg.
p1 := p.Append(config.Key("bar"))
assert.True(t, p1.Equal(config.NewPath(config.Key("foo"), config.Key("bar"))))
// Multiple args.
p2 := p.Append(config.Key("bar"), config.Index(1))
assert.True(t, p2.Equal(config.NewPath(config.Key("foo"), config.Key("bar"), config.Index(1))))
}
func TestPathJoin(t *testing.T) {
p := config.NewPath(config.Key("foo"))
// Single arg.
p1 := p.Join(config.NewPath(config.Key("bar")))
assert.True(t, p1.Equal(config.NewPath(config.Key("foo"), config.Key("bar"))))
// Multiple args.
p2 := p.Join(config.NewPath(config.Key("bar")), config.NewPath(config.Index(1)))
assert.True(t, p2.Equal(config.NewPath(config.Key("foo"), config.Key("bar"), config.Index(1))))
}
func TestPathEqualEmpty(t *testing.T) {
assert.True(t, config.EmptyPath.Equal(config.EmptyPath))
}
func TestPathEqual(t *testing.T) {
p1 := config.NewPath(config.Key("foo"), config.Index(1))
p2 := config.NewPath(config.Key("bar"), config.Index(2))
assert.False(t, p1.Equal(p2), "expected %q to not equal %q", p1, p2)
p3 := config.NewPath(config.Key("foo"), config.Index(1))
assert.True(t, p1.Equal(p3), "expected %q to equal %q", p1, p3)
p4 := config.NewPath(config.Key("foo"), config.Index(1), config.Key("bar"), config.Index(2))
assert.False(t, p1.Equal(p4), "expected %q to not equal %q", p1, p4)
}
func TestPathHasPrefixEmpty(t *testing.T) {
empty := config.EmptyPath
nonEmpty := config.NewPath(config.Key("foo"))
assert.True(t, empty.HasPrefix(empty))
assert.True(t, nonEmpty.HasPrefix(empty))
assert.False(t, empty.HasPrefix(nonEmpty))
}
func TestPathHasPrefix(t *testing.T) {
p1 := config.NewPath(config.Key("foo"), config.Index(1))
p2 := config.NewPath(config.Key("bar"), config.Index(2))
assert.False(t, p1.HasPrefix(p2), "expected %q to not have prefix %q", p1, p2)
p3 := config.NewPath(config.Key("foo"))
assert.True(t, p1.HasPrefix(p3), "expected %q to have prefix %q", p1, p3)
}
func TestPathString(t *testing.T) {
p1 := config.NewPath(config.Key("foo"), config.Index(1))
assert.Equal(t, "foo[1]", p1.String())
p2 := config.NewPath(config.Key("bar"), config.Index(2), config.Key("baz"))
assert.Equal(t, "bar[2].baz", p2.String())
p3 := config.NewPath(config.Key("foo"), config.Index(1), config.Key("bar"), config.Index(2), config.Key("baz"))
assert.Equal(t, "foo[1].bar[2].baz", p3.String())
}

View File

@ -3,7 +3,7 @@ package diag
import ( import (
"fmt" "fmt"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
) )
type Diagnostic struct { type Diagnostic struct {
@ -19,7 +19,7 @@ type Diagnostic struct {
// Location is a source code location associated with the diagnostic message. // Location is a source code location associated with the diagnostic message.
// It may be zero if there is no associated location. // It may be zero if there is no associated location.
Location config.Location Location dyn.Location
} }
// Errorf creates a new error diagnostic. // Errorf creates a new error diagnostic.

View File

@ -3,13 +3,13 @@ package convert
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func assertFromTypedToTypedEqual[T any](t *testing.T, src T) { func assertFromTypedToTypedEqual[T any](t *testing.T, src T) {
nv, err := FromTyped(src, config.NilValue) nv, err := FromTyped(src, dyn.NilValue)
require.NoError(t, err) require.NoError(t, err)
var dst T var dst T

View File

@ -3,11 +3,11 @@ package convert
import ( import (
"fmt" "fmt"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
) )
type TypeError struct { type TypeError struct {
value config.Value value dyn.Value
msg string msg string
} }

View File

@ -4,18 +4,18 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
) )
// FromTyped converts changes made in the typed structure w.r.t. the configuration value // FromTyped converts changes made in the typed structure w.r.t. the configuration value
// back to the configuration value, retaining existing location information where possible. // back to the configuration value, retaining existing location information where possible.
func FromTyped(src any, ref config.Value) (config.Value, error) { func FromTyped(src any, ref dyn.Value) (dyn.Value, error) {
srcv := reflect.ValueOf(src) srcv := reflect.ValueOf(src)
// Dereference pointer if necessary // Dereference pointer if necessary
for srcv.Kind() == reflect.Pointer { for srcv.Kind() == reflect.Pointer {
if srcv.IsNil() { if srcv.IsNil() {
return config.NilValue, nil return dyn.NilValue, nil
} }
srcv = srcv.Elem() srcv = srcv.Elem()
} }
@ -37,53 +37,53 @@ func FromTyped(src any, ref config.Value) (config.Value, error) {
return fromTypedFloat(srcv, ref) return fromTypedFloat(srcv, ref)
} }
return config.NilValue, fmt.Errorf("unsupported type: %s", srcv.Kind()) return dyn.NilValue, fmt.Errorf("unsupported type: %s", srcv.Kind())
} }
func fromTypedStruct(src reflect.Value, ref config.Value) (config.Value, error) { func fromTypedStruct(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
// Check that the reference value is compatible or nil. // Check that the reference value is compatible or nil.
switch ref.Kind() { switch ref.Kind() {
case config.KindMap, config.KindNil: case dyn.KindMap, dyn.KindNil:
default: default:
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind()) return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
} }
out := make(map[string]config.Value) out := make(map[string]dyn.Value)
info := getStructInfo(src.Type()) info := getStructInfo(src.Type())
for k, v := range info.FieldValues(src) { for k, v := range info.FieldValues(src) {
// Convert the field taking into account the reference value (may be equal to config.NilValue). // Convert the field taking into account the reference value (may be equal to config.NilValue).
nv, err := FromTyped(v.Interface(), ref.Get(k)) nv, err := FromTyped(v.Interface(), ref.Get(k))
if err != nil { if err != nil {
return config.Value{}, err return dyn.Value{}, err
} }
if nv != config.NilValue { if nv != dyn.NilValue {
out[k] = nv out[k] = nv
} }
} }
// If the struct was equal to its zero value, emit a nil. // If the struct was equal to its zero value, emit a nil.
if len(out) == 0 { if len(out) == 0 {
return config.NilValue, nil return dyn.NilValue, nil
} }
return config.NewValue(out, ref.Location()), nil return dyn.NewValue(out, ref.Location()), nil
} }
func fromTypedMap(src reflect.Value, ref config.Value) (config.Value, error) { func fromTypedMap(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
// Check that the reference value is compatible or nil. // Check that the reference value is compatible or nil.
switch ref.Kind() { switch ref.Kind() {
case config.KindMap, config.KindNil: case dyn.KindMap, dyn.KindNil:
default: default:
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind()) return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
} }
// Return nil if the map is nil. // Return nil if the map is nil.
if src.IsNil() { if src.IsNil() {
return config.NilValue, nil return dyn.NilValue, nil
} }
out := make(map[string]config.Value) out := make(map[string]dyn.Value)
iter := src.MapRange() iter := src.MapRange()
for iter.Next() { for iter.Next() {
k := iter.Key().String() k := iter.Key().String()
@ -92,7 +92,7 @@ func fromTypedMap(src reflect.Value, ref config.Value) (config.Value, error) {
// Convert entry taking into account the reference value (may be equal to config.NilValue). // Convert entry taking into account the reference value (may be equal to config.NilValue).
nv, err := FromTyped(v.Interface(), ref.Get(k)) nv, err := FromTyped(v.Interface(), ref.Get(k))
if err != nil { if err != nil {
return config.Value{}, err return dyn.Value{}, err
} }
// Every entry is represented, even if it is a nil. // Every entry is represented, even if it is a nil.
@ -100,115 +100,115 @@ func fromTypedMap(src reflect.Value, ref config.Value) (config.Value, error) {
out[k] = nv out[k] = nv
} }
return config.NewValue(out, ref.Location()), nil return dyn.NewValue(out, ref.Location()), nil
} }
func fromTypedSlice(src reflect.Value, ref config.Value) (config.Value, error) { func fromTypedSlice(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
// Check that the reference value is compatible or nil. // Check that the reference value is compatible or nil.
switch ref.Kind() { switch ref.Kind() {
case config.KindSequence, config.KindNil: case dyn.KindSequence, dyn.KindNil:
default: default:
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind()) return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
} }
// Return nil if the slice is nil. // Return nil if the slice is nil.
if src.IsNil() { if src.IsNil() {
return config.NilValue, nil return dyn.NilValue, nil
} }
out := make([]config.Value, src.Len()) out := make([]dyn.Value, src.Len())
for i := 0; i < src.Len(); i++ { for i := 0; i < src.Len(); i++ {
v := src.Index(i) v := src.Index(i)
// Convert entry taking into account the reference value (may be equal to config.NilValue). // Convert entry taking into account the reference value (may be equal to config.NilValue).
nv, err := FromTyped(v.Interface(), ref.Index(i)) nv, err := FromTyped(v.Interface(), ref.Index(i))
if err != nil { if err != nil {
return config.Value{}, err return dyn.Value{}, err
} }
out[i] = nv out[i] = nv
} }
return config.NewValue(out, ref.Location()), nil return dyn.NewValue(out, ref.Location()), nil
} }
func fromTypedString(src reflect.Value, ref config.Value) (config.Value, error) { func fromTypedString(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() { switch ref.Kind() {
case config.KindString: case dyn.KindString:
value := src.String() value := src.String()
if value == ref.MustString() { if value == ref.MustString() {
return ref, nil return ref, nil
} }
return config.V(value), nil return dyn.V(value), nil
case config.KindNil: case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value. // This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields. // Otherwise, we would always include all zero valued fields.
if src.IsZero() { if src.IsZero() {
return config.NilValue, nil return dyn.NilValue, nil
} }
return config.V(src.String()), nil return dyn.V(src.String()), nil
} }
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind()) return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
} }
func fromTypedBool(src reflect.Value, ref config.Value) (config.Value, error) { func fromTypedBool(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() { switch ref.Kind() {
case config.KindBool: case dyn.KindBool:
value := src.Bool() value := src.Bool()
if value == ref.MustBool() { if value == ref.MustBool() {
return ref, nil return ref, nil
} }
return config.V(value), nil return dyn.V(value), nil
case config.KindNil: case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value. // This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields. // Otherwise, we would always include all zero valued fields.
if src.IsZero() { if src.IsZero() {
return config.NilValue, nil return dyn.NilValue, nil
} }
return config.V(src.Bool()), nil return dyn.V(src.Bool()), nil
} }
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind()) return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
} }
func fromTypedInt(src reflect.Value, ref config.Value) (config.Value, error) { func fromTypedInt(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() { switch ref.Kind() {
case config.KindInt: case dyn.KindInt:
value := src.Int() value := src.Int()
if value == ref.MustInt() { if value == ref.MustInt() {
return ref, nil return ref, nil
} }
return config.V(value), nil return dyn.V(value), nil
case config.KindNil: case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value. // This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields. // Otherwise, we would always include all zero valued fields.
if src.IsZero() { if src.IsZero() {
return config.NilValue, nil return dyn.NilValue, nil
} }
return config.V(src.Int()), nil return dyn.V(src.Int()), nil
} }
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind()) return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
} }
func fromTypedFloat(src reflect.Value, ref config.Value) (config.Value, error) { func fromTypedFloat(src reflect.Value, ref dyn.Value) (dyn.Value, error) {
switch ref.Kind() { switch ref.Kind() {
case config.KindFloat: case dyn.KindFloat:
value := src.Float() value := src.Float()
if value == ref.MustFloat() { if value == ref.MustFloat() {
return ref, nil return ref, nil
} }
return config.V(value), nil return dyn.V(value), nil
case config.KindNil: case dyn.KindNil:
// This field is not set in the reference, so we only include it if it has a non-zero value. // This field is not set in the reference, so we only include it if it has a non-zero value.
// Otherwise, we would always include all zero valued fields. // Otherwise, we would always include all zero valued fields.
if src.IsZero() { if src.IsZero() {
return config.NilValue, nil return dyn.NilValue, nil
} }
return config.V(src.Float()), nil return dyn.V(src.Float()), nil
} }
return config.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind()) return dyn.Value{}, fmt.Errorf("unhandled type: %s", ref.Kind())
} }

View File

@ -3,7 +3,7 @@ package convert
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -15,11 +15,11 @@ func TestFromTypedStructZeroFields(t *testing.T) {
} }
src := Tmp{} src := Tmp{}
ref := config.NilValue ref := dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NilValue, nv) assert.Equal(t, dyn.NilValue, nv)
} }
func TestFromTypedStructSetFields(t *testing.T) { func TestFromTypedStructSetFields(t *testing.T) {
@ -33,12 +33,12 @@ func TestFromTypedStructSetFields(t *testing.T) {
Bar: "bar", Bar: "bar",
} }
ref := config.NilValue ref := dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{ assert.Equal(t, dyn.V(map[string]dyn.Value{
"foo": config.V("foo"), "foo": dyn.V("foo"),
"bar": config.V("bar"), "bar": dyn.V("bar"),
}), nv) }), nv)
} }
@ -53,45 +53,45 @@ func TestFromTypedStructSetFieldsRetainLocationIfUnchanged(t *testing.T) {
Bar: "qux", Bar: "qux",
} }
ref := config.V(map[string]config.Value{ ref := dyn.V(map[string]dyn.Value{
"foo": config.NewValue("bar", config.Location{File: "foo"}), "foo": dyn.NewValue("bar", dyn.Location{File: "foo"}),
"bar": config.NewValue("baz", config.Location{File: "bar"}), "bar": dyn.NewValue("baz", dyn.Location{File: "bar"}),
}) })
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
// Assert foo has retained its location. // Assert foo has retained its location.
assert.Equal(t, config.NewValue("bar", config.Location{File: "foo"}), nv.Get("foo")) assert.Equal(t, dyn.NewValue("bar", dyn.Location{File: "foo"}), nv.Get("foo"))
// Assert bar lost its location (because it was overwritten). // Assert bar lost its location (because it was overwritten).
assert.Equal(t, config.NewValue("qux", config.Location{}), nv.Get("bar")) assert.Equal(t, dyn.NewValue("qux", dyn.Location{}), nv.Get("bar"))
} }
func TestFromTypedMapNil(t *testing.T) { func TestFromTypedMapNil(t *testing.T) {
var src map[string]string = nil var src map[string]string = nil
ref := config.V(map[string]config.Value{ ref := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NilValue, nv) assert.Equal(t, dyn.NilValue, nv)
} }
func TestFromTypedMapEmpty(t *testing.T) { func TestFromTypedMapEmpty(t *testing.T) {
var src = map[string]string{} var src = map[string]string{}
ref := config.V(map[string]config.Value{ ref := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{}), nv) assert.Equal(t, dyn.V(map[string]dyn.Value{}), nv)
} }
func TestFromTypedMapNonEmpty(t *testing.T) { func TestFromTypedMapNonEmpty(t *testing.T) {
@ -100,12 +100,12 @@ func TestFromTypedMapNonEmpty(t *testing.T) {
"bar": "bar", "bar": "bar",
} }
ref := config.NilValue ref := dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{ assert.Equal(t, dyn.V(map[string]dyn.Value{
"foo": config.V("foo"), "foo": dyn.V("foo"),
"bar": config.V("bar"), "bar": dyn.V("bar"),
}), nv) }), nv)
} }
@ -115,19 +115,19 @@ func TestFromTypedMapNonEmptyRetainLocationIfUnchanged(t *testing.T) {
"bar": "qux", "bar": "qux",
} }
ref := config.V(map[string]config.Value{ ref := dyn.V(map[string]dyn.Value{
"foo": config.NewValue("bar", config.Location{File: "foo"}), "foo": dyn.NewValue("bar", dyn.Location{File: "foo"}),
"bar": config.NewValue("baz", config.Location{File: "bar"}), "bar": dyn.NewValue("baz", dyn.Location{File: "bar"}),
}) })
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
// Assert foo has retained its location. // Assert foo has retained its location.
assert.Equal(t, config.NewValue("bar", config.Location{File: "foo"}), nv.Get("foo")) assert.Equal(t, dyn.NewValue("bar", dyn.Location{File: "foo"}), nv.Get("foo"))
// Assert bar lost its location (because it was overwritten). // Assert bar lost its location (because it was overwritten).
assert.Equal(t, config.NewValue("qux", config.Location{}), nv.Get("bar")) assert.Equal(t, dyn.NewValue("qux", dyn.Location{}), nv.Get("bar"))
} }
func TestFromTypedMapFieldWithZeroValue(t *testing.T) { func TestFromTypedMapFieldWithZeroValue(t *testing.T) {
@ -135,38 +135,38 @@ func TestFromTypedMapFieldWithZeroValue(t *testing.T) {
"foo": "", "foo": "",
} }
ref := config.NilValue ref := dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(map[string]config.Value{ assert.Equal(t, dyn.V(map[string]dyn.Value{
"foo": config.NilValue, "foo": dyn.NilValue,
}), nv) }), nv)
} }
func TestFromTypedSliceNil(t *testing.T) { func TestFromTypedSliceNil(t *testing.T) {
var src []string = nil var src []string = nil
ref := config.V([]config.Value{ ref := dyn.V([]dyn.Value{
config.V("bar"), dyn.V("bar"),
config.V("baz"), dyn.V("baz"),
}) })
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NilValue, nv) assert.Equal(t, dyn.NilValue, nv)
} }
func TestFromTypedSliceEmpty(t *testing.T) { func TestFromTypedSliceEmpty(t *testing.T) {
var src = []string{} var src = []string{}
ref := config.V([]config.Value{ ref := dyn.V([]dyn.Value{
config.V("bar"), dyn.V("bar"),
config.V("baz"), dyn.V("baz"),
}) })
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V([]config.Value{}), nv) assert.Equal(t, dyn.V([]dyn.Value{}), nv)
} }
func TestFromTypedSliceNonEmpty(t *testing.T) { func TestFromTypedSliceNonEmpty(t *testing.T) {
@ -175,12 +175,12 @@ func TestFromTypedSliceNonEmpty(t *testing.T) {
"bar", "bar",
} }
ref := config.NilValue ref := dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V([]config.Value{ assert.Equal(t, dyn.V([]dyn.Value{
config.V("foo"), dyn.V("foo"),
config.V("bar"), dyn.V("bar"),
}), nv) }), nv)
} }
@ -190,205 +190,205 @@ func TestFromTypedSliceNonEmptyRetainLocationIfUnchanged(t *testing.T) {
"bar", "bar",
} }
ref := config.V([]config.Value{ ref := dyn.V([]dyn.Value{
config.NewValue("foo", config.Location{File: "foo"}), dyn.NewValue("foo", dyn.Location{File: "foo"}),
config.NewValue("baz", config.Location{File: "baz"}), dyn.NewValue("baz", dyn.Location{File: "baz"}),
}) })
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
// Assert foo has retained its location. // Assert foo has retained its location.
assert.Equal(t, config.NewValue("foo", config.Location{File: "foo"}), nv.Index(0)) assert.Equal(t, dyn.NewValue("foo", dyn.Location{File: "foo"}), nv.Index(0))
// Assert bar lost its location (because it was overwritten). // Assert bar lost its location (because it was overwritten).
assert.Equal(t, config.NewValue("bar", config.Location{}), nv.Index(1)) assert.Equal(t, dyn.NewValue("bar", dyn.Location{}), nv.Index(1))
} }
func TestFromTypedStringEmpty(t *testing.T) { func TestFromTypedStringEmpty(t *testing.T) {
var src string var src string
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NilValue, nv) assert.Equal(t, dyn.NilValue, nv)
} }
func TestFromTypedStringEmptyOverwrite(t *testing.T) { func TestFromTypedStringEmptyOverwrite(t *testing.T) {
var src string var src string
var ref = config.V("old") var ref = dyn.V("old")
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(""), nv) assert.Equal(t, dyn.V(""), nv)
} }
func TestFromTypedStringNonEmpty(t *testing.T) { func TestFromTypedStringNonEmpty(t *testing.T) {
var src string = "new" var src string = "new"
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V("new"), nv) assert.Equal(t, dyn.V("new"), nv)
} }
func TestFromTypedStringNonEmptyOverwrite(t *testing.T) { func TestFromTypedStringNonEmptyOverwrite(t *testing.T) {
var src string = "new" var src string = "new"
var ref = config.V("old") var ref = dyn.V("old")
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V("new"), nv) assert.Equal(t, dyn.V("new"), nv)
} }
func TestFromTypedStringRetainsLocationsIfUnchanged(t *testing.T) { func TestFromTypedStringRetainsLocationsIfUnchanged(t *testing.T) {
var src string = "foo" var src string = "foo"
var ref = config.NewValue("foo", config.Location{File: "foo"}) var ref = dyn.NewValue("foo", dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NewValue("foo", config.Location{File: "foo"}), nv) assert.Equal(t, dyn.NewValue("foo", dyn.Location{File: "foo"}), nv)
} }
func TestFromTypedStringTypeError(t *testing.T) { func TestFromTypedStringTypeError(t *testing.T) {
var src string = "foo" var src string = "foo"
var ref = config.V(1234) var ref = dyn.V(1234)
_, err := FromTyped(src, ref) _, err := FromTyped(src, ref)
require.Error(t, err) require.Error(t, err)
} }
func TestFromTypedBoolEmpty(t *testing.T) { func TestFromTypedBoolEmpty(t *testing.T) {
var src bool var src bool
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NilValue, nv) assert.Equal(t, dyn.NilValue, nv)
} }
func TestFromTypedBoolEmptyOverwrite(t *testing.T) { func TestFromTypedBoolEmptyOverwrite(t *testing.T) {
var src bool var src bool
var ref = config.V(true) var ref = dyn.V(true)
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(false), nv) assert.Equal(t, dyn.V(false), nv)
} }
func TestFromTypedBoolNonEmpty(t *testing.T) { func TestFromTypedBoolNonEmpty(t *testing.T) {
var src bool = true var src bool = true
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(true), nv) assert.Equal(t, dyn.V(true), nv)
} }
func TestFromTypedBoolNonEmptyOverwrite(t *testing.T) { func TestFromTypedBoolNonEmptyOverwrite(t *testing.T) {
var src bool = true var src bool = true
var ref = config.V(false) var ref = dyn.V(false)
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(true), nv) assert.Equal(t, dyn.V(true), nv)
} }
func TestFromTypedBoolRetainsLocationsIfUnchanged(t *testing.T) { func TestFromTypedBoolRetainsLocationsIfUnchanged(t *testing.T) {
var src bool = true var src bool = true
var ref = config.NewValue(true, config.Location{File: "foo"}) var ref = dyn.NewValue(true, dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NewValue(true, config.Location{File: "foo"}), nv) assert.Equal(t, dyn.NewValue(true, dyn.Location{File: "foo"}), nv)
} }
func TestFromTypedBoolTypeError(t *testing.T) { func TestFromTypedBoolTypeError(t *testing.T) {
var src bool = true var src bool = true
var ref = config.V("string") var ref = dyn.V("string")
_, err := FromTyped(src, ref) _, err := FromTyped(src, ref)
require.Error(t, err) require.Error(t, err)
} }
func TestFromTypedIntEmpty(t *testing.T) { func TestFromTypedIntEmpty(t *testing.T) {
var src int var src int
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NilValue, nv) assert.Equal(t, dyn.NilValue, nv)
} }
func TestFromTypedIntEmptyOverwrite(t *testing.T) { func TestFromTypedIntEmptyOverwrite(t *testing.T) {
var src int var src int
var ref = config.V(1234) var ref = dyn.V(1234)
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(int64(0)), nv) assert.Equal(t, dyn.V(int64(0)), nv)
} }
func TestFromTypedIntNonEmpty(t *testing.T) { func TestFromTypedIntNonEmpty(t *testing.T) {
var src int = 1234 var src int = 1234
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(int64(1234)), nv) assert.Equal(t, dyn.V(int64(1234)), nv)
} }
func TestFromTypedIntNonEmptyOverwrite(t *testing.T) { func TestFromTypedIntNonEmptyOverwrite(t *testing.T) {
var src int = 1234 var src int = 1234
var ref = config.V(1233) var ref = dyn.V(1233)
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(int64(1234)), nv) assert.Equal(t, dyn.V(int64(1234)), nv)
} }
func TestFromTypedIntRetainsLocationsIfUnchanged(t *testing.T) { func TestFromTypedIntRetainsLocationsIfUnchanged(t *testing.T) {
var src int = 1234 var src int = 1234
var ref = config.NewValue(1234, config.Location{File: "foo"}) var ref = dyn.NewValue(1234, dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NewValue(1234, config.Location{File: "foo"}), nv) assert.Equal(t, dyn.NewValue(1234, dyn.Location{File: "foo"}), nv)
} }
func TestFromTypedIntTypeError(t *testing.T) { func TestFromTypedIntTypeError(t *testing.T) {
var src int = 1234 var src int = 1234
var ref = config.V("string") var ref = dyn.V("string")
_, err := FromTyped(src, ref) _, err := FromTyped(src, ref)
require.Error(t, err) require.Error(t, err)
} }
func TestFromTypedFloatEmpty(t *testing.T) { func TestFromTypedFloatEmpty(t *testing.T) {
var src float64 var src float64
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NilValue, nv) assert.Equal(t, dyn.NilValue, nv)
} }
func TestFromTypedFloatEmptyOverwrite(t *testing.T) { func TestFromTypedFloatEmptyOverwrite(t *testing.T) {
var src float64 var src float64
var ref = config.V(1.23) var ref = dyn.V(1.23)
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(0.0), nv) assert.Equal(t, dyn.V(0.0), nv)
} }
func TestFromTypedFloatNonEmpty(t *testing.T) { func TestFromTypedFloatNonEmpty(t *testing.T) {
var src float64 = 1.23 var src float64 = 1.23
var ref = config.NilValue var ref = dyn.NilValue
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(1.23), nv) assert.Equal(t, dyn.V(1.23), nv)
} }
func TestFromTypedFloatNonEmptyOverwrite(t *testing.T) { func TestFromTypedFloatNonEmptyOverwrite(t *testing.T) {
var src float64 = 1.23 var src float64 = 1.23
var ref = config.V(1.24) var ref = dyn.V(1.24)
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.V(1.23), nv) assert.Equal(t, dyn.V(1.23), nv)
} }
func TestFromTypedFloatRetainsLocationsIfUnchanged(t *testing.T) { func TestFromTypedFloatRetainsLocationsIfUnchanged(t *testing.T) {
var src float64 = 1.23 var src float64 = 1.23
var ref = config.NewValue(1.23, config.Location{File: "foo"}) var ref = dyn.NewValue(1.23, dyn.Location{File: "foo"})
nv, err := FromTyped(src, ref) nv, err := FromTyped(src, ref)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, config.NewValue(1.23, config.Location{File: "foo"}), nv) assert.Equal(t, dyn.NewValue(1.23, dyn.Location{File: "foo"}), nv)
} }
func TestFromTypedFloatTypeError(t *testing.T) { func TestFromTypedFloatTypeError(t *testing.T) {
var src float64 = 1.23 var src float64 = 1.23
var ref = config.V("string") var ref = dyn.V("string")
_, err := FromTyped(src, ref) _, err := FromTyped(src, ref)
require.Error(t, err) require.Error(t, err)
} }

View File

@ -5,15 +5,15 @@ import (
"reflect" "reflect"
"strconv" "strconv"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
) )
func Normalize(dst any, src config.Value) (config.Value, diag.Diagnostics) { func Normalize(dst any, src dyn.Value) (dyn.Value, diag.Diagnostics) {
return normalizeType(reflect.TypeOf(dst), src) return normalizeType(reflect.TypeOf(dst), src)
} }
func normalizeType(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeType(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
for typ.Kind() == reflect.Pointer { for typ.Kind() == reflect.Pointer {
typ = typ.Elem() typ = typ.Elem()
} }
@ -35,10 +35,10 @@ func normalizeType(typ reflect.Type, src config.Value) (config.Value, diag.Diagn
return normalizeFloat(typ, src) return normalizeFloat(typ, src)
} }
return config.NilValue, diag.Errorf("unsupported type: %s", typ.Kind()) return dyn.NilValue, diag.Errorf("unsupported type: %s", typ.Kind())
} }
func typeMismatch(expected config.Kind, src config.Value) diag.Diagnostic { func typeMismatch(expected dyn.Kind, src dyn.Value) diag.Diagnostic {
return diag.Diagnostic{ return diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: fmt.Sprintf("expected %s, found %s", expected, src.Kind()), Summary: fmt.Sprintf("expected %s, found %s", expected, src.Kind()),
@ -46,12 +46,12 @@ func typeMismatch(expected config.Kind, src config.Value) diag.Diagnostic {
} }
} }
func normalizeStruct(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeStruct(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics var diags diag.Diagnostics
switch src.Kind() { switch src.Kind() {
case config.KindMap: case dyn.KindMap:
out := make(map[string]config.Value) out := make(map[string]dyn.Value)
info := getStructInfo(typ) info := getStructInfo(typ)
for k, v := range src.MustMap() { for k, v := range src.MustMap() {
index, ok := info.Fields[k] index, ok := info.Fields[k]
@ -77,20 +77,20 @@ func normalizeStruct(typ reflect.Type, src config.Value) (config.Value, diag.Dia
out[k] = v out[k] = v
} }
return config.NewValue(out, src.Location()), diags return dyn.NewValue(out, src.Location()), diags
case config.KindNil: case dyn.KindNil:
return src, diags return src, diags
} }
return config.NilValue, diags.Append(typeMismatch(config.KindMap, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindMap, src))
} }
func normalizeMap(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeMap(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics var diags diag.Diagnostics
switch src.Kind() { switch src.Kind() {
case config.KindMap: case dyn.KindMap:
out := make(map[string]config.Value) out := make(map[string]dyn.Value)
for k, v := range src.MustMap() { for k, v := range src.MustMap() {
// Normalize the value according to the map element type. // Normalize the value according to the map element type.
v, err := normalizeType(typ.Elem(), v) v, err := normalizeType(typ.Elem(), v)
@ -105,20 +105,20 @@ func normalizeMap(typ reflect.Type, src config.Value) (config.Value, diag.Diagno
out[k] = v out[k] = v
} }
return config.NewValue(out, src.Location()), diags return dyn.NewValue(out, src.Location()), diags
case config.KindNil: case dyn.KindNil:
return src, diags return src, diags
} }
return config.NilValue, diags.Append(typeMismatch(config.KindMap, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindMap, src))
} }
func normalizeSlice(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeSlice(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics var diags diag.Diagnostics
switch src.Kind() { switch src.Kind() {
case config.KindSequence: case dyn.KindSequence:
out := make([]config.Value, 0, len(src.MustSequence())) out := make([]dyn.Value, 0, len(src.MustSequence()))
for _, v := range src.MustSequence() { for _, v := range src.MustSequence() {
// Normalize the value according to the slice element type. // Normalize the value according to the slice element type.
v, err := normalizeType(typ.Elem(), v) v, err := normalizeType(typ.Elem(), v)
@ -133,42 +133,42 @@ func normalizeSlice(typ reflect.Type, src config.Value) (config.Value, diag.Diag
out = append(out, v) out = append(out, v)
} }
return config.NewValue(out, src.Location()), diags return dyn.NewValue(out, src.Location()), diags
case config.KindNil: case dyn.KindNil:
return src, diags return src, diags
} }
return config.NilValue, diags.Append(typeMismatch(config.KindSequence, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindSequence, src))
} }
func normalizeString(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeString(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics var diags diag.Diagnostics
var out string var out string
switch src.Kind() { switch src.Kind() {
case config.KindString: case dyn.KindString:
out = src.MustString() out = src.MustString()
case config.KindBool: case dyn.KindBool:
out = strconv.FormatBool(src.MustBool()) out = strconv.FormatBool(src.MustBool())
case config.KindInt: case dyn.KindInt:
out = strconv.FormatInt(src.MustInt(), 10) out = strconv.FormatInt(src.MustInt(), 10)
case config.KindFloat: case dyn.KindFloat:
out = strconv.FormatFloat(src.MustFloat(), 'f', -1, 64) out = strconv.FormatFloat(src.MustFloat(), 'f', -1, 64)
default: default:
return config.NilValue, diags.Append(typeMismatch(config.KindString, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindString, src))
} }
return config.NewValue(out, src.Location()), diags return dyn.NewValue(out, src.Location()), diags
} }
func normalizeBool(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeBool(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics var diags diag.Diagnostics
var out bool var out bool
switch src.Kind() { switch src.Kind() {
case config.KindBool: case dyn.KindBool:
out = src.MustBool() out = src.MustBool()
case config.KindString: case dyn.KindString:
// See https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/decode.go#L684-L693. // See https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/decode.go#L684-L693.
switch src.MustString() { switch src.MustString() {
case "true", "y", "Y", "yes", "Yes", "YES", "on", "On", "ON": case "true", "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
@ -177,59 +177,59 @@ func normalizeBool(typ reflect.Type, src config.Value) (config.Value, diag.Diagn
out = false out = false
default: default:
// Cannot interpret as a boolean. // Cannot interpret as a boolean.
return config.NilValue, diags.Append(typeMismatch(config.KindBool, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindBool, src))
} }
default: default:
return config.NilValue, diags.Append(typeMismatch(config.KindBool, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindBool, src))
} }
return config.NewValue(out, src.Location()), diags return dyn.NewValue(out, src.Location()), diags
} }
func normalizeInt(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeInt(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics var diags diag.Diagnostics
var out int64 var out int64
switch src.Kind() { switch src.Kind() {
case config.KindInt: case dyn.KindInt:
out = src.MustInt() out = src.MustInt()
case config.KindString: case dyn.KindString:
var err error var err error
out, err = strconv.ParseInt(src.MustString(), 10, 64) out, err = strconv.ParseInt(src.MustString(), 10, 64)
if err != nil { if err != nil {
return config.NilValue, diags.Append(diag.Diagnostic{ return dyn.NilValue, diags.Append(diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: fmt.Sprintf("cannot parse %q as an integer", src.MustString()), Summary: fmt.Sprintf("cannot parse %q as an integer", src.MustString()),
Location: src.Location(), Location: src.Location(),
}) })
} }
default: default:
return config.NilValue, diags.Append(typeMismatch(config.KindInt, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindInt, src))
} }
return config.NewValue(out, src.Location()), diags return dyn.NewValue(out, src.Location()), diags
} }
func normalizeFloat(typ reflect.Type, src config.Value) (config.Value, diag.Diagnostics) { func normalizeFloat(typ reflect.Type, src dyn.Value) (dyn.Value, diag.Diagnostics) {
var diags diag.Diagnostics var diags diag.Diagnostics
var out float64 var out float64
switch src.Kind() { switch src.Kind() {
case config.KindFloat: case dyn.KindFloat:
out = src.MustFloat() out = src.MustFloat()
case config.KindString: case dyn.KindString:
var err error var err error
out, err = strconv.ParseFloat(src.MustString(), 64) out, err = strconv.ParseFloat(src.MustString(), 64)
if err != nil { if err != nil {
return config.NilValue, diags.Append(diag.Diagnostic{ return dyn.NilValue, diags.Append(diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: fmt.Sprintf("cannot parse %q as a floating point number", src.MustString()), Summary: fmt.Sprintf("cannot parse %q as a floating point number", src.MustString()),
Location: src.Location(), Location: src.Location(),
}) })
} }
default: default:
return config.NilValue, diags.Append(typeMismatch(config.KindFloat, src)) return dyn.NilValue, diags.Append(typeMismatch(dyn.KindFloat, src))
} }
return config.NewValue(out, src.Location()), diags return dyn.NewValue(out, src.Location()), diags
} }

View File

@ -3,8 +3,8 @@ package convert
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config"
"github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -15,9 +15,9 @@ func TestNormalizeStruct(t *testing.T) {
} }
var typ Tmp var typ Tmp
vin := config.V(map[string]config.Value{ vin := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
@ -32,9 +32,9 @@ func TestNormalizeStructElementDiagnostic(t *testing.T) {
} }
var typ Tmp var typ Tmp
vin := config.V(map[string]config.Value{ vin := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V(map[string]config.Value{"an": config.V("error")}), "bar": dyn.V(map[string]dyn.Value{"an": dyn.V("error")}),
}) })
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
@ -42,7 +42,7 @@ func TestNormalizeStructElementDiagnostic(t *testing.T) {
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: `expected string, found map`, Summary: `expected string, found map`,
Location: config.Location{}, Location: dyn.Location{},
}, err[0]) }, err[0])
// Elements that encounter an error during normalization are dropped. // Elements that encounter an error during normalization are dropped.
@ -57,9 +57,9 @@ func TestNormalizeStructUnknownField(t *testing.T) {
} }
var typ Tmp var typ Tmp
vin := config.V(map[string]config.Value{ vin := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
@ -82,7 +82,7 @@ func TestNormalizeStructNil(t *testing.T) {
} }
var typ Tmp var typ Tmp
vin := config.NilValue vin := dyn.NilValue
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, vin, vout) assert.Equal(t, vin, vout)
@ -94,7 +94,7 @@ func TestNormalizeStructError(t *testing.T) {
} }
var typ Tmp var typ Tmp
vin := config.V("string") vin := dyn.V("string")
_, err := Normalize(typ, vin) _, err := Normalize(typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -106,9 +106,9 @@ func TestNormalizeStructError(t *testing.T) {
func TestNormalizeMap(t *testing.T) { func TestNormalizeMap(t *testing.T) {
var typ map[string]string var typ map[string]string
vin := config.V(map[string]config.Value{ vin := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
@ -118,9 +118,9 @@ func TestNormalizeMap(t *testing.T) {
func TestNormalizeMapElementDiagnostic(t *testing.T) { func TestNormalizeMapElementDiagnostic(t *testing.T) {
var typ map[string]string var typ map[string]string
vin := config.V(map[string]config.Value{ vin := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V(map[string]config.Value{"an": config.V("error")}), "bar": dyn.V(map[string]dyn.Value{"an": dyn.V("error")}),
}) })
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
@ -128,7 +128,7 @@ func TestNormalizeMapElementDiagnostic(t *testing.T) {
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: `expected string, found map`, Summary: `expected string, found map`,
Location: config.Location{}, Location: dyn.Location{},
}, err[0]) }, err[0])
// Elements that encounter an error during normalization are dropped. // Elements that encounter an error during normalization are dropped.
@ -139,7 +139,7 @@ func TestNormalizeMapElementDiagnostic(t *testing.T) {
func TestNormalizeMapNil(t *testing.T) { func TestNormalizeMapNil(t *testing.T) {
var typ map[string]string var typ map[string]string
vin := config.NilValue vin := dyn.NilValue
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, vin, vout) assert.Equal(t, vin, vout)
@ -147,7 +147,7 @@ func TestNormalizeMapNil(t *testing.T) {
func TestNormalizeMapError(t *testing.T) { func TestNormalizeMapError(t *testing.T) {
var typ map[string]string var typ map[string]string
vin := config.V("string") vin := dyn.V("string")
_, err := Normalize(typ, vin) _, err := Normalize(typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -159,9 +159,9 @@ func TestNormalizeMapError(t *testing.T) {
func TestNormalizeSlice(t *testing.T) { func TestNormalizeSlice(t *testing.T) {
var typ []string var typ []string
vin := config.V([]config.Value{ vin := dyn.V([]dyn.Value{
config.V("foo"), dyn.V("foo"),
config.V("bar"), dyn.V("bar"),
}) })
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
@ -171,10 +171,10 @@ func TestNormalizeSlice(t *testing.T) {
func TestNormalizeSliceElementDiagnostic(t *testing.T) { func TestNormalizeSliceElementDiagnostic(t *testing.T) {
var typ []string var typ []string
vin := config.V([]config.Value{ vin := dyn.V([]dyn.Value{
config.V("foo"), dyn.V("foo"),
config.V("bar"), dyn.V("bar"),
config.V(map[string]config.Value{"an": config.V("error")}), dyn.V(map[string]dyn.Value{"an": dyn.V("error")}),
}) })
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
@ -182,7 +182,7 @@ func TestNormalizeSliceElementDiagnostic(t *testing.T) {
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: `expected string, found map`, Summary: `expected string, found map`,
Location: config.Location{}, Location: dyn.Location{},
}, err[0]) }, err[0])
// Elements that encounter an error during normalization are dropped. // Elements that encounter an error during normalization are dropped.
@ -191,7 +191,7 @@ func TestNormalizeSliceElementDiagnostic(t *testing.T) {
func TestNormalizeSliceNil(t *testing.T) { func TestNormalizeSliceNil(t *testing.T) {
var typ []string var typ []string
vin := config.NilValue vin := dyn.NilValue
vout, err := Normalize(typ, vin) vout, err := Normalize(typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, vin, vout) assert.Equal(t, vin, vout)
@ -199,7 +199,7 @@ func TestNormalizeSliceNil(t *testing.T) {
func TestNormalizeSliceError(t *testing.T) { func TestNormalizeSliceError(t *testing.T) {
var typ []string var typ []string
vin := config.V("string") vin := dyn.V("string")
_, err := Normalize(typ, vin) _, err := Normalize(typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -211,7 +211,7 @@ func TestNormalizeSliceError(t *testing.T) {
func TestNormalizeString(t *testing.T) { func TestNormalizeString(t *testing.T) {
var typ string var typ string
vin := config.V("string") vin := dyn.V("string")
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, vin, vout) assert.Equal(t, vin, vout)
@ -219,7 +219,7 @@ func TestNormalizeString(t *testing.T) {
func TestNormalizeStringNil(t *testing.T) { func TestNormalizeStringNil(t *testing.T) {
var typ string var typ string
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1}) vin := dyn.NewValue(nil, dyn.Location{File: "file", Line: 1, Column: 1})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -231,51 +231,51 @@ func TestNormalizeStringNil(t *testing.T) {
func TestNormalizeStringFromBool(t *testing.T) { func TestNormalizeStringFromBool(t *testing.T) {
var typ string var typ string
vin := config.NewValue(true, config.Location{File: "file", Line: 1, Column: 1}) vin := dyn.NewValue(true, dyn.Location{File: "file", Line: 1, Column: 1})
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.NewValue("true", vin.Location()), vout) assert.Equal(t, dyn.NewValue("true", vin.Location()), vout)
} }
func TestNormalizeStringFromInt(t *testing.T) { func TestNormalizeStringFromInt(t *testing.T) {
var typ string var typ string
vin := config.NewValue(123, config.Location{File: "file", Line: 1, Column: 1}) vin := dyn.NewValue(123, dyn.Location{File: "file", Line: 1, Column: 1})
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.NewValue("123", vin.Location()), vout) assert.Equal(t, dyn.NewValue("123", vin.Location()), vout)
} }
func TestNormalizeStringFromFloat(t *testing.T) { func TestNormalizeStringFromFloat(t *testing.T) {
var typ string var typ string
vin := config.NewValue(1.20, config.Location{File: "file", Line: 1, Column: 1}) vin := dyn.NewValue(1.20, dyn.Location{File: "file", Line: 1, Column: 1})
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.NewValue("1.2", vin.Location()), vout) assert.Equal(t, dyn.NewValue("1.2", vin.Location()), vout)
} }
func TestNormalizeStringError(t *testing.T) { func TestNormalizeStringError(t *testing.T) {
var typ string var typ string
vin := config.V(map[string]config.Value{"an": config.V("error")}) vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: `expected string, found map`, Summary: `expected string, found map`,
Location: config.Location{}, Location: dyn.Location{},
}, err[0]) }, err[0])
} }
func TestNormalizeBool(t *testing.T) { func TestNormalizeBool(t *testing.T) {
var typ bool var typ bool
vin := config.V(true) vin := dyn.V(true)
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.V(true), vout) assert.Equal(t, dyn.V(true), vout)
} }
func TestNormalizeBoolNil(t *testing.T) { func TestNormalizeBoolNil(t *testing.T) {
var typ bool var typ bool
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1}) vin := dyn.NewValue(nil, dyn.Location{File: "file", Line: 1, Column: 1})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -299,16 +299,16 @@ func TestNormalizeBoolFromString(t *testing.T) {
{"on", true}, {"on", true},
{"off", false}, {"off", false},
} { } {
vin := config.V(c.Input) vin := dyn.V(c.Input)
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.V(c.Output), vout) assert.Equal(t, dyn.V(c.Output), vout)
} }
} }
func TestNormalizeBoolFromStringError(t *testing.T) { func TestNormalizeBoolFromStringError(t *testing.T) {
var typ bool var typ bool
vin := config.V("abc") vin := dyn.V("abc")
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -320,27 +320,27 @@ func TestNormalizeBoolFromStringError(t *testing.T) {
func TestNormalizeBoolError(t *testing.T) { func TestNormalizeBoolError(t *testing.T) {
var typ bool var typ bool
vin := config.V(map[string]config.Value{"an": config.V("error")}) vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: `expected bool, found map`, Summary: `expected bool, found map`,
Location: config.Location{}, Location: dyn.Location{},
}, err[0]) }, err[0])
} }
func TestNormalizeInt(t *testing.T) { func TestNormalizeInt(t *testing.T) {
var typ int var typ int
vin := config.V(123) vin := dyn.V(123)
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.V(int64(123)), vout) assert.Equal(t, dyn.V(int64(123)), vout)
} }
func TestNormalizeIntNil(t *testing.T) { func TestNormalizeIntNil(t *testing.T) {
var typ int var typ int
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1}) vin := dyn.NewValue(nil, dyn.Location{File: "file", Line: 1, Column: 1})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -352,15 +352,15 @@ func TestNormalizeIntNil(t *testing.T) {
func TestNormalizeIntFromString(t *testing.T) { func TestNormalizeIntFromString(t *testing.T) {
var typ int var typ int
vin := config.V("123") vin := dyn.V("123")
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.V(int64(123)), vout) assert.Equal(t, dyn.V(int64(123)), vout)
} }
func TestNormalizeIntFromStringError(t *testing.T) { func TestNormalizeIntFromStringError(t *testing.T) {
var typ int var typ int
vin := config.V("abc") vin := dyn.V("abc")
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -372,27 +372,27 @@ func TestNormalizeIntFromStringError(t *testing.T) {
func TestNormalizeIntError(t *testing.T) { func TestNormalizeIntError(t *testing.T) {
var typ int var typ int
vin := config.V(map[string]config.Value{"an": config.V("error")}) vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: `expected int, found map`, Summary: `expected int, found map`,
Location: config.Location{}, Location: dyn.Location{},
}, err[0]) }, err[0])
} }
func TestNormalizeFloat(t *testing.T) { func TestNormalizeFloat(t *testing.T) {
var typ float64 var typ float64
vin := config.V(1.2) vin := dyn.V(1.2)
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.V(1.2), vout) assert.Equal(t, dyn.V(1.2), vout)
} }
func TestNormalizeFloatNil(t *testing.T) { func TestNormalizeFloatNil(t *testing.T) {
var typ float64 var typ float64
vin := config.NewValue(nil, config.Location{File: "file", Line: 1, Column: 1}) vin := dyn.NewValue(nil, dyn.Location{File: "file", Line: 1, Column: 1})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -404,15 +404,15 @@ func TestNormalizeFloatNil(t *testing.T) {
func TestNormalizeFloatFromString(t *testing.T) { func TestNormalizeFloatFromString(t *testing.T) {
var typ float64 var typ float64
vin := config.V("1.2") vin := dyn.V("1.2")
vout, err := Normalize(&typ, vin) vout, err := Normalize(&typ, vin)
assert.Empty(t, err) assert.Empty(t, err)
assert.Equal(t, config.V(1.2), vout) assert.Equal(t, dyn.V(1.2), vout)
} }
func TestNormalizeFloatFromStringError(t *testing.T) { func TestNormalizeFloatFromStringError(t *testing.T) {
var typ float64 var typ float64
vin := config.V("abc") vin := dyn.V("abc")
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
@ -424,12 +424,12 @@ func TestNormalizeFloatFromStringError(t *testing.T) {
func TestNormalizeFloatError(t *testing.T) { func TestNormalizeFloatError(t *testing.T) {
var typ float64 var typ float64
vin := config.V(map[string]config.Value{"an": config.V("error")}) vin := dyn.V(map[string]dyn.Value{"an": dyn.V("error")})
_, err := Normalize(&typ, vin) _, err := Normalize(&typ, vin)
assert.Len(t, err, 1) assert.Len(t, err, 1)
assert.Equal(t, diag.Diagnostic{ assert.Equal(t, diag.Diagnostic{
Severity: diag.Error, Severity: diag.Error,
Summary: `expected float, found map`, Summary: `expected float, found map`,
Location: config.Location{}, Location: dyn.Location{},
}, err[0]) }, err[0])
} }

View File

@ -5,16 +5,16 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
) )
// structInfo holds the type information we need to efficiently // structInfo holds the type information we need to efficiently
// convert data from a [config.Value] to a Go struct. // convert data from a [dyn.Value] to a Go struct.
type structInfo struct { type structInfo struct {
// Fields maps the JSON-name of the field to the field's index for use with [FieldByIndex]. // Fields maps the JSON-name of the field to the field's index for use with [FieldByIndex].
Fields map[string][]int Fields map[string][]int
// ValueField maps to the field with a [config.Value]. // ValueField maps to the field with a [dyn.Value].
// The underlying type is expected to only have one of these. // The underlying type is expected to only have one of these.
ValueField []int ValueField []int
} }
@ -74,10 +74,10 @@ func buildStructInfo(typ reflect.Type) structInfo {
continue continue
} }
// If this field has type [config.Value], we populate it with the source [config.Value] from [ToTyped]. // If this field has type [dyn.Value], we populate it with the source [dyn.Value] from [ToTyped].
if sf.IsExported() && sf.Type == configValueType { if sf.IsExported() && sf.Type == configValueType {
if out.ValueField != nil { if out.ValueField != nil {
panic("multiple config.Value fields") panic("multiple dyn.Value fields")
} }
out.ValueField = append(prefix, sf.Index...) out.ValueField = append(prefix, sf.Index...)
continue continue
@ -129,5 +129,5 @@ func (s *structInfo) FieldValues(v reflect.Value) map[string]reflect.Value {
return out return out
} }
// Type of [config.Value]. // Type of [dyn.Value].
var configValueType = reflect.TypeOf((*config.Value)(nil)).Elem() var configValueType = reflect.TypeOf((*dyn.Value)(nil)).Elem()

View File

@ -4,7 +4,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -207,7 +207,7 @@ func TestStructInfoValueFieldAbsent(t *testing.T) {
func TestStructInfoValueFieldPresent(t *testing.T) { func TestStructInfoValueFieldPresent(t *testing.T) {
type Tmp struct { type Tmp struct {
Foo config.Value Foo dyn.Value
} }
si := getStructInfo(reflect.TypeOf(Tmp{})) si := getStructInfo(reflect.TypeOf(Tmp{}))
@ -216,8 +216,8 @@ func TestStructInfoValueFieldPresent(t *testing.T) {
func TestStructInfoValueFieldMultiple(t *testing.T) { func TestStructInfoValueFieldMultiple(t *testing.T) {
type Tmp struct { type Tmp struct {
Foo config.Value Foo dyn.Value
Bar config.Value Bar dyn.Value
} }
assert.Panics(t, func() { assert.Panics(t, func() {

View File

@ -5,17 +5,17 @@ import (
"reflect" "reflect"
"strconv" "strconv"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
) )
func ToTyped(dst any, src config.Value) error { func ToTyped(dst any, src dyn.Value) error {
dstv := reflect.ValueOf(dst) dstv := reflect.ValueOf(dst)
// Dereference pointer if necessary // Dereference pointer if necessary
for dstv.Kind() == reflect.Pointer { for dstv.Kind() == reflect.Pointer {
// If the source value is nil and the destination is a settable pointer, // If the source value is nil and the destination is a settable pointer,
// set the destination to nil. Also see `end_to_end_test.go`. // set the destination to nil. Also see `end_to_end_test.go`.
if dstv.CanSet() && src == config.NilValue { if dstv.CanSet() && src == dyn.NilValue {
dstv.SetZero() dstv.SetZero()
return nil return nil
} }
@ -50,9 +50,9 @@ func ToTyped(dst any, src config.Value) error {
return fmt.Errorf("unsupported type: %s", dstv.Kind()) return fmt.Errorf("unsupported type: %s", dstv.Kind())
} }
func toTypedStruct(dst reflect.Value, src config.Value) error { func toTypedStruct(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case config.KindMap: case dyn.KindMap:
info := getStructInfo(dst.Type()) info := getStructInfo(dst.Type())
for k, v := range src.MustMap() { for k, v := range src.MustMap() {
index, ok := info.Fields[k] index, ok := info.Fields[k]
@ -83,14 +83,14 @@ func toTypedStruct(dst reflect.Value, src config.Value) error {
} }
} }
// Populate field(s) for [config.Value], if any. // Populate field(s) for [dyn.Value], if any.
if info.ValueField != nil { if info.ValueField != nil {
vv := dst.FieldByIndex(info.ValueField) vv := dst.FieldByIndex(info.ValueField)
vv.Set(reflect.ValueOf(src)) vv.Set(reflect.ValueOf(src))
} }
return nil return nil
case config.KindNil: case dyn.KindNil:
dst.SetZero() dst.SetZero()
return nil return nil
} }
@ -101,9 +101,9 @@ func toTypedStruct(dst reflect.Value, src config.Value) error {
} }
} }
func toTypedMap(dst reflect.Value, src config.Value) error { func toTypedMap(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case config.KindMap: case dyn.KindMap:
m := src.MustMap() m := src.MustMap()
// Always overwrite. // Always overwrite.
@ -118,7 +118,7 @@ func toTypedMap(dst reflect.Value, src config.Value) error {
dst.SetMapIndex(kv, vv.Elem()) dst.SetMapIndex(kv, vv.Elem())
} }
return nil return nil
case config.KindNil: case dyn.KindNil:
dst.SetZero() dst.SetZero()
return nil return nil
} }
@ -129,9 +129,9 @@ func toTypedMap(dst reflect.Value, src config.Value) error {
} }
} }
func toTypedSlice(dst reflect.Value, src config.Value) error { func toTypedSlice(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case config.KindSequence: case dyn.KindSequence:
seq := src.MustSequence() seq := src.MustSequence()
// Always overwrite. // Always overwrite.
@ -143,7 +143,7 @@ func toTypedSlice(dst reflect.Value, src config.Value) error {
} }
} }
return nil return nil
case config.KindNil: case dyn.KindNil:
dst.SetZero() dst.SetZero()
return nil return nil
} }
@ -154,18 +154,18 @@ func toTypedSlice(dst reflect.Value, src config.Value) error {
} }
} }
func toTypedString(dst reflect.Value, src config.Value) error { func toTypedString(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case config.KindString: case dyn.KindString:
dst.SetString(src.MustString()) dst.SetString(src.MustString())
return nil return nil
case config.KindBool: case dyn.KindBool:
dst.SetString(strconv.FormatBool(src.MustBool())) dst.SetString(strconv.FormatBool(src.MustBool()))
return nil return nil
case config.KindInt: case dyn.KindInt:
dst.SetString(strconv.FormatInt(src.MustInt(), 10)) dst.SetString(strconv.FormatInt(src.MustInt(), 10))
return nil return nil
case config.KindFloat: case dyn.KindFloat:
dst.SetString(strconv.FormatFloat(src.MustFloat(), 'f', -1, 64)) dst.SetString(strconv.FormatFloat(src.MustFloat(), 'f', -1, 64))
return nil return nil
} }
@ -176,12 +176,12 @@ func toTypedString(dst reflect.Value, src config.Value) error {
} }
} }
func toTypedBool(dst reflect.Value, src config.Value) error { func toTypedBool(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case config.KindBool: case dyn.KindBool:
dst.SetBool(src.MustBool()) dst.SetBool(src.MustBool())
return nil return nil
case config.KindString: case dyn.KindString:
// See https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/decode.go#L684-L693. // See https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/decode.go#L684-L693.
switch src.MustString() { switch src.MustString() {
case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON": case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
@ -199,12 +199,12 @@ func toTypedBool(dst reflect.Value, src config.Value) error {
} }
} }
func toTypedInt(dst reflect.Value, src config.Value) error { func toTypedInt(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case config.KindInt: case dyn.KindInt:
dst.SetInt(src.MustInt()) dst.SetInt(src.MustInt())
return nil return nil
case config.KindString: case dyn.KindString:
if i64, err := strconv.ParseInt(src.MustString(), 10, 64); err == nil { if i64, err := strconv.ParseInt(src.MustString(), 10, 64); err == nil {
dst.SetInt(i64) dst.SetInt(i64)
return nil return nil
@ -217,12 +217,12 @@ func toTypedInt(dst reflect.Value, src config.Value) error {
} }
} }
func toTypedFloat(dst reflect.Value, src config.Value) error { func toTypedFloat(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case config.KindFloat: case dyn.KindFloat:
dst.SetFloat(src.MustFloat()) dst.SetFloat(src.MustFloat())
return nil return nil
case config.KindString: case dyn.KindString:
if f64, err := strconv.ParseFloat(src.MustString(), 64); err == nil { if f64, err := strconv.ParseFloat(src.MustString(), 64); err == nil {
dst.SetFloat(f64) dst.SetFloat(f64)
return nil return nil

View File

@ -3,7 +3,7 @@ package convert
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -21,9 +21,9 @@ func TestToTypedStruct(t *testing.T) {
} }
var out Tmp var out Tmp
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -48,9 +48,9 @@ func TestToTypedStructOverwrite(t *testing.T) {
Foo: "baz", Foo: "baz",
Bar: "qux", Bar: "qux",
} }
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -74,9 +74,9 @@ func TestToTypedStructAnonymousByValue(t *testing.T) {
} }
var out Tmp var out Tmp
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -100,9 +100,9 @@ func TestToTypedStructAnonymousByPointer(t *testing.T) {
} }
var out Tmp var out Tmp
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -117,7 +117,7 @@ func TestToTypedStructNil(t *testing.T) {
} }
var out = Tmp{} var out = Tmp{}
err := ToTyped(&out, config.NilValue) err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, Tmp{}, out) assert.Equal(t, Tmp{}, out)
} }
@ -128,7 +128,7 @@ func TestToTypedStructNilOverwrite(t *testing.T) {
} }
var out = Tmp{"bar"} var out = Tmp{"bar"}
err := ToTyped(&out, config.NilValue) err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, Tmp{}, out) assert.Equal(t, Tmp{}, out)
} }
@ -137,12 +137,12 @@ func TestToTypedStructWithValueField(t *testing.T) {
type Tmp struct { type Tmp struct {
Foo string `json:"foo"` Foo string `json:"foo"`
ConfigValue config.Value ConfigValue dyn.Value
} }
var out Tmp var out Tmp
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -154,8 +154,8 @@ func TestToTypedStructWithValueField(t *testing.T) {
func TestToTypedMap(t *testing.T) { func TestToTypedMap(t *testing.T) {
var out = map[string]string{} var out = map[string]string{}
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"key": config.V("value"), "key": dyn.V("value"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -169,8 +169,8 @@ func TestToTypedMapOverwrite(t *testing.T) {
"foo": "bar", "foo": "bar",
} }
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"bar": config.V("qux"), "bar": dyn.V("qux"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -182,8 +182,8 @@ func TestToTypedMapOverwrite(t *testing.T) {
func TestToTypedMapWithPointerElement(t *testing.T) { func TestToTypedMapWithPointerElement(t *testing.T) {
var out map[string]*string var out map[string]*string
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"key": config.V("value"), "key": dyn.V("value"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -194,7 +194,7 @@ func TestToTypedMapWithPointerElement(t *testing.T) {
func TestToTypedMapNil(t *testing.T) { func TestToTypedMapNil(t *testing.T) {
var out = map[string]string{} var out = map[string]string{}
err := ToTyped(&out, config.NilValue) err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, out) assert.Nil(t, out)
} }
@ -203,7 +203,7 @@ func TestToTypedMapNilOverwrite(t *testing.T) {
var out = map[string]string{ var out = map[string]string{
"foo": "bar", "foo": "bar",
} }
err := ToTyped(&out, config.NilValue) err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, out) assert.Nil(t, out)
} }
@ -211,9 +211,9 @@ func TestToTypedMapNilOverwrite(t *testing.T) {
func TestToTypedSlice(t *testing.T) { func TestToTypedSlice(t *testing.T) {
var out []string var out []string
v := config.V([]config.Value{ v := dyn.V([]dyn.Value{
config.V("foo"), dyn.V("foo"),
config.V("bar"), dyn.V("bar"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -226,9 +226,9 @@ func TestToTypedSlice(t *testing.T) {
func TestToTypedSliceOverwrite(t *testing.T) { func TestToTypedSliceOverwrite(t *testing.T) {
var out = []string{"qux"} var out = []string{"qux"}
v := config.V([]config.Value{ v := dyn.V([]dyn.Value{
config.V("foo"), dyn.V("foo"),
config.V("bar"), dyn.V("bar"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -241,9 +241,9 @@ func TestToTypedSliceOverwrite(t *testing.T) {
func TestToTypedSliceWithPointerElement(t *testing.T) { func TestToTypedSliceWithPointerElement(t *testing.T) {
var out []*string var out []*string
v := config.V([]config.Value{ v := dyn.V([]dyn.Value{
config.V("foo"), dyn.V("foo"),
config.V("bar"), dyn.V("bar"),
}) })
err := ToTyped(&out, v) err := ToTyped(&out, v)
@ -255,63 +255,63 @@ func TestToTypedSliceWithPointerElement(t *testing.T) {
func TestToTypedSliceNil(t *testing.T) { func TestToTypedSliceNil(t *testing.T) {
var out []string var out []string
err := ToTyped(&out, config.NilValue) err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, out) assert.Nil(t, out)
} }
func TestToTypedSliceNilOverwrite(t *testing.T) { func TestToTypedSliceNilOverwrite(t *testing.T) {
var out = []string{"foo"} var out = []string{"foo"}
err := ToTyped(&out, config.NilValue) err := ToTyped(&out, dyn.NilValue)
require.NoError(t, err) require.NoError(t, err)
assert.Nil(t, out) assert.Nil(t, out)
} }
func TestToTypedString(t *testing.T) { func TestToTypedString(t *testing.T) {
var out string var out string
err := ToTyped(&out, config.V("foo")) err := ToTyped(&out, dyn.V("foo"))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "foo", out) assert.Equal(t, "foo", out)
} }
func TestToTypedStringOverwrite(t *testing.T) { func TestToTypedStringOverwrite(t *testing.T) {
var out string = "bar" var out string = "bar"
err := ToTyped(&out, config.V("foo")) err := ToTyped(&out, dyn.V("foo"))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "foo", out) assert.Equal(t, "foo", out)
} }
func TestToTypedStringFromBool(t *testing.T) { func TestToTypedStringFromBool(t *testing.T) {
var out string var out string
err := ToTyped(&out, config.V(true)) err := ToTyped(&out, dyn.V(true))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "true", out) assert.Equal(t, "true", out)
} }
func TestToTypedStringFromInt(t *testing.T) { func TestToTypedStringFromInt(t *testing.T) {
var out string var out string
err := ToTyped(&out, config.V(123)) err := ToTyped(&out, dyn.V(123))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "123", out) assert.Equal(t, "123", out)
} }
func TestToTypedStringFromFloat(t *testing.T) { func TestToTypedStringFromFloat(t *testing.T) {
var out string var out string
err := ToTyped(&out, config.V(1.2)) err := ToTyped(&out, dyn.V(1.2))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "1.2", out) assert.Equal(t, "1.2", out)
} }
func TestToTypedBool(t *testing.T) { func TestToTypedBool(t *testing.T) {
var out bool var out bool
err := ToTyped(&out, config.V(true)) err := ToTyped(&out, dyn.V(true))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, true, out) assert.Equal(t, true, out)
} }
func TestToTypedBoolOverwrite(t *testing.T) { func TestToTypedBoolOverwrite(t *testing.T) {
var out bool = true var out bool = true
err := ToTyped(&out, config.V(false)) err := ToTyped(&out, dyn.V(false))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, false, out) assert.Equal(t, false, out)
} }
@ -321,128 +321,128 @@ func TestToTypedBoolFromString(t *testing.T) {
// True-ish // True-ish
for _, v := range []string{"y", "yes", "on"} { for _, v := range []string{"y", "yes", "on"} {
err := ToTyped(&out, config.V(v)) err := ToTyped(&out, dyn.V(v))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, true, out) assert.Equal(t, true, out)
} }
// False-ish // False-ish
for _, v := range []string{"n", "no", "off"} { for _, v := range []string{"n", "no", "off"} {
err := ToTyped(&out, config.V(v)) err := ToTyped(&out, dyn.V(v))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, false, out) assert.Equal(t, false, out)
} }
// Other // Other
err := ToTyped(&out, config.V("${var.foo}")) err := ToTyped(&out, dyn.V("${var.foo}"))
require.Error(t, err) require.Error(t, err)
} }
func TestToTypedInt(t *testing.T) { func TestToTypedInt(t *testing.T) {
var out int var out int
err := ToTyped(&out, config.V(1234)) err := ToTyped(&out, dyn.V(1234))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, int(1234), out) assert.Equal(t, int(1234), out)
} }
func TestToTypedInt32(t *testing.T) { func TestToTypedInt32(t *testing.T) {
var out32 int32 var out32 int32
err := ToTyped(&out32, config.V(1235)) err := ToTyped(&out32, dyn.V(1235))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, int32(1235), out32) assert.Equal(t, int32(1235), out32)
} }
func TestToTypedInt64(t *testing.T) { func TestToTypedInt64(t *testing.T) {
var out64 int64 var out64 int64
err := ToTyped(&out64, config.V(1236)) err := ToTyped(&out64, dyn.V(1236))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, int64(1236), out64) assert.Equal(t, int64(1236), out64)
} }
func TestToTypedIntOverwrite(t *testing.T) { func TestToTypedIntOverwrite(t *testing.T) {
var out int = 123 var out int = 123
err := ToTyped(&out, config.V(1234)) err := ToTyped(&out, dyn.V(1234))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, int(1234), out) assert.Equal(t, int(1234), out)
} }
func TestToTypedInt32Overwrite(t *testing.T) { func TestToTypedInt32Overwrite(t *testing.T) {
var out32 int32 = 123 var out32 int32 = 123
err := ToTyped(&out32, config.V(1234)) err := ToTyped(&out32, dyn.V(1234))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, int32(1234), out32) assert.Equal(t, int32(1234), out32)
} }
func TestToTypedInt64Overwrite(t *testing.T) { func TestToTypedInt64Overwrite(t *testing.T) {
var out64 int64 = 123 var out64 int64 = 123
err := ToTyped(&out64, config.V(1234)) err := ToTyped(&out64, dyn.V(1234))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, int64(1234), out64) assert.Equal(t, int64(1234), out64)
} }
func TestToTypedIntFromStringError(t *testing.T) { func TestToTypedIntFromStringError(t *testing.T) {
var out int var out int
err := ToTyped(&out, config.V("abc")) err := ToTyped(&out, dyn.V("abc"))
require.Error(t, err) require.Error(t, err)
} }
func TestToTypedIntFromStringInt(t *testing.T) { func TestToTypedIntFromStringInt(t *testing.T) {
var out int var out int
err := ToTyped(&out, config.V("123")) err := ToTyped(&out, dyn.V("123"))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, int(123), out) assert.Equal(t, int(123), out)
} }
func TestToTypedFloat32(t *testing.T) { func TestToTypedFloat32(t *testing.T) {
var out float32 var out float32
err := ToTyped(&out, config.V(float32(1.0))) err := ToTyped(&out, dyn.V(float32(1.0)))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, float32(1.0), out) assert.Equal(t, float32(1.0), out)
} }
func TestToTypedFloat64(t *testing.T) { func TestToTypedFloat64(t *testing.T) {
var out float64 var out float64
err := ToTyped(&out, config.V(float64(1.0))) err := ToTyped(&out, dyn.V(float64(1.0)))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, float64(1.0), out) assert.Equal(t, float64(1.0), out)
} }
func TestToTypedFloat32Overwrite(t *testing.T) { func TestToTypedFloat32Overwrite(t *testing.T) {
var out float32 = 1.0 var out float32 = 1.0
err := ToTyped(&out, config.V(float32(2.0))) err := ToTyped(&out, dyn.V(float32(2.0)))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, float32(2.0), out) assert.Equal(t, float32(2.0), out)
} }
func TestToTypedFloat64Overwrite(t *testing.T) { func TestToTypedFloat64Overwrite(t *testing.T) {
var out float64 = 1.0 var out float64 = 1.0
err := ToTyped(&out, config.V(float64(2.0))) err := ToTyped(&out, dyn.V(float64(2.0)))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, float64(2.0), out) assert.Equal(t, float64(2.0), out)
} }
func TestToTypedFloat32FromStringError(t *testing.T) { func TestToTypedFloat32FromStringError(t *testing.T) {
var out float32 var out float32
err := ToTyped(&out, config.V("abc")) err := ToTyped(&out, dyn.V("abc"))
require.Error(t, err) require.Error(t, err)
} }
func TestToTypedFloat64FromStringError(t *testing.T) { func TestToTypedFloat64FromStringError(t *testing.T) {
var out float64 var out float64
err := ToTyped(&out, config.V("abc")) err := ToTyped(&out, dyn.V("abc"))
require.Error(t, err) require.Error(t, err)
} }
func TestToTypedFloat32FromString(t *testing.T) { func TestToTypedFloat32FromString(t *testing.T) {
var out float32 var out float32
err := ToTyped(&out, config.V("1.2")) err := ToTyped(&out, dyn.V("1.2"))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, float32(1.2), out) assert.Equal(t, float32(1.2), out)
} }
func TestToTypedFloat64FromString(t *testing.T) { func TestToTypedFloat64FromString(t *testing.T) {
var out float64 var out float64
err := ToTyped(&out, config.V("1.2")) err := ToTyped(&out, dyn.V("1.2"))
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, float64(1.2), out) assert.Equal(t, float64(1.2), out)
} }

View File

@ -1,4 +1,4 @@
package config package dyn
import "time" import "time"

View File

@ -1,4 +1,4 @@
package config package dyn
import "fmt" import "fmt"

View File

@ -1,13 +1,13 @@
package config_test package dyn_test
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestLocation(t *testing.T) { func TestLocation(t *testing.T) {
loc := config.Location{File: "file", Line: 1, Column: 2} loc := dyn.Location{File: "file", Line: 1, Column: 2}
assert.Equal(t, "file:1:2", loc.String()) assert.Equal(t, "file:1:2", loc.String())
} }

View File

@ -3,7 +3,7 @@ package merge
import ( import (
"fmt" "fmt"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
) )
// Merge recursively merges the specified values. // Merge recursively merges the specified values.
@ -12,46 +12,46 @@ import (
// * Merging x with nil or nil with x always yields x. // * Merging x with nil or nil with x always yields x.
// * Merging maps a and b means entries from map b take precedence. // * Merging maps a and b means entries from map b take precedence.
// * Merging sequences a and b means concatenating them. // * Merging sequences a and b means concatenating them.
func Merge(a, b config.Value) (config.Value, error) { func Merge(a, b dyn.Value) (dyn.Value, error) {
return merge(a, b) return merge(a, b)
} }
func merge(a, b config.Value) (config.Value, error) { func merge(a, b dyn.Value) (dyn.Value, error) {
ak := a.Kind() ak := a.Kind()
bk := b.Kind() bk := b.Kind()
// If a is nil, return b. // If a is nil, return b.
if ak == config.KindNil { if ak == dyn.KindNil {
return b, nil return b, nil
} }
// If b is nil, return a. // If b is nil, return a.
if bk == config.KindNil { if bk == dyn.KindNil {
return a, nil return a, nil
} }
// Call the appropriate merge function based on the kind of a and b. // Call the appropriate merge function based on the kind of a and b.
switch ak { switch ak {
case config.KindMap: case dyn.KindMap:
if bk != config.KindMap { if bk != dyn.KindMap {
return config.NilValue, fmt.Errorf("cannot merge map with %s", bk) return dyn.NilValue, fmt.Errorf("cannot merge map with %s", bk)
} }
return mergeMap(a, b) return mergeMap(a, b)
case config.KindSequence: case dyn.KindSequence:
if bk != config.KindSequence { if bk != dyn.KindSequence {
return config.NilValue, fmt.Errorf("cannot merge sequence with %s", bk) return dyn.NilValue, fmt.Errorf("cannot merge sequence with %s", bk)
} }
return mergeSequence(a, b) return mergeSequence(a, b)
default: default:
if ak != bk { if ak != bk {
return config.NilValue, fmt.Errorf("cannot merge %s with %s", ak, bk) return dyn.NilValue, fmt.Errorf("cannot merge %s with %s", ak, bk)
} }
return mergePrimitive(a, b) return mergePrimitive(a, b)
} }
} }
func mergeMap(a, b config.Value) (config.Value, error) { func mergeMap(a, b dyn.Value) (dyn.Value, error) {
out := make(map[string]config.Value) out := make(map[string]dyn.Value)
am := a.MustMap() am := a.MustMap()
bm := b.MustMap() bm := b.MustMap()
@ -66,7 +66,7 @@ func mergeMap(a, b config.Value) (config.Value, error) {
// If the key already exists, merge the values. // If the key already exists, merge the values.
merged, err := merge(out[k], v) merged, err := merge(out[k], v)
if err != nil { if err != nil {
return config.NilValue, err return dyn.NilValue, err
} }
out[k] = merged out[k] = merged
} else { } else {
@ -76,23 +76,23 @@ func mergeMap(a, b config.Value) (config.Value, error) {
} }
// Preserve the location of the first value. // Preserve the location of the first value.
return config.NewValue(out, a.Location()), nil return dyn.NewValue(out, a.Location()), nil
} }
func mergeSequence(a, b config.Value) (config.Value, error) { func mergeSequence(a, b dyn.Value) (dyn.Value, error) {
as := a.MustSequence() as := a.MustSequence()
bs := b.MustSequence() bs := b.MustSequence()
// Merging sequences means concatenating them. // Merging sequences means concatenating them.
out := make([]config.Value, len(as)+len(bs)) out := make([]dyn.Value, len(as)+len(bs))
copy(out[:], as) copy(out[:], as)
copy(out[len(as):], bs) copy(out[len(as):], bs)
// Preserve the location of the first value. // Preserve the location of the first value.
return config.NewValue(out, a.Location()), nil return dyn.NewValue(out, a.Location()), nil
} }
func mergePrimitive(a, b config.Value) (config.Value, error) { func mergePrimitive(a, b dyn.Value) (dyn.Value, error) {
// Merging primitive values means using the incoming value. // Merging primitive values means using the incoming value.
return b, nil return b, nil
} }

View File

@ -3,19 +3,19 @@ package merge
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestMergeMaps(t *testing.T) { func TestMergeMaps(t *testing.T) {
v1 := config.V(map[string]config.Value{ v1 := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
"bar": config.V("baz"), "bar": dyn.V("baz"),
}) })
v2 := config.V(map[string]config.Value{ v2 := dyn.V(map[string]dyn.Value{
"bar": config.V("qux"), "bar": dyn.V("qux"),
"qux": config.V("foo"), "qux": dyn.V("foo"),
}) })
// Merge v2 into v1. // Merge v2 into v1.
@ -42,13 +42,13 @@ func TestMergeMaps(t *testing.T) {
} }
func TestMergeMapsNil(t *testing.T) { func TestMergeMapsNil(t *testing.T) {
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
}) })
// Merge nil into v. // Merge nil into v.
{ {
out, err := Merge(v, config.NilValue) out, err := Merge(v, dyn.NilValue)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, map[string]any{ assert.Equal(t, map[string]any{
"foo": "bar", "foo": "bar",
@ -57,7 +57,7 @@ func TestMergeMapsNil(t *testing.T) {
// Merge v into nil. // Merge v into nil.
{ {
out, err := Merge(config.NilValue, v) out, err := Merge(dyn.NilValue, v)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, map[string]any{ assert.Equal(t, map[string]any{
"foo": "bar", "foo": "bar",
@ -66,29 +66,29 @@ func TestMergeMapsNil(t *testing.T) {
} }
func TestMergeMapsError(t *testing.T) { func TestMergeMapsError(t *testing.T) {
v := config.V(map[string]config.Value{ v := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
}) })
other := config.V("string") other := dyn.V("string")
// Merge a string into v. // Merge a string into v.
{ {
out, err := Merge(v, other) out, err := Merge(v, other)
assert.EqualError(t, err, "cannot merge map with string") assert.EqualError(t, err, "cannot merge map with string")
assert.Equal(t, config.NilValue, out) assert.Equal(t, dyn.NilValue, out)
} }
} }
func TestMergeSequences(t *testing.T) { func TestMergeSequences(t *testing.T) {
v1 := config.V([]config.Value{ v1 := dyn.V([]dyn.Value{
config.V("bar"), dyn.V("bar"),
config.V("baz"), dyn.V("baz"),
}) })
v2 := config.V([]config.Value{ v2 := dyn.V([]dyn.Value{
config.V("qux"), dyn.V("qux"),
config.V("foo"), dyn.V("foo"),
}) })
// Merge v2 into v1. // Merge v2 into v1.
@ -117,13 +117,13 @@ func TestMergeSequences(t *testing.T) {
} }
func TestMergeSequencesNil(t *testing.T) { func TestMergeSequencesNil(t *testing.T) {
v := config.V([]config.Value{ v := dyn.V([]dyn.Value{
config.V("bar"), dyn.V("bar"),
}) })
// Merge nil into v. // Merge nil into v.
{ {
out, err := Merge(v, config.NilValue) out, err := Merge(v, dyn.NilValue)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, []any{ assert.Equal(t, []any{
"bar", "bar",
@ -132,7 +132,7 @@ func TestMergeSequencesNil(t *testing.T) {
// Merge v into nil. // Merge v into nil.
{ {
out, err := Merge(config.NilValue, v) out, err := Merge(dyn.NilValue, v)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, []any{ assert.Equal(t, []any{
"bar", "bar",
@ -141,23 +141,23 @@ func TestMergeSequencesNil(t *testing.T) {
} }
func TestMergeSequencesError(t *testing.T) { func TestMergeSequencesError(t *testing.T) {
v := config.V([]config.Value{ v := dyn.V([]dyn.Value{
config.V("bar"), dyn.V("bar"),
}) })
other := config.V("string") other := dyn.V("string")
// Merge a string into v. // Merge a string into v.
{ {
out, err := Merge(v, other) out, err := Merge(v, other)
assert.EqualError(t, err, "cannot merge sequence with string") assert.EqualError(t, err, "cannot merge sequence with string")
assert.Equal(t, config.NilValue, out) assert.Equal(t, dyn.NilValue, out)
} }
} }
func TestMergePrimitives(t *testing.T) { func TestMergePrimitives(t *testing.T) {
v1 := config.V("bar") v1 := dyn.V("bar")
v2 := config.V("baz") v2 := dyn.V("baz")
// Merge v2 into v1. // Merge v2 into v1.
{ {
@ -175,33 +175,33 @@ func TestMergePrimitives(t *testing.T) {
} }
func TestMergePrimitivesNil(t *testing.T) { func TestMergePrimitivesNil(t *testing.T) {
v := config.V("bar") v := dyn.V("bar")
// Merge nil into v. // Merge nil into v.
{ {
out, err := Merge(v, config.NilValue) out, err := Merge(v, dyn.NilValue)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "bar", out.AsAny()) assert.Equal(t, "bar", out.AsAny())
} }
// Merge v into nil. // Merge v into nil.
{ {
out, err := Merge(config.NilValue, v) out, err := Merge(dyn.NilValue, v)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "bar", out.AsAny()) assert.Equal(t, "bar", out.AsAny())
} }
} }
func TestMergePrimitivesError(t *testing.T) { func TestMergePrimitivesError(t *testing.T) {
v := config.V("bar") v := dyn.V("bar")
other := config.V(map[string]config.Value{ other := dyn.V(map[string]dyn.Value{
"foo": config.V("bar"), "foo": dyn.V("bar"),
}) })
// Merge a map into v. // Merge a map into v.
{ {
out, err := Merge(v, other) out, err := Merge(v, other)
assert.EqualError(t, err, "cannot merge string with map") assert.EqualError(t, err, "cannot merge string with map")
assert.Equal(t, config.NilValue, out) assert.Equal(t, dyn.NilValue, out)
} }
} }

View File

@ -1,4 +1,4 @@
package config package dyn
import ( import (
"bytes" "bytes"

View File

@ -1,4 +1,4 @@
package config package dyn
import ( import (
"fmt" "fmt"

View File

@ -1,10 +1,10 @@
package config_test package dyn_test
import ( import (
"fmt" "fmt"
"testing" "testing"
. "github.com/databricks/cli/libs/config" . "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

76
libs/dyn/path_test.go Normal file
View File

@ -0,0 +1,76 @@
package dyn_test
import (
"testing"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestPathAppend(t *testing.T) {
p := dyn.NewPath(dyn.Key("foo"))
// Single arg.
p1 := p.Append(dyn.Key("bar"))
assert.True(t, p1.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"))))
// Multiple args.
p2 := p.Append(dyn.Key("bar"), dyn.Index(1))
assert.True(t, p2.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"), dyn.Index(1))))
}
func TestPathJoin(t *testing.T) {
p := dyn.NewPath(dyn.Key("foo"))
// Single arg.
p1 := p.Join(dyn.NewPath(dyn.Key("bar")))
assert.True(t, p1.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"))))
// Multiple args.
p2 := p.Join(dyn.NewPath(dyn.Key("bar")), dyn.NewPath(dyn.Index(1)))
assert.True(t, p2.Equal(dyn.NewPath(dyn.Key("foo"), dyn.Key("bar"), dyn.Index(1))))
}
func TestPathEqualEmpty(t *testing.T) {
assert.True(t, dyn.EmptyPath.Equal(dyn.EmptyPath))
}
func TestPathEqual(t *testing.T) {
p1 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
p2 := dyn.NewPath(dyn.Key("bar"), dyn.Index(2))
assert.False(t, p1.Equal(p2), "expected %q to not equal %q", p1, p2)
p3 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
assert.True(t, p1.Equal(p3), "expected %q to equal %q", p1, p3)
p4 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1), dyn.Key("bar"), dyn.Index(2))
assert.False(t, p1.Equal(p4), "expected %q to not equal %q", p1, p4)
}
func TestPathHasPrefixEmpty(t *testing.T) {
empty := dyn.EmptyPath
nonEmpty := dyn.NewPath(dyn.Key("foo"))
assert.True(t, empty.HasPrefix(empty))
assert.True(t, nonEmpty.HasPrefix(empty))
assert.False(t, empty.HasPrefix(nonEmpty))
}
func TestPathHasPrefix(t *testing.T) {
p1 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
p2 := dyn.NewPath(dyn.Key("bar"), dyn.Index(2))
assert.False(t, p1.HasPrefix(p2), "expected %q to not have prefix %q", p1, p2)
p3 := dyn.NewPath(dyn.Key("foo"))
assert.True(t, p1.HasPrefix(p3), "expected %q to have prefix %q", p1, p3)
}
func TestPathString(t *testing.T) {
p1 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1))
assert.Equal(t, "foo[1]", p1.String())
p2 := dyn.NewPath(dyn.Key("bar"), dyn.Index(2), dyn.Key("baz"))
assert.Equal(t, "bar[2].baz", p2.String())
p3 := dyn.NewPath(dyn.Key("foo"), dyn.Index(1), dyn.Key("bar"), dyn.Index(2), dyn.Key("baz"))
assert.Equal(t, "foo[1].bar[2].baz", p3.String())
}

View File

@ -1,4 +1,4 @@
package config package dyn
import ( import (
"fmt" "fmt"

View File

@ -1,35 +1,35 @@
package config_test package dyn_test
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestValueIsAnchor(t *testing.T) { func TestValueIsAnchor(t *testing.T) {
var zero config.Value var zero dyn.Value
assert.False(t, zero.IsAnchor()) assert.False(t, zero.IsAnchor())
mark := zero.MarkAnchor() mark := zero.MarkAnchor()
assert.True(t, mark.IsAnchor()) assert.True(t, mark.IsAnchor())
} }
func TestValueAsMap(t *testing.T) { func TestValueAsMap(t *testing.T) {
var zeroValue config.Value var zeroValue dyn.Value
m, ok := zeroValue.AsMap() m, ok := zeroValue.AsMap()
assert.False(t, ok) assert.False(t, ok)
assert.Nil(t, m) assert.Nil(t, m)
var intValue = config.NewValue(1, config.Location{}) var intValue = dyn.NewValue(1, dyn.Location{})
m, ok = intValue.AsMap() m, ok = intValue.AsMap()
assert.False(t, ok) assert.False(t, ok)
assert.Nil(t, m) assert.Nil(t, m)
var mapValue = config.NewValue( var mapValue = dyn.NewValue(
map[string]config.Value{ map[string]dyn.Value{
"key": config.NewValue("value", config.Location{File: "file", Line: 1, Column: 2}), "key": dyn.NewValue("value", dyn.Location{File: "file", Line: 1, Column: 2}),
}, },
config.Location{File: "file", Line: 1, Column: 2}, dyn.Location{File: "file", Line: 1, Column: 2},
) )
m, ok = mapValue.AsMap() m, ok = mapValue.AsMap()
assert.True(t, ok) assert.True(t, ok)
@ -37,8 +37,8 @@ func TestValueAsMap(t *testing.T) {
} }
func TestValueIsValid(t *testing.T) { func TestValueIsValid(t *testing.T) {
var zeroValue config.Value var zeroValue dyn.Value
assert.False(t, zeroValue.IsValid()) assert.False(t, zeroValue.IsValid())
var intValue = config.NewValue(1, config.Location{}) var intValue = dyn.NewValue(1, dyn.Location{})
assert.True(t, intValue.IsValid()) assert.True(t, intValue.IsValid())
} }

View File

@ -1,4 +1,4 @@
package config package dyn
import "errors" import "errors"

View File

@ -1,10 +1,10 @@
package config_test package dyn_test
import ( import (
"errors" "errors"
"testing" "testing"
. "github.com/databricks/cli/libs/config" . "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -15,7 +15,7 @@ type loader struct {
path string path string
} }
func errorf(loc config.Location, format string, args ...interface{}) error { func errorf(loc dyn.Location, format string, args ...interface{}) error {
return fmt.Errorf("yaml (%s): %s", loc, fmt.Sprintf(format, args...)) return fmt.Errorf("yaml (%s): %s", loc, fmt.Sprintf(format, args...))
} }
@ -25,22 +25,22 @@ func newLoader(path string) *loader {
} }
} }
func (d *loader) location(node *yaml.Node) config.Location { func (d *loader) location(node *yaml.Node) dyn.Location {
return config.Location{ return dyn.Location{
File: d.path, File: d.path,
Line: node.Line, Line: node.Line,
Column: node.Column, Column: node.Column,
} }
} }
func (d *loader) load(node *yaml.Node) (config.Value, error) { func (d *loader) load(node *yaml.Node) (dyn.Value, error) {
loc := config.Location{ loc := dyn.Location{
File: d.path, File: d.path,
Line: node.Line, Line: node.Line,
Column: node.Column, Column: node.Column,
} }
var value config.Value var value dyn.Value
var err error var err error
switch node.Kind { switch node.Kind {
@ -55,7 +55,7 @@ func (d *loader) load(node *yaml.Node) (config.Value, error) {
case yaml.AliasNode: case yaml.AliasNode:
value, err = d.loadAlias(node, loc) value, err = d.loadAlias(node, loc)
default: default:
return config.NilValue, errorf(loc, "unknown node kind: %v", node.Kind) return dyn.NilValue, errorf(loc, "unknown node kind: %v", node.Kind)
} }
if err != nil { if err != nil {
@ -71,35 +71,35 @@ func (d *loader) load(node *yaml.Node) (config.Value, error) {
return value, nil return value, nil
} }
func (d *loader) loadDocument(node *yaml.Node, loc config.Location) (config.Value, error) { func (d *loader) loadDocument(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
return d.load(node.Content[0]) return d.load(node.Content[0])
} }
func (d *loader) loadSequence(node *yaml.Node, loc config.Location) (config.Value, error) { func (d *loader) loadSequence(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
acc := make([]config.Value, len(node.Content)) acc := make([]dyn.Value, len(node.Content))
for i, n := range node.Content { for i, n := range node.Content {
v, err := d.load(n) v, err := d.load(n)
if err != nil { if err != nil {
return config.NilValue, err return dyn.NilValue, err
} }
acc[i] = v acc[i] = v
} }
return config.NewValue(acc, loc), nil return dyn.NewValue(acc, loc), nil
} }
func (d *loader) loadMapping(node *yaml.Node, loc config.Location) (config.Value, error) { func (d *loader) loadMapping(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
var merge *yaml.Node var merge *yaml.Node
acc := make(map[string]config.Value) acc := make(map[string]dyn.Value)
for i := 0; i < len(node.Content); i += 2 { for i := 0; i < len(node.Content); i += 2 {
key := node.Content[i] key := node.Content[i]
val := node.Content[i+1] val := node.Content[i+1]
// Assert that keys are strings // Assert that keys are strings
if key.Kind != yaml.ScalarNode { if key.Kind != yaml.ScalarNode {
return config.NilValue, errorf(loc, "key is not a scalar") return dyn.NilValue, errorf(loc, "key is not a scalar")
} }
st := key.ShortTag() st := key.ShortTag()
@ -113,19 +113,19 @@ func (d *loader) loadMapping(node *yaml.Node, loc config.Location) (config.Value
merge = val merge = val
continue continue
default: default:
return config.NilValue, errorf(loc, "invalid key tag: %v", st) return dyn.NilValue, errorf(loc, "invalid key tag: %v", st)
} }
v, err := d.load(val) v, err := d.load(val)
if err != nil { if err != nil {
return config.NilValue, err return dyn.NilValue, err
} }
acc[key.Value] = v acc[key.Value] = v
} }
if merge == nil { if merge == nil {
return config.NewValue(acc, loc), nil return dyn.NewValue(acc, loc), nil
} }
// Build location for the merge node. // Build location for the merge node.
@ -141,68 +141,68 @@ func (d *loader) loadMapping(node *yaml.Node, loc config.Location) (config.Value
case yaml.AliasNode: case yaml.AliasNode:
mnodes = []*yaml.Node{merge} mnodes = []*yaml.Node{merge}
default: default:
return config.NilValue, merr return dyn.NilValue, merr
} }
// Build a sequence of values to merge. // Build a sequence of values to merge.
// The entries that we already accumulated have precedence. // The entries that we already accumulated have precedence.
var seq []map[string]config.Value var seq []map[string]dyn.Value
for _, n := range mnodes { for _, n := range mnodes {
v, err := d.load(n) v, err := d.load(n)
if err != nil { if err != nil {
return config.NilValue, err return dyn.NilValue, err
} }
m, ok := v.AsMap() m, ok := v.AsMap()
if !ok { if !ok {
return config.NilValue, merr return dyn.NilValue, merr
} }
seq = append(seq, m) seq = append(seq, m)
} }
// Append the accumulated entries to the sequence. // Append the accumulated entries to the sequence.
seq = append(seq, acc) seq = append(seq, acc)
out := make(map[string]config.Value) out := make(map[string]dyn.Value)
for _, m := range seq { for _, m := range seq {
for k, v := range m { for k, v := range m {
out[k] = v out[k] = v
} }
} }
return config.NewValue(out, loc), nil return dyn.NewValue(out, loc), nil
} }
func (d *loader) loadScalar(node *yaml.Node, loc config.Location) (config.Value, error) { func (d *loader) loadScalar(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
st := node.ShortTag() st := node.ShortTag()
switch st { switch st {
case "!!str": case "!!str":
return config.NewValue(node.Value, loc), nil return dyn.NewValue(node.Value, loc), nil
case "!!bool": case "!!bool":
switch strings.ToLower(node.Value) { switch strings.ToLower(node.Value) {
case "true": case "true":
return config.NewValue(true, loc), nil return dyn.NewValue(true, loc), nil
case "false": case "false":
return config.NewValue(false, loc), nil return dyn.NewValue(false, loc), nil
default: default:
return config.NilValue, errorf(loc, "invalid bool value: %v", node.Value) return dyn.NilValue, errorf(loc, "invalid bool value: %v", node.Value)
} }
case "!!int": case "!!int":
i64, err := strconv.ParseInt(node.Value, 10, 64) i64, err := strconv.ParseInt(node.Value, 10, 64)
if err != nil { if err != nil {
return config.NilValue, errorf(loc, "invalid int value: %v", node.Value) return dyn.NilValue, errorf(loc, "invalid int value: %v", node.Value)
} }
// Use regular int type instead of int64 if possible. // Use regular int type instead of int64 if possible.
if i64 >= math.MinInt32 && i64 <= math.MaxInt32 { if i64 >= math.MinInt32 && i64 <= math.MaxInt32 {
return config.NewValue(int(i64), loc), nil return dyn.NewValue(int(i64), loc), nil
} }
return config.NewValue(i64, loc), nil return dyn.NewValue(i64, loc), nil
case "!!float": case "!!float":
f64, err := strconv.ParseFloat(node.Value, 64) f64, err := strconv.ParseFloat(node.Value, 64)
if err != nil { if err != nil {
return config.NilValue, errorf(loc, "invalid float value: %v", node.Value) return dyn.NilValue, errorf(loc, "invalid float value: %v", node.Value)
} }
return config.NewValue(f64, loc), nil return dyn.NewValue(f64, loc), nil
case "!!null": case "!!null":
return config.NewValue(nil, loc), nil return dyn.NewValue(nil, loc), nil
case "!!timestamp": case "!!timestamp":
// Try a couple of layouts // Try a couple of layouts
for _, layout := range []string{ for _, layout := range []string{
@ -213,15 +213,15 @@ func (d *loader) loadScalar(node *yaml.Node, loc config.Location) (config.Value,
} { } {
t, terr := time.Parse(layout, node.Value) t, terr := time.Parse(layout, node.Value)
if terr == nil { if terr == nil {
return config.NewValue(t, loc), nil return dyn.NewValue(t, loc), nil
} }
} }
return config.NilValue, errorf(loc, "invalid timestamp value: %v", node.Value) return dyn.NilValue, errorf(loc, "invalid timestamp value: %v", node.Value)
default: default:
return config.NilValue, errorf(loc, "unknown tag: %v", st) return dyn.NilValue, errorf(loc, "unknown tag: %v", st)
} }
} }
func (d *loader) loadAlias(node *yaml.Node, loc config.Location) (config.Value, error) { func (d *loader) loadAlias(node *yaml.Node, loc dyn.Location) (dyn.Value, error) {
return d.load(node.Alias) return d.load(node.Alias)
} }

View File

@ -3,19 +3,19 @@ package yamlloader
import ( import (
"io" "io"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
func LoadYAML(path string, r io.Reader) (config.Value, error) { func LoadYAML(path string, r io.Reader) (dyn.Value, error) {
var node yaml.Node var node yaml.Node
dec := yaml.NewDecoder(r) dec := yaml.NewDecoder(r)
err := dec.Decode(&node) err := dec.Decode(&node)
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
return config.NilValue, nil return dyn.NilValue, nil
} }
return config.NilValue, err return dyn.NilValue, err
} }
return newLoader(path).load(&node) return newLoader(path).load(&node)

View File

@ -3,14 +3,14 @@ package yamlloader_test
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestYAMLAnchor01(t *testing.T) { func TestYAMLAnchor01(t *testing.T) {
file := "testdata/anchor_01.yml" file := "testdata/anchor_01.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
assert.True(t, self.Get("defaults").IsAnchor()) assert.True(t, self.Get("defaults").IsAnchor())
assert.False(t, self.Get("shirt1").IsAnchor()) assert.False(t, self.Get("shirt1").IsAnchor())
@ -18,31 +18,31 @@ func TestYAMLAnchor01(t *testing.T) {
pattern := self.Get("shirt1").Get("pattern") pattern := self.Get("shirt1").Get("pattern")
assert.Equal(t, "striped", pattern.AsAny()) assert.Equal(t, "striped", pattern.AsAny())
assert.Equal(t, config.Location{File: file, Line: 8, Column: 12}, pattern.Location()) assert.Equal(t, dyn.Location{File: file, Line: 8, Column: 12}, pattern.Location())
} }
func TestYAMLAnchor02(t *testing.T) { func TestYAMLAnchor02(t *testing.T) {
file := "testdata/anchor_02.yml" file := "testdata/anchor_02.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
color := self.Get("shirt").Get("color") color := self.Get("shirt").Get("color")
assert.Equal(t, "red", color.AsAny()) assert.Equal(t, "red", color.AsAny())
assert.Equal(t, config.Location{File: file, Line: 4, Column: 10}, color.Location()) assert.Equal(t, dyn.Location{File: file, Line: 4, Column: 10}, color.Location())
primary := self.Get("shirt").Get("primary") primary := self.Get("shirt").Get("primary")
assert.Equal(t, "cotton", primary.AsAny()) assert.Equal(t, "cotton", primary.AsAny())
assert.Equal(t, config.Location{File: file, Line: 8, Column: 12}, primary.Location()) assert.Equal(t, dyn.Location{File: file, Line: 8, Column: 12}, primary.Location())
pattern := self.Get("shirt").Get("pattern") pattern := self.Get("shirt").Get("pattern")
assert.Equal(t, "striped", pattern.AsAny()) assert.Equal(t, "striped", pattern.AsAny())
assert.Equal(t, config.Location{File: file, Line: 13, Column: 12}, pattern.Location()) assert.Equal(t, dyn.Location{File: file, Line: 13, Column: 12}, pattern.Location())
} }
func TestYAMLAnchor03(t *testing.T) { func TestYAMLAnchor03(t *testing.T) {
file := "testdata/anchor_03.yml" file := "testdata/anchor_03.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
// Assert the override took place. // Assert the override took place.
blue := self.Get("shirt").Get("color") blue := self.Get("shirt").Get("color")
@ -55,63 +55,63 @@ func TestYAMLAnchor03(t *testing.T) {
func TestYAMLAnchor04(t *testing.T) { func TestYAMLAnchor04(t *testing.T) {
file := "testdata/anchor_04.yml" file := "testdata/anchor_04.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
p1 := self.Get("person1").Get("address").Get("city") p1 := self.Get("person1").Get("address").Get("city")
assert.Equal(t, "San Francisco", p1.AsAny()) assert.Equal(t, "San Francisco", p1.AsAny())
assert.Equal(t, config.Location{File: file, Line: 4, Column: 9}, p1.Location()) assert.Equal(t, dyn.Location{File: file, Line: 4, Column: 9}, p1.Location())
p2 := self.Get("person2").Get("address").Get("city") p2 := self.Get("person2").Get("address").Get("city")
assert.Equal(t, "Los Angeles", p2.AsAny()) assert.Equal(t, "Los Angeles", p2.AsAny())
assert.Equal(t, config.Location{File: file, Line: 16, Column: 11}, p2.Location()) assert.Equal(t, dyn.Location{File: file, Line: 16, Column: 11}, p2.Location())
} }
func TestYAMLAnchor05(t *testing.T) { func TestYAMLAnchor05(t *testing.T) {
file := "testdata/anchor_05.yml" file := "testdata/anchor_05.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
features := self.Get("phone1").Get("features") features := self.Get("phone1").Get("features")
assert.Equal(t, "wifi", features.Index(0).AsAny()) assert.Equal(t, "wifi", features.Index(0).AsAny())
assert.Equal(t, config.Location{File: file, Line: 4, Column: 5}, features.Index(0).Location()) assert.Equal(t, dyn.Location{File: file, Line: 4, Column: 5}, features.Index(0).Location())
assert.Equal(t, "bluetooth", features.Index(1).AsAny()) assert.Equal(t, "bluetooth", features.Index(1).AsAny())
assert.Equal(t, config.Location{File: file, Line: 5, Column: 5}, features.Index(1).Location()) assert.Equal(t, dyn.Location{File: file, Line: 5, Column: 5}, features.Index(1).Location())
} }
func TestYAMLAnchor06(t *testing.T) { func TestYAMLAnchor06(t *testing.T) {
file := "testdata/anchor_06.yml" file := "testdata/anchor_06.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
greeting := self.Get("greeting1") greeting := self.Get("greeting1")
assert.Equal(t, "Hello, World!", greeting.AsAny()) assert.Equal(t, "Hello, World!", greeting.AsAny())
assert.Equal(t, config.Location{File: file, Line: 2, Column: 16}, greeting.Location()) assert.Equal(t, dyn.Location{File: file, Line: 2, Column: 16}, greeting.Location())
} }
func TestYAMLAnchor07(t *testing.T) { func TestYAMLAnchor07(t *testing.T) {
file := "testdata/anchor_07.yml" file := "testdata/anchor_07.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
name := self.Get("person1").Get("name") name := self.Get("person1").Get("name")
assert.Equal(t, "Alice", name.AsAny()) assert.Equal(t, "Alice", name.AsAny())
assert.Equal(t, config.Location{File: file, Line: 5, Column: 9}, name.Location()) assert.Equal(t, dyn.Location{File: file, Line: 5, Column: 9}, name.Location())
age := self.Get("person1").Get("age") age := self.Get("person1").Get("age")
assert.Equal(t, 25, age.AsAny()) assert.Equal(t, 25, age.AsAny())
assert.Equal(t, config.Location{File: file, Line: 2, Column: 13}, age.Location()) assert.Equal(t, dyn.Location{File: file, Line: 2, Column: 13}, age.Location())
} }
func TestYAMLAnchor08(t *testing.T) { func TestYAMLAnchor08(t *testing.T) {
file := "testdata/anchor_08.yml" file := "testdata/anchor_08.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
username := self.Get("user1").Get("username") username := self.Get("user1").Get("username")
assert.Equal(t, "user1", username.AsAny()) assert.Equal(t, "user1", username.AsAny())
assert.Equal(t, config.Location{File: file, Line: 5, Column: 13}, username.Location()) assert.Equal(t, dyn.Location{File: file, Line: 5, Column: 13}, username.Location())
active := self.Get("user1").Get("active") active := self.Get("user1").Get("active")
assert.Equal(t, true, active.AsAny()) assert.Equal(t, true, active.AsAny())
assert.Equal(t, config.Location{File: file, Line: 2, Column: 11}, active.Location()) assert.Equal(t, dyn.Location{File: file, Line: 2, Column: 11}, active.Location())
} }

View File

@ -5,7 +5,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/databricks/cli/libs/config/yamlloader" "github.com/databricks/cli/libs/dyn/yamlloader"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"

View File

@ -3,14 +3,14 @@ package yamlloader_test
import ( import (
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestYAMLMix01(t *testing.T) { func TestYAMLMix01(t *testing.T) {
file := "testdata/mix_01.yml" file := "testdata/mix_01.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
assert.True(t, self.Get("base_address").IsAnchor()) assert.True(t, self.Get("base_address").IsAnchor())
assert.False(t, self.Get("office_address").IsAnchor()) assert.False(t, self.Get("office_address").IsAnchor())
@ -19,7 +19,7 @@ func TestYAMLMix01(t *testing.T) {
func TestYAMLMix02(t *testing.T) { func TestYAMLMix02(t *testing.T) {
file := "testdata/mix_02.yml" file := "testdata/mix_02.yml"
self := loadYAML(t, file) self := loadYAML(t, file)
assert.NotEqual(t, config.NilValue, self) assert.NotEqual(t, dyn.NilValue, self)
assert.True(t, self.Get("base_colors").IsAnchor()) assert.True(t, self.Get("base_colors").IsAnchor())
assert.False(t, self.Get("theme").IsAnchor()) assert.False(t, self.Get("theme").IsAnchor())

View File

@ -5,14 +5,14 @@ import (
"os" "os"
"testing" "testing"
"github.com/databricks/cli/libs/config" "github.com/databricks/cli/libs/dyn"
"github.com/databricks/cli/libs/config/yamlloader" "github.com/databricks/cli/libs/dyn/yamlloader"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
func loadYAML(t *testing.T, path string) config.Value { func loadYAML(t *testing.T, path string) dyn.Value {
input, err := os.ReadFile(path) input, err := os.ReadFile(path)
require.NoError(t, err) require.NoError(t, err)
@ -31,5 +31,5 @@ func loadYAML(t *testing.T, path string) config.Value {
func TestYAMLEmpty(t *testing.T) { func TestYAMLEmpty(t *testing.T) {
self := loadYAML(t, "testdata/empty.yml") self := loadYAML(t, "testdata/empty.yml")
assert.Equal(t, config.NilValue, self) assert.Equal(t, dyn.NilValue, self)
} }