From 0ec3d2525de24324de3cc804642ba3ca59a57a0b Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 4 Apr 2025 16:13:08 +0200 Subject: [PATCH] Templates: fix quoting certain parameters (#20376) --- .../definition/meter/volkszaehler-http.yaml | 4 ++-- .../meter/volkszaehler-importexport.yaml | 8 +++---- .../definition/meter/volkszaehler-ws.yaml | 2 +- templates/definition/meter/vzlogger.yaml | 20 ++++++++-------- util/templates/includes/vehicle-common.tpl | 2 +- util/templates/init.go | 2 +- util/templates/types.go | 18 +-------------- util/templates/utils.go | 23 +++++++++++++++++++ util/templates/utils_test.go | 5 ++-- 9 files changed, 45 insertions(+), 39 deletions(-) diff --git a/templates/definition/meter/volkszaehler-http.yaml b/templates/definition/meter/volkszaehler-http.yaml index 9977302d9..8b4969086 100644 --- a/templates/definition/meter/volkszaehler-http.yaml +++ b/templates/definition/meter/volkszaehler-http.yaml @@ -21,8 +21,8 @@ render: | power: # power reading source: http # use http plugin {{- if .host }} - uri: http://{{ .host }}:{{ .port }}/api/data/{{ trimAll "'" .uuid }}.json?from=now + uri: http://{{ .host }}:{{ .port }}/api/data/{{ unquote .uuid }}.json?from=now {{ else }} - uri: {{ trimSuffix "/" .url }}/{{ trimAll "'" .uuid }}.json?from=now + uri: {{ trimSuffix "/" .url }}/{{ unquote .uuid }}.json?from=now {{- end }} jq: .data.tuples[0][1] # parse response json diff --git a/templates/definition/meter/volkszaehler-importexport.yaml b/templates/definition/meter/volkszaehler-importexport.yaml index d60e54f08..4c44455b7 100644 --- a/templates/definition/meter/volkszaehler-importexport.yaml +++ b/templates/definition/meter/volkszaehler-importexport.yaml @@ -25,16 +25,16 @@ render: | add: - source: http # import channel {{- if .host }} - uri: http://{{ .host }}:{{ .port }}/api/data/{{ trimAll "'" .importuuid }}.json?from=now + uri: http://{{ .host }}:{{ .port }}/api/data/{{ unquote .importuuid }}.json?from=now {{ else }} - uri: {{ trimSuffix "/" .url }}/{{ trimAll "'" .importuuid }}.json?from=now + uri: {{ trimSuffix "/" .url }}/{{ unquote .importuuid }}.json?from=now {{- end }} jq: .data.tuples[0][1] # parse response json - source: http # export channel {{- if .host }} - uri: http://{{ .host }}:{{ .port }}/api/data/{{ trimAll "'" .exportuuid }}.json?from=now + uri: http://{{ .host }}:{{ .port }}/api/data/{{ unquote .exportuuid }}.json?from=now {{ else }} - uri: {{ trimSuffix "/" .url }}/{{ trimAll "'" .exportuuid }}.json?from=now + uri: {{ trimSuffix "/" .url }}/{{ unquote .exportuuid }}.json?from=now {{- end }} jq: .data.tuples[0][1] # parse response json scale: -1 # export must result in negative values diff --git a/templates/definition/meter/volkszaehler-ws.yaml b/templates/definition/meter/volkszaehler-ws.yaml index d9c326b68..ed6680a4f 100644 --- a/templates/definition/meter/volkszaehler-ws.yaml +++ b/templates/definition/meter/volkszaehler-ws.yaml @@ -19,6 +19,6 @@ render: | power: # power reading source: ws # use websocket plugin uri: ws://{{ .host }}:{{ .port }}/socket - jq: .data | select(.uuid=={{ quote (trimAll "'" .uuid) }}) .tuples[0][1] # parse response json + jq: .data | select(.uuid=="{{ unquote .uuid }}") .tuples[0][1] # parse response json timeout: 30s scale: 1 diff --git a/templates/definition/meter/vzlogger.yaml b/templates/definition/meter/vzlogger.yaml index b57625678..cf1541f77 100644 --- a/templates/definition/meter/vzlogger.yaml +++ b/templates/definition/meter/vzlogger.yaml @@ -73,7 +73,7 @@ render: | power: # power reading source: http # use http plugin uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .uuid) }}) | .tuples[0][1] # parse response json + jq: .data[] | select(.uuid=="{{ unquote .uuid }}") | .tuples[0][1] # parse response json cache: {{ .cache }} {{- if .scale }} scale: {{ .scale }} @@ -82,44 +82,44 @@ render: | currents: - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l1currentuuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l1currentuuid }}") | .tuples[0][1] cache: {{ .cache }} - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l2currentuuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l2currentuuid }}") | .tuples[0][1] cache: {{ .cache }} - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l3currentuuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l3currentuuid }}") | .tuples[0][1] cache: {{ .cache }} {{ end -}} {{ if and .l1poweruuid .l2poweruuid .l3poweruuid -}} powers: - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l1poweruuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l1poweruuid }}") | .tuples[0][1] cache: {{ .cache }} - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l2poweruuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l2poweruuid }}") | .tuples[0][1] cache: {{ .cache }} - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l3poweruuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l3poweruuid }}") | .tuples[0][1] cache: {{ .cache }} {{ end -}} {{ if and .l1voltageuuid .l2voltageuuid .l3voltageuuid -}} voltages: - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l1voltageuuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l1voltageuuid }}") | .tuples[0][1] cache: {{ .cache }} - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l2voltageuuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l2voltageuuid }}") | .tuples[0][1] cache: {{ .cache }} - source: http uri: http://{{ .host }}:{{ .port }}/ - jq: .data[] | select(.uuid=={{ quote (trimAll "'" .l3voltageuuid) }}) | .tuples[0][1] + jq: .data[] | select(.uuid=="{{ unquote .l3voltageuuid }}") | .tuples[0][1] cache: {{ .cache }} {{ end -}} diff --git a/util/templates/includes/vehicle-common.tpl b/util/templates/includes/vehicle-common.tpl index 6212c8596..e5158ee5c 100644 --- a/util/templates/includes/vehicle-common.tpl +++ b/util/templates/includes/vehicle-common.tpl @@ -31,7 +31,7 @@ onIdentify: {{- if len .identifiers }} identifiers: {{- range .identifiers }} -- {{ . }} +- {{ quote . }} {{- end }} {{- end }} diff --git a/util/templates/init.go b/util/templates/init.go index 581d65809..9075839b3 100644 --- a/util/templates/init.go +++ b/util/templates/init.go @@ -31,7 +31,7 @@ var ( func init() { ConfigDefaults.Load() - baseTmpl = template.Must(template.ParseFS(includeFS, "includes/*.tpl")) + baseTmpl = template.Must(FuncMap(template.New("base")).ParseFS(includeFS, "includes/*.tpl")) for _, class := range []Class{Charger, Meter, Vehicle, Tariff} { load(class) diff --git a/util/templates/types.go b/util/templates/types.go index 7f92c466a..c08454114 100644 --- a/util/templates/types.go +++ b/util/templates/types.go @@ -8,7 +8,6 @@ import ( "strings" "dario.cat/mergo" - "gopkg.in/yaml.v3" ) const ( @@ -250,22 +249,7 @@ func (p *Param) yamlQuote(value string) string { return value } - input := fmt.Sprintf("key: %s", value) - - var res struct { - Value string `yaml:"key"` - } - - if err := yaml.Unmarshal([]byte(input), &res); err != nil || value != res.Value { - return quote(value) - } - - // fix 0815, but not 0 - if strings.HasPrefix(value, "0") && len(value) > 1 { - return quote(value) - } - - return value + return yamlQuote(value) } // Product contains naming information about a product a template supports diff --git a/util/templates/utils.go b/util/templates/utils.go index 7b2a75ff9..f5a0458ae 100644 --- a/util/templates/utils.go +++ b/util/templates/utils.go @@ -8,8 +8,30 @@ import ( "text/template" "github.com/Masterminds/sprig/v3" + "gopkg.in/yaml.v3" ) +func yamlQuote(value string) string { + if value == "" { + return value + } + + input := fmt.Sprintf("key: %s", value) + + var res struct { + Value any `yaml:"key"` + } + + if err := yaml.Unmarshal([]byte(input), &res); err == nil { + b, err := yaml.Marshal(res) + if err == nil && strings.TrimSpace(strings.TrimPrefix(string(b), "key: ")) == value { + return value + } + } + + return quote(value) +} + func quote(value string) string { quoted := strings.ReplaceAll(value, `'`, `''`) return fmt.Sprintf("'%s'", quoted) @@ -41,6 +63,7 @@ func FuncMap(tmpl *template.Template) *template.Template { }, "urlEncode": url.QueryEscape, "unquote": unquote, + "quote": yamlQuote, } return tmpl.Funcs(sprig.FuncMap()).Funcs(funcMap) diff --git a/util/templates/utils_test.go b/util/templates/utils_test.go index 14cde28e2..d654dffcd 100644 --- a/util/templates/utils_test.go +++ b/util/templates/utils_test.go @@ -10,10 +10,9 @@ import ( ) func TestYamlDecode(t *testing.T) { - p := Param{Type: TypeString} - for _, value := range []string{`value`, `!value`, `@value`, `"value"`, `"va"lue"`, `va'lue`, `@va'lue`, `0815`, `"0815"`, `4711`, `#pwd`, ``} { + for _, value := range []string{`value`, `!value`, `@value`, `"va"lue"`, `va'lue`, `@va'lue`, `0815`, `4711`, `#pwd`, ``} { t.Run(value, func(t *testing.T) { - quoted := p.yamlQuote(value) + quoted := yamlQuote(value) input := fmt.Sprintf("key: %s", quoted) var res struct {