英文:
How do you apply a recursive formatting with Go Templates (Helm)?
问题
我正在使用helm,并给定一个yaml对象,我想要将其展开并应用一些递归格式化。
给定以下内容:
some_map:
with: different
indentation:
levels: and
nested:
sub:
maps: "42"
and_more:
maps: 42
我想要(例如)得到以下结果:
some_map.with="different"
some_map.indentation.levels="and"
some_map.nested.sub.maps="42"
some_map.nested.and_more.maps=42
我还没有在helm文档中找到关于递归循环的内容,请记住,示例中递归的格式(如果不是根节点,则为"%v.%v",否则为"%v=%v")可能会有所不同。
英文:
I'm using helm and given a yaml object I want to flatten it while applying some recursive formatting.
Given this:
some_map:
with: different
indentation:
levels: and
nested:
sub:
maps: "42"
and_more:
maps: 42
I want to (for example) get this:
some_map.with="different"
some_map.indentation.levels="and"
some_map.nested.sub.maps="42"
some_map.nested.and_more.maps=42
I haven't read anything about recursive looping in the helm docs, keep in mind that the format of the recursion in the example ( "%v.%v" if !root else "%v=%v" ) may vary.
答案1
得分: 3
是的,似乎{{ define
支持对{{ include
的递归使用,尽管不清楚递归的深度。
我编写了一个验证它是否可行的 PoC 示例:
{{- define "bob" -}}
{{- $it := . -}}
{{- $knd := kindOf . -}}
{{- if eq $knd "map" }}
{{- range (keys .) }}
{{- $k := . }}
{{- $v := get $it . }}
{{- $vk := kindOf $v }}
{{- if eq $vk "map" }}
{{- printf "%s." $k }}
{{- include "bob" $v }}
{{- else }}
{{- printf "%s=%s\n" $k (toJson $v) }}
{{- end }}
{{- end }}
{{- else }}
{{ toJson . }}#k({{ $knd }})
{{- end }}
{{- end -}}
调用方式如下:
{{ $fred := dict
"alpha" (dict "a0" "a0ch0")
"beta" (dict "beta0" (dict "beta00" 1234))
"charlie" (list "ch0" "ch1" "ch2") }}
data:
theData: |
{{ toJson $fred | indent 4 }}
toml: |
{{ include "bob" $fred | indent 4 }}
生成的结果如下:
data:
theData: |
{"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"]}
toml: |
alpha.a0="a0ch0"
beta.beta0.beta00=1234
charlie=["ch0","ch1","ch2"]
另外,你引用的示例似乎涉及到最外层的变量名,我认为 Helm 不知道这个变量名,所以你需要使用一个人工包装器 dict
来实现这种行为:{{ include "toToml" (dict "some_map" .Values.some_map) }}
。
英文:
Yes, it seems that {{ define
supports recursive use of {{ include
, although unknown to what depth
The PoC I whipped up to see if it could work
{{- define "bob" -}}
{{- $it := . -}}
{{- $knd := kindOf . -}}
{{- if eq $knd "map" }}
{{- range (keys .) }}
{{- $k := . }}
{{- $v := get $it . }}
{{- $vk := kindOf $v }}
{{- if eq $vk "map" }}
{{- printf "%s." $k }}
{{- include "bob" $v }}
{{- else }}
{{- printf "%s=%s\n" $k (toJson $v) }}
{{- end }}
{{- end }}
{{- else }}
{{ toJson . }}#k({{ $knd }})
{{- end }}
{{- end -}}
invoked as
{{ $fred := dict
"alpha" (dict "a0" "a0ch0")
"beta" (dict "beta0" (dict "beta00" 1234))
"charlie" (list "ch0" "ch1" "ch2") }}
data:
theData: |
{{ toJson $fred | indent 4 }}
toml: |
{{ include "bob" $fred | indent 4 }}
produced
data:
theData: |
{"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"]}
toml: |
alpha.a0="a0ch0"
beta.beta0.beta00=1234
charlie=["ch0","ch1","ch2"]
Also, your cited example seems to make reference to the outermost variable name, which I don't think helm knows about, so you'd need an artificial wrapper dict
in order to get that behavior: {{ include "toToml" (dict "some_map" .Values.some_map) }}
答案2
得分: 1
另一种方法
_helpers.tpl:
{{- define "template.flattenFn" -}}
{{- $ctx := . -}}
{{- if or (eq (kindOf .data) "map") (eq (kindOf .data) "slice") }}
{{- range $key, $value := .data }}
{{- include "template.flattenFn" (dict "prefixes" (append $ctx.prefixes $key) "data" $value ) }}
{{- end }}
{{- else }}
{{- printf "\"%s\":%s, " (join "__" .prefixes) (toJson .data) }}
{{- end }}
{{- end -}}
{{- define "template.flatten" -}}
{{- include "template.flattenFn" (dict "prefixes" list "data" . ) }}
{{- end -}}
values.yaml
environment_map:
Log:
Level:
Default: Debug
Target:
- Name: Console
Args:
formatter: "JsonFormatter"
usage
{{- range $env, $value := include "template.flatten" .Values.environment_map | fromYaml }}
- name: {{ $env }}
value: {{ $value | quote }}
result
- name: Log__Level__Default
value: "Debug"
- name: Log__Target__0__Args__formatter
value: "JsonFormatter"
- name: Log__Target__0__Name
value: "Console"
英文:
another approach
_helpers.tpl:
{{- define "template.flattenFn" -}}
{{- $ctx := . -}}
{{- if or (eq (kindOf .data) "map") (eq (kindOf .data) "slice") }}
{{- range $key, $value := .data }}
{{- include "template.flattenFn" (dict "prefixes" (append $ctx.prefixes $key) "data" $value ) }}
{{- end }}
{{- else }}
{{- printf "\"%s\":%s, " (join "__" .prefixes) (toJson .data) }}
{{- end }}
{{- end -}}
{{- define "template.flatten" -}}
{{- include "template.flattenFn" (dict "prefixes" list "data" . ) }}
{{- end -}}
values.yaml
environment_map:
Log:
Level:
Default: Debug
Target:
- Name: Console
Args:
formatter: "JsonFormatter"
usage
{{- range $env, $value := include "template.flatten" .Values.environment_map | fromYaml }}
- name: {{ $env }}
value: {{ $value | quote }}
result
- name: Log__Level__Default
value: "Debug"
- name: Log__Target__0__Args__formatter
value: "JsonFormatter"
- name: Log__Target__0__Name
value: "Console"
答案3
得分: 0
感谢@mdaniel的答案,它帮助/允许我解决了我的问题!然而,他的(快速,我明白了)解决方案存在问题,如果您具有相同前缀的多个值。继续使用他的示例:
{{ $fred := dict
"alpha" (dict "a0" "a0ch0")
"beta" (dict "beta0" (dict "beta00" 1234))
"charlie" (list "ch0" "ch1" "ch2")
"problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
data:
theData: |
{{ toJson $fred | indent 4 }}
toml: |
{{ include "bob" $fred | indent 4 }}
将产生以下结果:
data:
theData: |
{"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
toml: |
problem.beta0.1="1"
2="2"
alpha.a0="a0ch0"
beta.beta0.beta00=1234
charlie=["ch0","ch1","ch2"]
这是不正确的。还有另一个问题是顺序丢失的问题,不知道为什么或如何修复它,但这不是很大的问题。
我的额外要求是,我需要在所有行中添加公共前缀。如果没有它,您可以定义另一个模板来简化使用,但这很容易做到。
免责声明:我对helm/go-templating完全不熟悉,所以以下内容可能不是最佳解决方案,但它应该解决这些问题。
继续使用上面的示例:
{{ $fred := dict
"alpha" (dict "a0" "a0ch0")
"beta" (dict "beta0" (dict "beta00" 1234))
"charlie" (list "ch0" "ch1" "ch2")
"problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
data:
theData: |
{{ toJson $fred | indent 4 }}
toml: |
{{ include "flattenYaml" (dict "prefix" "added_prefix" "data" $fred) | indent 4 }}
将产生以下结果:
data:
theData: |
{"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
toml: |
added_prefix.alpha.a0="a0ch0"
added_prefix.beta.beta0.beta00=1234
added_prefix.charlie=["ch0","ch1","ch2"]
added_prefix.problem.beta0.1="1"
added_prefix.problem.beta0.2="2"
而flattenYaml
模板的源代码如下:
{{- define "flattenYaml" -}}
{{- $dict := . -}}
{{- $prefix := $dict.prefix -}}
{{- $data := $dict.data -}}
{{- $knd := kindOf $data -}}
{{- if eq $knd "map" }}
{{- range (keys $data) }}
{{- $key := . }}
{{- $prefixedKey := (printf "%s.%s" $prefix $key) }}
{{- $value := get $data $key }}
{{- $valueKind := kindOf $value }}
{{- if eq $valueKind "map" }}
{{- include "flattenYaml" (dict "prefix" ($prefixedKey) "data" $value) }}
{{- else }}
{{- printf "%s=%s\n" $prefixedKey (toJson $value) }}
{{- end }}
{{- end }}
{{- else }}
{{ toJson . }}#k({{ $knd }})
{{- end }}
{{- end -}}
免责声明2:我不知道原始解决方案中的#k ...
在{{ toJson . }}#k({{ $knd }})
中是什么意思,如果它在您的面前爆炸了,请不要感到惊讶;)
编辑:
原来的
{{ toJson . }}#k({{ $knd }})
实际上在我的面前爆炸了,我仍然不知道#k
应该起什么作用,但以下替换修复了我的问题:
{{- if ne $data nil }}
{{- toJson $data }}
{{- end }}
英文:
Thanks to @mdaniel for his answer, which helped/allowed me to fix my problem! His (quick, I get it) solution has problem though if you have move values with same prefix. To carry on with his example:
{{ $fred := dict
"alpha" (dict "a0" "a0ch0")
"beta" (dict "beta0" (dict "beta00" 1234))
"charlie" (list "ch0" "ch1" "ch2")
"problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
data:
theData: |
{{ toJson $fred | indent 4 }}
toml: |
{{ include "bob" $fred | indent 4 }}
will produce:
data:
theData: |
{"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
toml: |
problem.beta0.1="1"
2="2"
alpha.a0="a0ch0"
beta.beta0.beta00=1234
charlie=["ch0","ch1","ch2"]
which is not correct. Also there is another eye-candy problem of lost order, no idea why or how to fix it, but that's not such biggie.
My extra requirement was, that I needed to add common prefix to all lines. Without it you can define another template simplifying usage, but that's trivial to do.
disclaimer: I'm totally new to helm/go-templating, so following isn't probably optimal, but it should fix these issues.
To carry on with example again:
{{ $fred := dict
"alpha" (dict "a0" "a0ch0")
"beta" (dict "beta0" (dict "beta00" 1234))
"charlie" (list "ch0" "ch1" "ch2")
"problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
data:
theData: |
{{ toJson $fred | indent 4 }}
toml: |
{{ include "flattenYaml" (dict "prefix" "added_prefix" "data" $fred) | indent 4 }}
will produce:
data:
theData: |
{"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
toml: |
added_prefix.alpha.a0="a0ch0"
added_prefix.beta.beta0.beta00=1234
added_prefix.charlie=["ch0","ch1","ch2"]
added_prefix.problem.beta0.1="1"
added_prefix.problem.beta0.2="2"
and template source for flattenYaml looks like this:
{{- define "flattenYaml" -}}
{{- $dict := . -}}
{{- $prefix := $dict.prefix -}}
{{- $data := $dict.data -}}
{{- $knd := kindOf $data -}}
{{- if eq $knd "map" }}
{{- range (keys $data) }}
{{- $key := . }}
{{- $prefixedKey := (printf "%s.%s" $prefix $key) }}
{{- $value := get $data $key }}
{{- $valueKind := kindOf $value }}
{{- if eq $valueKind "map" }}
{{- include "flattenYaml" (dict "prefix" ($prefixedKey) "data" $value) }}
{{- else }}
{{- printf "%s=%s\n" $prefixedKey (toJson $value) }}
{{- end }}
{{- end }}
{{- else }}
{{ toJson . }}#k({{ $knd }})
{{- end }}
{{- end -}}
disclaimer 2: I have no idea what #k ...
in {{ toJson . }}#k({{ $knd }})
from original solution does, do not be surprised if it explodes into your face
edit:
the
{{ toJson . }}#k({{ $knd }})
actually blew into my face, still don't know what #k should serve, but following replacement fixed my issue:
{{- if ne $data nil }}
{{- toJson $data }}
{{- end }}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论