kairos-sdk/unstructured/yaml.go
Itxaka e50888d054
Fix parsing cmdline when keys have a dash (#73)
* Fix parsing cmdline when keys have a dash

If a key has a dash we need to add quotes to it before parsing it with
gojq, otherwise it will fail AND the full cmdline will not be parsed!

Signed-off-by: Itxaka <itxaka@kairos.io>

* Actualizar bootcmdline_test.go

---------

Signed-off-by: Itxaka <itxaka@kairos.io>
2024-03-18 17:28:31 +01:00

153 lines
3.1 KiB
Go

package unstructured
import (
"errors"
"fmt"
"github.com/hashicorp/go-multierror"
"github.com/itchyny/gojq"
"gopkg.in/yaml.v3"
"strings"
)
func YAMLHasKey(query string, content []byte) (bool, error) {
data := map[string]interface{}{}
err := yaml.Unmarshal([]byte(content), &data)
if err != nil {
return false, err
}
c, err := gojq.Parse(fmt.Sprintf(".%s | ..", query))
if err != nil {
return false, err
}
code, err := gojq.Compile(c)
if err != nil {
return false, err
}
iter := code.Run(data)
v, _ := iter.Next()
if err, ok := v.(error); ok {
return false, err
}
if v == nil {
return false, nil
}
return true, nil
}
func lookupKey(command string, data map[string]interface{}) (interface{}, error) {
query, err := gojq.Parse(command)
if err != nil {
return nil, err
}
code, err := gojq.Compile(query)
if err != nil {
return nil, err
}
iter := code.Run(data)
v, ok := iter.Next()
if !ok {
return nil, errors.New("failed getting result from gojq")
}
return v, nil
}
func LookupString(command string, data map[string]interface{}) (string, error) {
v, err := lookupKey(command, data)
if err != nil {
return "", err
}
if t, ok := v.(string); ok {
return t, nil
}
return "", fmt.Errorf("value is not a string: %T", v)
}
func ReplaceValue(command string, data map[string]interface{}) (string, error) {
v, err := lookupKey(command, data)
if err != nil {
return "", err
}
if _, ok := v.(map[string]interface{}); ok {
b, err := yaml.Marshal(v)
return string(b), err
}
return "", fmt.Errorf("unexpected type: %T", v)
}
// func ReplaceKeyValue(command string, data interface{}) (string, error) {
// LookupString(commd
// }
func jq(command string, data map[string]interface{}) (map[string]interface{}, error) {
v, err := lookupKey(command, data)
if err != nil {
return make(map[string]interface{}), err
}
if err, ok := v.(error); ok {
return nil, err
}
if t, ok := v.(map[string]interface{}); ok {
return t, nil
}
return make(map[string]interface{}), nil
}
func ToYAML(v map[string]interface{}) ([]byte, error) {
data := map[string]interface{}{}
var errs error
for k, value := range v {
prefix := "."
equal := "="
tmplKey := "%s"
tmplValue := "\"%s\""
// If key has a dash we need to add quotes to it to avoid failure parsing ut
if strings.Contains(k, "-") {
tmplKey = "\"%s\""
}
// support boolean types
if value == "true" || value == "false" {
tmplValue = "%s"
}
finalTemplate := prefix + tmplKey + equal + tmplValue
newData, err := jq(fmt.Sprintf(finalTemplate, k, value), data)
if err != nil {
errs = multierror.Append(errs, err)
continue
}
data = newData
}
out, err := yaml.Marshal(&data)
if err != nil {
errs = multierror.Append(errs, err)
}
return out, errs
}
// ToYAMLMap turns a map string interface which describes a yaml file in 'dot.yaml' format to a fully deep marshalled yaml.
func ToYAMLMap(v map[string]interface{}) (map[string]interface{}, error) {
result := map[string]interface{}{}
tempData, err := ToYAML(v)
if err != nil {
return result, err
}
err = yaml.Unmarshal(tempData, &result)
return result, err
}