Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
Signed-off-by: Jeff Ortel <jortel@redhat.com>
  • Loading branch information
jortel committed Jan 9, 2025
1 parent fb43f87 commit 3cc7cf2
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 12 deletions.
81 changes: 81 additions & 0 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"errors"
"testing"

"github.com/onsi/gomega"
Expand Down Expand Up @@ -126,3 +127,83 @@ func TestIncidentSelector(t *testing.T) {
selector = scope.incidentSelector()
g.Expect("(!package||package=a||package=b) && !(package=C||package=D)").To(gomega.Equal(selector))
}

func TestInjectorDefaults(t *testing.T) {
g := gomega.NewGomegaWithT(t)
inj := ResourceInjector{dict: make(map[string]any)}
r := &Resource{
Fields: []Field{
{
Name: "Name",
Key: "person.name",
Default: "Elmer",
},
{
Name: "Age",
Key: "person.age",
},
},
}
err := inj.addDefaults(r)
g.Expect(err).To(gomega.BeNil())
g.Expect(inj.dict[r.Fields[0].Key]).To(gomega.Equal(r.Fields[0].Default))
g.Expect(inj.dict[r.Fields[1].Key]).To(gomega.BeNil())
}

func TestInjectorTypeCast(t *testing.T) {
g := gomega.NewGomegaWithT(t)
inj := ResourceInjector{dict: make(map[string]any)}
r := &Resource{
Fields: []Field{
{
Name: "Name",
Key: "person.name",
Default: "Elmer",
},
{
Name: "Age",
Key: "person.age",
Type: "integer",
Default: "18",
},
{
Name: "Resident",
Key: "person.resident",
Type: "boolean",
Default: "true",
},
{
Name: "Member",
Key: "person.member",
Type: "boolean",
Default: 1,
},
{
Name: "One",
Key: "person.one",
Type: "integer",
Default: true,
},
},
}
err := inj.addDefaults(r)
g.Expect(err).To(gomega.BeNil())
g.Expect(inj.dict[r.Fields[0].Key]).To(gomega.Equal(r.Fields[0].Default))
g.Expect(inj.dict[r.Fields[1].Key]).To(gomega.Equal(18))
g.Expect(inj.dict[r.Fields[2].Key]).To(gomega.BeTrue())
g.Expect(inj.dict[r.Fields[3].Key]).To(gomega.BeTrue())
g.Expect(inj.dict[r.Fields[4].Key]).To(gomega.Equal(1))

// cast error.
inj.dict = make(map[string]any)
r.Fields = append(
r.Fields,
Field{
Name: "Resident",
Key: "person.parent",
Type: "integer",
Default: "true",
})
err = inj.addDefaults(r)
g.Expect(errors.Is(err, &TypeError{})).To(gomega.BeTrue())
}
158 changes: 146 additions & 12 deletions cmd/injector.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
pathlib "path"
"regexp"
"strconv"
"strings"

"github.com/konveyor/analyzer-lsp/provider"
Expand Down Expand Up @@ -49,11 +50,92 @@ func (e *FieldNotMatched) Is(err error) (matched bool) {
return
}

// TypeError used to report resource field cast error.
type TypeError struct {
Field *Field
Reason string
Object any
}

func (e *TypeError) Error() (s string) {
return fmt.Sprintf(
"Resource injector: cast failed. field=%s type=%s reason=%s, object:%v",
e.Field.Name,
e.Field.Type,
e.Reason,
e.Object)
}

func (e *TypeError) Is(err error) (matched bool) {
var inst *TypeError
matched = errors.As(err, &inst)
return
}

// Field injection specification.
type Field struct {
Name string `json:"name"`
Path string `json:"path"`
Key string `json:"key"`
Name string `json:"name"`
Path string `json:"path"`
Key string `json:"key"`
Type string `json:"type"`
Default any `json:"default"`
}

