例如我想合并下面的两个模板,
# v1
instance_db_address: {{ .MYSQL_ADDRESS }}
instance_db_port: {{ .MYSQL_PORT }}
imagePullSecrets: {{ .IMAGE_PULL_SECRET }}
resources:
requests:
memory: "1Gi"
cpu: "512m"
limits:
memory: "1Gi"
cpu: "1000m"
# v2
instance_db_address: {{ .MYSQL_ADDRESS2 }}
instance_db_port: {{ .MYSQL_PORT2 }}
答案应该是
instance_db_address: {{ .MYSQL_ADDRESS2 }}
instance_db_port: {{ .MYSQL_PORT2 }}
imagePullSecrets: {{ .IMAGE_PULL_SECRET }}
resources:
requests:
memory: "1Gi"
cpu: "512m"
limits:
memory: "1Gi"
cpu: "1000m"
我发现很难合并,因为这些不是 yaml,有人可以帮助我吗?
我尝试在每行的大括号中添加一些引号,但我想保留大括号而不使用引号。所以效果不太好。
假设您正在使用
text/template
来处理这些模板,您可以(并且应该)合并所谓的“解析树”——这是模板被解析成的内容(实际上是 Execute
d),而不是模板的源文本。
实现此目的的一种方法:
package main
import (
"errors"
"fmt"
"log"
"os"
"strings"
"text/template"
"text/template/parse"
)
const t1Text = `instance_db_address: {{ .MYSQL_ADDRESS }}
instance_db_port: {{ .MYSQL_PORT }}
imagePullSecrets: {{ .IMAGE_PULL_SECRET }}
resources:
requests:
memory: "1Gi"
cpu: "512m"
limits:
memory: "1Gi"
cpu: "1000m"
`
const t2Text = `instance_db_address: {{ .MYSQL_ADDRESS2 }}
instance_db_port: {{ .MYSQL_PORT2 }}
`
func merge(dst, src *template.Template) error {
dstNodes := dst.Tree.Root.Nodes
a1, p1, err := findAddrAndPortNodes(dstNodes)
if err != nil {
return err
}
srcNodes := src.Tree.Root.Nodes
a2, p2, err := findAddrAndPortNodes(srcNodes)
if err != nil {
return err
}
dstNodes[a1] = srcNodes[a2]
dstNodes[p1] = srcNodes[p2]
return nil
}
func findAddrAndPortNodes(nodes []parse.Node) (
addrIndex int, portIndex int, err error) {
type curNode struct {
text string
nodeIndexPtr *int
}
const (
modeText = iota
modeAction
)
toLocate := map[string]*int{
"instance_db_address:": &addrIndex,
"instance_db_port:": &portIndex,
}
var cur curNode
mode := modeText
NODE_LOOP:
for ix, n := range nodes {
switch mode {
case modeText:
tn, ok := n.(*parse.TextNode)
if !ok {
continue
}
nodeText := strings.TrimSpace(string(tn.Text))
for text, dst := range toLocate {
if nodeText != text {
continue
}
cur.text = text
cur.nodeIndexPtr = dst
mode = modeAction
continue NODE_LOOP
}
case modeAction:
_, ok := n.(*parse.ActionNode)
if !ok {
return 0, 0, fmt.Errorf(
"unexpected node type: %T for %q", n, cur.text)
}
*cur.nodeIndexPtr = ix
delete(toLocate, cur.text)
if len(toLocate) == 0 {
break NODE_LOOP
}
mode = modeText
continue
}
}
if len(toLocate) != 0 {
return 0, 0, errors.New("failed to locate all nodes")
}
return
}
func main() {
t1 := template.New("v1")
t1, err := t1.Parse(t1Text)
if err != nil {
log.Fatalln("failed to parse 1st template:", err)
}
t2 := template.New("v2")
t2, err = t2.Parse(t2Text)
if err != nil {
log.Fatalln("failed to parse 2nd template:", err)
}
ctx := map[string]string{
"IMAGE_PULL_SECRET": "whatever",
"MYSQL_ADDRESS": "orig_addr",
"MYSQL_PORT": "orig_port",
"MYSQL_ADDRESS2": "new_addr",
"MYSQL_PORT2": "new_port",
}
err = t1.Execute(os.Stdout, ctx)
if err != nil {
log.Fatalln("failed to execute 1st template:", err)
}
fmt.Println(strings.Repeat("-", 80))
err = merge(t1, t2)
if err != nil {
log.Fatalln("failed to merge:", err)
}
err = t1.Execute(os.Stdout, ctx)
if err != nil {
log.Fatal("failed to execute modified template:", err)
}
}
运行时,该程序会生成:
instance_db_address: orig_addr
instance_db_port: orig_port
imagePullSecrets: whatever
resources:
requests:
memory: "1Gi"
cpu: "512m"
limits:
memory: "1Gi"
cpu: "1000m"
--------------------------------------------------------------------------------
instance_db_address: new_addr
instance_db_port: new_port
imagePullSecrets: whatever
resources:
requests:
memory: "1Gi"
cpu: "512m"
limits:
memory: "1Gi"
cpu: "1000m"
这意味着两个兴趣点的动作实际上在原始模板中发生了变化。
游乐场。
template.Template
的定义开始。