如何在Go模板(Helm)中应用递归格式化?

huangapple go评论112阅读模式
英文:

How do you apply a recursive formatting with Go Templates (Helm)?

问题

我正在使用helm,并给定一个yaml对象,我想要将其展开并应用一些递归格式化。

给定以下内容:

  1. some_map:
  2. with: different
  3. indentation:
  4. levels: and
  5. nested:
  6. sub:
  7. maps: "42"
  8. and_more:
  9. maps: 42

我想要(例如)得到以下结果:

  1. some_map.with="different"
  2. some_map.indentation.levels="and"
  3. some_map.nested.sub.maps="42"
  4. 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:

  1. some_map:
  2. with: different
  3. indentation:
  4. levels: and
  5. nested:
  6. sub:
  7. maps: "42"
  8. and_more:
  9. maps: 42

I want to (for example) get this:

  1. some_map.with="different"
  2. some_map.indentation.levels="and"
  3. some_map.nested.sub.maps="42"
  4. 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 示例:

  1. {{- define "bob" -}}
  2. {{- $it := . -}}
  3. {{- $knd := kindOf . -}}
  4. {{- if eq $knd "map" }}
  5. {{- range (keys .) }}
  6. {{- $k := . }}
  7. {{- $v := get $it . }}
  8. {{- $vk := kindOf $v }}
  9. {{- if eq $vk "map" }}
  10. {{- printf "%s." $k }}
  11. {{- include "bob" $v }}
  12. {{- else }}
  13. {{- printf "%s=%s\n" $k (toJson $v) }}
  14. {{- end }}
  15. {{- end }}
  16. {{- else }}
  17. {{ toJson . }}#k({{ $knd }})
  18. {{- end }}
  19. {{- end -}}

调用方式如下:

  1. {{ $fred := dict
  2. "alpha" (dict "a0" "a0ch0")
  3. "beta" (dict "beta0" (dict "beta00" 1234))
  4. "charlie" (list "ch0" "ch1" "ch2") }}
  5. data:
  6. theData: |
  7. {{ toJson $fred | indent 4 }}
  8. toml: |
  9. {{ include "bob" $fred | indent 4 }}

生成的结果如下:

  1. data:
  2. theData: |
  3. {"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"]}
  4. toml: |
  5. alpha.a0="a0ch0"
  6. beta.beta0.beta00=1234
  7. 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

  1. {{- define "bob" -}}
  2. {{- $it := . -}}
  3. {{- $knd := kindOf . -}}
  4. {{- if eq $knd "map" }}
  5. {{- range (keys .) }}
  6. {{- $k := . }}
  7. {{- $v := get $it . }}
  8. {{- $vk := kindOf $v }}
  9. {{- if eq $vk "map" }}
  10. {{- printf "%s." $k }}
  11. {{- include "bob" $v }}
  12. {{- else }}
  13. {{- printf "%s=%s\n" $k (toJson $v) }}
  14. {{- end }}
  15. {{- end }}
  16. {{- else }}
  17. {{ toJson . }}#k({{ $knd }})
  18. {{- end }}
  19. {{- end -}}

invoked as

  1. {{ $fred := dict
  2. "alpha" (dict "a0" "a0ch0")
  3. "beta" (dict "beta0" (dict "beta00" 1234))
  4. "charlie" (list "ch0" "ch1" "ch2") }}
  5. data:
  6. theData: |
  7. {{ toJson $fred | indent 4 }}
  8. toml: |
  9. {{ include "bob" $fred | indent 4 }}

produced

  1. data:
  2. theData: |
  3. {"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"]}
  4. toml: |
  5. alpha.a0="a0ch0"
  6. beta.beta0.beta00=1234
  7. 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:

  1. {{- define "template.flattenFn" -}}
  2. {{- $ctx := . -}}
  3. {{- if or (eq (kindOf .data) "map") (eq (kindOf .data) "slice") }}
  4. {{- range $key, $value := .data }}
  5. {{- include "template.flattenFn" (dict "prefixes" (append $ctx.prefixes $key) "data" $value ) }}
  6. {{- end }}
  7. {{- else }}
  8. {{- printf "\"%s\":%s, " (join "__" .prefixes) (toJson .data) }}
  9. {{- end }}
  10. {{- end -}}
  11. {{- define "template.flatten" -}}
  12. {{- include "template.flattenFn" (dict "prefixes" list "data" . ) }}
  13. {{- end -}}

