Python 对比两组 yaml 文件的差异性

需求

需要对比 nacos 两套环境之间的 yaml 文件差异性时,每套环境中有的数个文件,其中文件数量、文件名称、相同文件有不通内容,需要将差异性列出来。

实现方案

方案1:一个一个文件的用本地工具或在线工具进行对比,比如 Beyond Compare、Idea 对比文件

方案2:当多个环境之前,比如开发,测试,仿真,生产 反复多次对比时,方案1的一次性会体现出重复性的工作,所以可以自己写脚本来对比

  • 先读取 yaml 目录,解析 yaml 文件为 json(python 模块 yaml)

  • 通过 json 结构,解析对比不同的属性值(python模块 json_tools:http://www.ibloger.net/article/3518.html)

Snipaste_2022-08-21_11-17-36.jpg

实现代码

# !/usr/bin/env python3
# -*- coding: utf-8 -*-

import os.path
import yaml
import json_tools

"""
json 比较工具

将读取的字符串类型转化为字典或列表,loader可以选择以下几种:
- BaseLoader:仅加载最基本的YAML
- SafeLoader:安全地加载YAML语言的子集。建议用于加载不受信任的输入。(safe_load)
- FullLoader:加载完整的YAML语言。避免任意代码执行。这是当前(PyYAML 5.1)默认加载器调用yaml.load(input)(发出警告后)(full_load)
- UnsafeLoader(也称为Loader向后兼容性):原始的Loader代码,可以通过不受信任的数据输入轻松利用。
"""


def abbr_txt(data):
    if isinstance(data, str) and len(data) > 90:
        return data[:90] + '...';
    else:
        return data


if __name__ == '__main__':
    prefix = 'files/'
    source = 'aaa'
    target = 'bbb'
    f_name_list = os.listdir(prefix + source)
    t_files = os.listdir(prefix + target)
    ignore_files = []
    # ignore_files = ['CAE-AUTHORIZATION.yaml']

    no_yml_file = list()
    s_diff_files = set(f_name_list) - set(t_files)
    if s_diff_files:
        print(target, '不存在的文件', s_diff_files)
    same_files = set(f_name_list) & set(t_files)
    if same_files:
        print(target, '共存的文件', same_files)

    print('\n-----------------------\n')

    for f_name in sorted(same_files):
        if 'yaml' in f_name or 'yml' in f_name:
            if f_name in ignore_files: continue
            s_stream = open(prefix + source + '/' + f_name, mode='r', encoding='utf-8')
            t_stream = open(prefix + target + '/' + f_name, mode='r', encoding='utf-8')
            s_data = yaml.load(s_stream, Loader=yaml.FullLoader)
            t_data = yaml.load(t_stream, Loader=yaml.FullLoader)
            s_stream.close()
            t_stream.close()

            if s_data == t_data:
                # print(f_name, '内容一致')
                pass
            else:
                print('{}内容不一致'.format(f_name))
                s_miss_dict, t_miss_dict = {}, {}
                s_diffKey, t_diffKey = {}, {}
                for diff in json_tools.diff(s_data, t_data):
                    t_missKey = dict(diff).get('remove')
                    s_missKey = dict(diff).get('add')
                    diffKey = dict(diff).get('replace')
                    value = dict(diff).get('value')
                    prev = dict(diff).get('prev')
                    # print(diff)
                    if t_missKey:
                        t_miss_dict[t_missKey] = prev
                    if s_missKey:
                        s_miss_dict[s_missKey] = value
                    if diffKey:
                        s_diffKey[diffKey] = prev
                        t_diffKey[diffKey] = value

                if t_miss_dict:
                    print('\n{} 缺失'.format(target))
                    for k, v in t_miss_dict.items():
                        print('   ', k, '=', v)
                if s_miss_dict:
                    print('\n', source, '缺失')
                    for k, v in s_miss_dict.items():
                        print('   ', k, '=', v)
                if s_diffKey:
                    print('\n属性值不同')
                    for k, v in s_diffKey.items():
                        print(' ', k, '\n    「{} -> {}」:{} -> {}'.format(source, target, abbr_txt(v), abbr_txt(t_diffKey.get(k))))

        else:
            no_yml_file.append(f_name)

    if no_yml_file:
        print('\n非yml文件', no_yml_file)

对比结果

bbb 不存在的文件 {'AFFILIATE-MARKETING.yaml', 'logback.xml', '_legacy_quartz.yaml'}
bbb 共存的文件 {'CAE-GATEWAY.yaml'}

-----------------------

CAE-GATEWAY.yaml内容不一致

bbb 缺失
    /server/connection-timeout = 10000ms
    /spring/cloud/gateway/routes/1 = {'id': 'service', 'uri': 'lb://SERVICE', 'predicates': ['Path=/service/**'], 'filters': ['StripPrefix=1', {'name': 'Retry', 'args': {'retries': 3, 'statuses': ['INTERNAL_SERVER_ERROR'], 'methods': ['GET', 'POST'], 'series': ['SERVER_ERROR']}}]}

 aaa 缺失
    /spring/cloud/gateway/routes/0/filters/1 = {'name': 'Retry', 'args': {'retries': 3, 'statuses': ['INTERNAL_SERVER_ERROR'], 'methods': ['GET', 'POST'], 'series': ['SERVER_ERROR']}}

属性值不同
  /server/tomcat/background-processor-delay 
    「aaa -> bbb」:30s -> 60s
  /spring/cloud/gateway/routes/0/id 
    「aaa -> bbb」:MEMBER-CENTER -> service
  /spring/cloud/gateway/routes/0/uri 
    「aaa -> bbb」:http://MAGIC-MEMBER:8080 -> lb://SERVICE
  /spring/cloud/gateway/routes/0/predicates/0 
    「aaa -> bbb」:Path=/MEMBER-CENTER/** -> Path=/service/**


未经允许请勿转载:程序喵 » Python 对比两组 yaml 文件的差异性

点  赞 (1) 打  赏
分享到: