python - 使用 ruamel.yaml 更新包含多个 yaml 的 yaml 文件中的 yaml block

标签 python yaml

我有一个 yaml 文件,其中包含多个 yaml block 。文件可见here .

基本上,我正在尝试更新文件最后一个 yaml block 中的图像键之一 (ctrl+f blockfreight/go-bftx:) 的值。但是,我想保留有关该文件的所有内容(包括注释),除了我正在更新的一个值。

我有以下代码:

"""
Retrieves a truncated version of the latest git commit sha and updates 
the go-bftx container image tag in app.yaml
"""

import sys
import ruamel.yaml
from subprocess import check_output

yaml_path = 'app.yaml'
for yaml_block in ruamel.yaml.round_trip_load_all(stream=open(yaml_path)):
    pass

# parse the most recent git commit sha from command line
docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 -- pretty=format:%h'.split()).decode()

# update go-bftx image with most recent git-commit-sha tag in the StatefulSet block
yaml_block['spec']['template']['spec']['containers'][1]['image'] = docker_image

ruamel.yaml.round_trip_dump(yaml_block, sys.stdout)

这成功编辑了值,保持注释完整,但仅将最终的 yaml block 发送到 stdout。

有没有办法让我只编辑 app.yaml 中的第六个(也是最后一个)yaml block ,并保持文件的其余部分完整(包括注释)?

我尝试将上面代码中的 pass 替换为 if 语句,该语句将前五个 yaml 发送到 stdout,然后编辑第六个值中的值,将其也发送到 stdout。我的想法是使用 bash 将所有标准输出发送到文件(例如 python app_modifier.py > app1.yaml),但这仅发送第六个 yaml 的输出。

该代码如下所示:

for i, yaml_block in enumerate(ruamel.yaml.round_trip_load_all(stream=open(yaml_path))):
    if i != 5:
        ruamel.yaml.round_trip_dump(yaml_block, sys.stdout)
    else:
        # parse the most recent git commit sha from command line
        docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 --pretty=format:%h'.split()).decode()

        # update go-bftx image with most recent git-commit-sha tag in the StatefulSet blocks
        yaml_block['spec']['template']['spec']['containers'][1]['image'] = docker_image

        ruamel.yaml.round_trip_dump(yaml_block, sys.stdout)

任何帮助将不胜感激!谢谢!

最佳答案

您的文件由多个 YAML 文档组成,这是您使用 round_trip_load_all 读取的内容,它为您提供了一个生成器。

如果您使用 round_trip_dump() 将其写回,您将永远无法获得原始文件中的 --- YAML 文档分隔符。

您可能可以使用生成器和round_trip_dump_all,因为您知道要在哪个文档中进行更改,但制作round_trip_load_all的列表可能更容易 生成并处理它。我还会使用 ruamel.yaml 的新 API 来执行此操作:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = list(yaml.load_all(open('app.yaml')))

# parse the most recent git commit sha from command line
# docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 -- pretty=format:%h'.split()).decode()
docker_image = 'blockfreight/go-bftx:ci-cd-' + 'check_output_output'

# update go-bftx image with most recent git-commit-sha tag in the StatefulSet block
data[-1]['spec']['template']['spec']['containers'][1]['image'] = docker_image

with open('out.yaml', 'w') as ofp:
    yaml.dump_all(data, ofp)

以上大部分有效。 out.yaml diff 包含您想要进行的更改,以及一些空白标准化(缩进,在 [ " 之间),这当然是一次性的。

这种方法有两个主要问题:

  • 文件中的第一个 YAML 文档没有内容,因此它的注释不能卡在任何映射/序列中并且不会被保留
  • 第二个 YAML 文档有一个被删除的最终注释(#//Initializes BFTX Service to Interactive with Endpoints)。这很可能是 ruamel.yaml 中的错误,仅出现在多文档文件中,我必须调查

要解决第一个问题,您只能以普通行的方式读取该文档,而无需 ruamel.yaml。当您这样做时,您不妨完成除其余部分之外的所有操作,因为这也解决(即规避)第二个问题:

import sys
import ruamel.yaml

with open('out.yaml', 'w') as ofp:
    lines = ''
    with open('app.yaml') as ifp:
        for line in ifp:
            lines += line
            if line == '---\n':
                ofp.write(lines)
                lines = ''
    # process lines from the last document
    # print(lines)
    yaml = ruamel.yaml.YAML()
    yaml.preserve_quotes = True
    data = yaml.load(lines)

    # parse the most recent git commit sha from command line
    # docker_image = 'blockfreight/go-bftx:ci-cd-' + check_output('git log -1 -- pretty=format:%h'.split()).decode()
    docker_image = 'blockfreight/go-bftx:ci-cd-' + 'check_output_output'

    # update go-bftx image with most recent git-commit-sha tag in the StatefulSet block
    data['spec']['template']['spec']['containers'][1]['image'] = docker_image

    yaml.dump(data, ofp)

这应该可以满足您的要求,除非您关心流程样式序列中的前导尾随空格,或者保留缩进不一致的三个位置。 diff -u app.yaml out.yaml 的输出:

--- app.yaml    2018-06-23 14:41:02.256290577 +0200
+++ out.yaml    2018-06-23 14:58:09.933991459 +0200
@@ -143,7 +143,7 @@
 spec:
   selector:
     matchLabels:
-       app: bftx
+      app: bftx
   serviceName: blockfreight
   replicas: 1
   template:
@@ -151,7 +151,7 @@
       labels:
         app: bftx
     spec:
-     containers:
+      containers:
       - name: tm
         imagePullPolicy: IfNotPresent
         image: tendermint/tendermint:0.20.0
@@ -199,7 +199,7 @@
           tendermint node --moniker="`hostname`" --p2p.seeds="<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1d7c787c7f7f7b2b7f25242c292e282d2c2e7b2f7c252d2d7b7c24782f2f7c2c29282c7e7c242d7b795d7f7b69652d337f71727e767b6f78747a756933737869" rel="noreferrer noopener nofollow">[email protected]</a>:8888,<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6a5c0f535f5b5f0958090c0f0e5b535e5c5e0f5c090f5b5b080b5858535d0f090e085e5b5b5b5a59082a080c1e125b4408060509010c180f030d021e44040f1e" rel="noreferrer noopener nofollow">[email protected]</a>:8888,<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="791b411b4041414a4e494e414a1b1d491c4c411b1f404b4f1d4f4b48184d4e484f49181f4b1b1d181c391b1f0d014b571b15161a121f0b1c101e110d57171c0d" rel="noreferrer noopener nofollow">[email protected]</a>:8888,<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="86bee5b6bfb7e0b2e3b5e2e5b2e7e5b4b1e2e4b7e3e0e2b5bee4e3e3e3b6b7b4e2bfbfbfb0b1e0e2bec6e4e0f2feb5a8e4eae9e5ede0f4e3efe1eef2a8e8e3f2" rel="noreferrer noopener nofollow">[email protected]</a>:8888" --proxy_app="tcp://localhost:46658" --consensus.create_empty_blocks=false
       - name: app
         imagePullPolicy: Always
-        image: blockfreight/go-bftx:rc1
+        image: blockfreight/go-bftx:ci-cd-check_output_output
         ports:
         - containerPort: 12345
         - containerPort: 46658
@@ -247,7 +247,7 @@
         - mountPath: /etc/nginx/conf.d/pub_key.conf
           name: tmconfigdir
           subPath: pub_key_nginx.conf
-     volumes:
+      volumes:
       - name: tmconfigdir
         configMap:
           name: bftx-config
@@ -262,7 +262,7 @@
       annotations:
         volume.alpha.kubernetes.io/storage-class: anything
     spec:
-      accessModes: [ "ReadWriteOnce" ]
+      accessModes: ["ReadWriteOnce"]
       resources:
         requests:
           storage: 2Gi
@@ -271,7 +271,7 @@
       annotations:
         volume.alpha.kubernetes.io/storage-class: anything
     spec:
-      accessModes: [ "ReadWriteOnce" ]
+      accessModes: ["ReadWriteOnce"]
       resources:
         requests:
           storage: 12Mi

关于python - 使用 ruamel.yaml 更新包含多个 yaml 的 yaml 文件中的 yaml block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50917103/

相关文章:

python - 如何限制创建的Thread对象的数量?

ansible - 如何在 Ansible 中循环库存并分配值(value)

python - 反序列化带有 header 和重复字段的流式 Protocol Buffer 消息

php - 将 YAML 文件转换为 PHP 文件

azure - Azure Pipeline 模板中的动态变量

java - 构建一个包含来自Github的YAML文件的jar文件

python - 如何解析并附加到 flexget yaml 配置文件?

python - 如何在python中随机选择一个文件

python - 代码中的 matplotlib 原始字符串换行符

python - 在 Python 模块中排序