values.yaml

  1. environment_map:
  2. Log:
  3. Level:
  4. Default: Debug
  5. Target:
  6. - Name: Console
  7. Args:
  8. formatter: "JsonFormatter"

usage

  1. {{- range $env, $value := include "template.flatten" .Values.environment_map | fromYaml }}
  2. - name: {{ $env }}
  3. value: {{ $value | quote }}

result

  1. - name: Log__Level__Default
  2. value: "Debug"
  3. - name: Log__Target__0__Args__formatter
  4. value: "JsonFormatter"
  5. - name: Log__Target__0__Name
  6. value: "Console"
英文:

another approach

_helpers.tpl:

  1. {{- define "template.flattenFn" -}}
  2. {{- $ctx := . -}}
  3. {{- if or (eq (kindOf .data) "map") (eq (kindOf .data) "slice") }}
  4. {{- range $key, $value := .data }}
  5. {{- include "template.flattenFn" (dict "prefixes" (append $ctx.prefixes $key) "data" $value ) }}
  6. {{- end }}
  7. {{- else }}
  8. {{- printf "\"%s\":%s, " (join "__" .prefixes) (toJson .data) }}
  9. {{- end }}
  10. {{- end -}}
  11. {{- define "template.flatten" -}}
  12. {{- include "template.flattenFn" (dict "prefixes" list "data" . ) }}
  13. {{- end -}}

values.yaml

  1. environment_map:
  2. Log:
  3. Level:
  4. Default: Debug
  5. Target:
  6. - Name: Console
  7. Args:
  8. formatter: "JsonFormatter"

usage

  1. {{- range $env, $value := include "template.flatten" .Values.environment_map | fromYaml }}
  2. - name: {{ $env }}
  3. value: {{ $value | quote }}

result

  1. - name: Log__Level__Default
  2. value: "Debug"
  3. - name: Log__Target__0__Args__formatter
  4. value: "JsonFormatter"
  5. - name: Log__Target__0__Name
  6. value: "Console"

答案3

得分: 0