// cast returns object cast as defined by Field.Type.
func (f *Field) cast(object any) (cast any, err error) {
cast = object
if f.Type == "" {
return
}
defer func() {
if err != nil {
err = &TypeError{
Field: f,
Reason: err.Error(),
Object: object,
}
}
}()
switch strings.ToLower(f.Type) {
case "string":
cast = fmt.Sprintf("%v", object)
case "integer":
switch x := object.(type) {
case int,
int8,
int16,
int32,
int64:
cast = x
case bool:
cast = 0
if x {
cast = 1
}
case string:
cast, err = strconv.Atoi(x)
default:
err = errors.New("expected: int|boolean|string")
}
case "boolean":
switch x := object.(type) {
case bool:
cast = x
case int,
int8,
int16,
int32,
int64:
cast = x != 0
case string:
cast, err = strconv.ParseBool(x)
default:
err = errors.New("expected: int|boolean|string")
}
default:
err = errors.New("expected: integer|boolean")
}
return
}

// Resource injection specification.
Expand Down Expand Up @@ -97,6 +179,25 @@ func (p *ParsedSelector) With(s string) {
}

// ResourceInjector inject resources into extension metadata.
// Example:
// metadata:
// provider:
// address: localhost:$(PORT)
// initConfig:
// - providerSpecificConfig:
// mavenInsecure: $(maven.insecure)
// mavenSettingsFile: $(maven.settings.path)
// name: java
// resources:
// - selector: identity:kind=maven
// fields:
// - key: maven.settings.path
// name: settings
// path: /shared/creds/maven/settings.xml
// - selector: setting:key=mvn.insecure.enabled
// fields:
// - key: maven.insecure
// name: value
type ResourceInjector struct {
dict map[string]any
}
Expand Down Expand Up @@ -131,6 +232,9 @@ func (r *ResourceInjector) build(md *Metadata) (err error) {
if err != nil {
return
}
for _, resource := range md.Resources {
err = r.addDefaults(&resource)
}
for _, resource := range md.Resources {
parsed := ParsedSelector{}
parsed.With(resource.Selector)
Expand Down Expand Up @@ -165,6 +269,20 @@ func (r *ResourceInjector) build(md *Metadata) (err error) {
return
}

// addDefaults adds defaults when specified.
func (r *ResourceInjector) addDefaults(resource *Resource) (err error) {
for _, f := range resource.Fields {
if f.Default == nil {
continue
}
err = r.addField(&f, f.Default)
if err != nil {
return
}
}
return
}

// add the resource fields specified in the injector.
func (r *ResourceInjector) add(resource *Resource, object any) (err error) {
mp := r.asMap(object)
Expand All @@ -177,20 +295,36 @@ func (r *ResourceInjector) add(resource *Resource, object any) (err error) {
}
return
}
if f.Path != "" {
err = r.write(f.Path, v)
if err != nil {
return
}
v = f.Path
err = r.addField(&f, v)
if err != nil {
return
}
}
return
}

// addField adds field to the dict.
// When field has a path defined, the values is written to the
// file and the dict[key] = path.
func (r *ResourceInjector) addField(f *Field, v any) (err error) {
if f.Path != "" {
err = r.write(f.Path, v)
if err != nil {
return
}
v = f.Path
} else {
v, err = f.cast(v)
if err != nil {
return
}
r.dict[f.Key] = v
}
r.dict[f.Key] = v
return
}

// write a resource field value to a file.
func (r *ResourceInjector) write(path string, v any) (err error) {
func (r *ResourceInjector) write(path string, object any) (err error) {
err = nas.MkDir(pathlib.Dir(path), 0755)
if err != nil {
return
Expand All @@ -202,7 +336,7 @@ func (r *ResourceInjector) write(path string, v any) (err error) {
defer func() {
_ = f.Close()
}()
s := r.string(v)
s := r.string(object)
_, err = f.Write([]byte(s))
return
}
Expand Down

0 comments on commit 3cc7cf2

Please sign in to comment.