需求
需要对比 nacos 两套环境之间的 yaml 文件差异性时,每套环境中有的数个文件,其中文件数量、文件名称、相同文件有不通内容,需要将差异性列出来。
实现方案
方案1:一个一个文件的用本地工具或在线工具进行对比,比如 Beyond Compare、Idea 对比文件
方案2:当多个环境之前,比如开发,测试,仿真,生产 反复多次对比时,方案1的一次性会体现出重复性的工作,所以可以自己写脚本来对比
先读取 yaml 目录,解析 yaml 文件为 json(python 模块 yaml)
通过 json 结构,解析对比不同的属性值(python模块 json_tools:http://www.ibloger.net/article/3518.html)
实现代码
# !/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 文件的差异性
程序喵