感谢@mdaniel的答案,它帮助/允许我解决了我的问题!然而,他的(快速,我明白了)解决方案存在问题,如果您具有相同前缀的多个值。继续使用他的示例:

  1. {{ $fred := dict
  2. "alpha" (dict "a0" "a0ch0")
  3. "beta" (dict "beta0" (dict "beta00" 1234))
  4. "charlie" (list "ch0" "ch1" "ch2")
  5. "problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
  6. data:
  7. theData: |
  8. {{ toJson $fred | indent 4 }}
  9. toml: |
  10. {{ include "bob" $fred | indent 4 }}

将产生以下结果:

  1. data:
  2. theData: |
  3. {"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
  4. toml: |
  5. problem.beta0.1="1"
  6. 2="2"
  7. alpha.a0="a0ch0"
  8. beta.beta0.beta00=1234
  9. charlie=["ch0","ch1","ch2"]

这是不正确的。还有另一个问题是顺序丢失的问题,不知道为什么或如何修复它,但这不是很大的问题。

我的额外要求是,我需要在所有行中添加公共前缀。如果没有它,您可以定义另一个模板来简化使用,但这很容易做到。

免责声明:我对helm/go-templating完全不熟悉,所以以下内容可能不是最佳解决方案,但它应该解决这些问题。

继续使用上面的示例:

  1. {{ $fred := dict
  2. "alpha" (dict "a0" "a0ch0")
  3. "beta" (dict "beta0" (dict "beta00" 1234))
  4. "charlie" (list "ch0" "ch1" "ch2")
  5. "problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
  6. data:
  7. theData: |
  8. {{ toJson $fred | indent 4 }}
  9. toml: |
  10. {{ include "flattenYaml" (dict "prefix" "added_prefix" "data" $fred) | indent 4 }}

将产生以下结果:

  1. data:
  2. theData: |
  3. {"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
  4. toml: |
  5. added_prefix.alpha.a0="a0ch0"
  6. added_prefix.beta.beta0.beta00=1234
  7. added_prefix.charlie=["ch0","ch1","ch2"]
  8. added_prefix.problem.beta0.1="1"
  9. added_prefix.problem.beta0.2="2"

flattenYaml模板的源代码如下:

  1. {{- define "flattenYaml" -}}
  2. {{- $dict := . -}}
  3. {{- $prefix := $dict.prefix -}}
  4. {{- $data := $dict.data -}}
  5. {{- $knd := kindOf $data -}}
  6. {{- if eq $knd "map" }}
  7. {{- range (keys $data) }}
  8. {{- $key := . }}
  9. {{- $prefixedKey := (printf "%s.%s" $prefix $key) }}
  10. {{- $value := get $data $key }}
  11. {{- $valueKind := kindOf $value }}
  12. {{- if eq $valueKind "map" }}
  13. {{- include "flattenYaml" (dict "prefix" ($prefixedKey) "data" $value) }}
  14. {{- else }}
  15. {{- printf "%s=%s\n" $prefixedKey (toJson $value) }}
  16. {{- end }}
  17. {{- end }}
  18. {{- else }}
  19. {{ toJson . }}#k({{ $knd }})
  20. {{- end }}
  21. {{- end -}}

免责声明2:我不知道原始解决方案中的#k ...{{ toJson . }}#k({{ $knd }})中是什么意思,如果它在您的面前爆炸了,请不要感到惊讶;)

编辑:
原来的

  1. {{ toJson . }}#k({{ $knd }})

实际上在我的面前爆炸了,我仍然不知道#k应该起什么作用,但以下替换修复了我的问题:

  1. {{- if ne $data nil }}
  2. {{- toJson $data }}
  3. {{- 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:

  1. {{ $fred := dict
  2. "alpha" (dict "a0" "a0ch0")
  3. "beta" (dict "beta0" (dict "beta00" 1234))
  4. "charlie" (list "ch0" "ch1" "ch2")
  5. "problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
  6. data:
  7. theData: |
  8. {{ toJson $fred | indent 4 }}
  9. toml: |
  10. {{ include "bob" $fred | indent 4 }}

will produce:

  1. data:
  2. theData: |
  3. {"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
  4. toml: |
  5. problem.beta0.1="1"
  6. 2="2"
  7. alpha.a0="a0ch0"
  8. beta.beta0.beta00=1234
  9. 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:

  1. {{ $fred := dict
  2. "alpha" (dict "a0" "a0ch0")
  3. "beta" (dict "beta0" (dict "beta00" 1234))
  4. "charlie" (list "ch0" "ch1" "ch2")
  5. "problem" (dict "beta0" (dict "1" "1" "2" "2" )) }}
  6. data:
  7. theData: |
  8. {{ toJson $fred | indent 4 }}
  9. toml: |
  10. {{ include "flattenYaml" (dict "prefix" "added_prefix" "data" $fred) | indent 4 }}

will produce:

  1. data:
  2. theData: |
  3. {"alpha":{"a0":"a0ch0"},"beta":{"beta0":{"beta00":1234}},"charlie":["ch0","ch1","ch2"],"problem":{"beta0":{"1":"1","2":"2"}}}
  4. toml: |
  5. added_prefix.alpha.a0="a0ch0"
  6. added_prefix.beta.beta0.beta00=1234
  7. added_prefix.charlie=["ch0","ch1","ch2"]
  8. added_prefix.problem.beta0.1="1"
  9. added_prefix.problem.beta0.2="2"

and template source for flattenYaml looks like this:

  1. {{- define "flattenYaml" -}}
  2. {{- $dict := . -}}
  3. {{- $prefix := $dict.prefix -}}
  4. {{- $data := $dict.data -}}
  5. {{- $knd := kindOf $data -}}
  6. {{- if eq $knd "map" }}
  7. {{- range (keys $data) }}
  8. {{- $key := . }}
  9. {{- $prefixedKey := (printf "%s.%s" $prefix $key) }}
  10. {{- $value := get $data $key }}
  11. {{- $valueKind := kindOf $value }}
  12. {{- if eq $valueKind "map" }}
  13. {{- include "flattenYaml" (dict "prefix" ($prefixedKey) "data" $value) }}
  14. {{- else }}
  15. {{- printf "%s=%s\n" $prefixedKey (toJson $value) }}
  16. {{- end }}
  17. {{- end }}
  18. {{- else }}
  19. {{ toJson . }}#k({{ $knd }})
  20. {{- end }}
  21. {{- 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 如何在Go模板(Helm)中应用递归格式化?

edit:
the

  1. {{ toJson . }}#k({{ $knd }})

actually blew into my face, still don't know what #k should serve, but following replacement fixed my issue:

  1. {{- if ne $data nil }}
  2. {{- toJson $data }}
  3. {{- end }}

huangapple
  • 本文由 发表于 2022年7月14日 19:36:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/72979870.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定