|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import pymysql
|
|
|
|
from update.utils.git_util import GitUtil
|
|
|
|
from dingxin_toolbox_drf.settings import BASE_DIR, CONFIG
|
|
|
|
from update.utils.git_util import GitUtil
|
|
|
|
from env import ENV
|
|
|
|
|
|
|
|
|
|
|
|
class DbCompare:
|
|
|
|
def __init__(self, target_ip, short_release):
|
|
|
|
self.target_server = target_ip
|
|
|
|
self.target_user = 'test'
|
|
|
|
self.target_pwd = 'cine123456'
|
|
|
|
self.target_port = '3306'
|
|
|
|
self.target_release = short_release
|
|
|
|
self.cine_sql_path = os.path.join(BASE_DIR, 'dx', 'sql', GitUtil(short_release).get_db_name() + '.sql')
|
|
|
|
self.diff_sql_path = os.path.join(BASE_DIR, 'dx', 'temp', self.target_server + '_diff.sql')
|
|
|
|
self.clear_diff_sql_path = os.path.join(BASE_DIR, 'dx', 'temp', self.target_server + '_diff_clear.sql')
|
|
|
|
self.create_sql_path = os.path.join(BASE_DIR, 'dx', 'temp', self.target_server + '_create.sql')
|
|
|
|
|
|
|
|
# 生成对比文件
|
|
|
|
def gen_diff_file(self):
|
|
|
|
print('开始生成差异文件')
|
|
|
|
if os.path.exists(self.diff_sql_path):
|
|
|
|
print(f'删除之前生成的差异文件 {self.diff_sql_path}')
|
|
|
|
os.remove(self.diff_sql_path)
|
|
|
|
if os.path.exists(self.diff_sql_path):
|
|
|
|
print('删除失败')
|
|
|
|
print('删除成功')
|
|
|
|
|
|
|
|
# serv_host = '127.0.0.1'
|
|
|
|
# serv_user = 'dingxin'
|
|
|
|
# serv_pwd = 'cine123456'
|
|
|
|
# serv_port = '3306'
|
|
|
|
|
|
|
|
serv_host = CONFIG[ENV]['DB']['HOST']
|
|
|
|
serv_user = CONFIG[ENV]['DB']['USER']
|
|
|
|
serv_pwd = CONFIG[ENV]['DB']['PASSWORD']
|
|
|
|
serv_port = 3309
|
|
|
|
|
|
|
|
server_1 = f'--server1={serv_user}:{serv_pwd}@{serv_host}:{serv_port}'
|
|
|
|
server_2 = f'--server2={self.target_user}:{self.target_pwd}@{self.target_server}:{self.target_port}'
|
|
|
|
|
|
|
|
git_util = GitUtil(self.target_release)
|
|
|
|
db_name = git_util.get_db_name()
|
|
|
|
|
|
|
|
cmd = f'mysqldiff {server_1} {server_2} --changes-for=server2 --difftype=sql --force --quiet --skip-table-options {db_name}:cine > {self.diff_sql_path}'
|
|
|
|
print('执行命令', cmd)
|
|
|
|
|
|
|
|
# result = os.system(cmd)
|
|
|
|
# print('执行返回结果:', result >> 8)
|
|
|
|
|
|
|
|
result = subprocess.getstatusoutput(cmd)
|
|
|
|
if result[0] != 0:
|
|
|
|
print('执行失败:', result[1])
|
|
|
|
print('执行成功:', result[1])
|
|
|
|
|
|
|
|
return self.diff_sql_path
|
|
|
|
|
|
|
|
# 针对降级的情况,需要屏蔽掉语句中的drop语句,此处可能有错误的风险,待验证
|
|
|
|
def remove_drop(self):
|
|
|
|
# 如果清理后的文件存在则删除
|
|
|
|
print('开始处理差异文件,清除Drop命令等')
|
|
|
|
if os.path.exists(self.clear_diff_sql_path):
|
|
|
|
print(f'清理之前生成的文件 {self.clear_diff_sql_path}')
|
|
|
|
os.remove(self.clear_diff_sql_path)
|
|
|
|
if os.path.exists(self.clear_diff_sql_path):
|
|
|
|
print('清理失败')
|
|
|
|
print('清理成功')
|
|
|
|
# 打开生成的差异sql,如果遇到ALTER语句则进入alter模式,将ALTER下面的语句写入temp中,如果是DROP就跳过,当遇到换行时就结束alter模式,把temp写入主列表
|
|
|
|
with open(self.diff_sql_path, 'r', encoding='utf-8') as f:
|
|
|
|
sql_list = []
|
|
|
|
temp = []
|
|
|
|
alter = 0
|
|
|
|
alter_definer = 0
|
|
|
|
for line in f.readlines():
|
|
|
|
if line.strip().startswith('ALTER TABLE'):
|
|
|
|
temp.append(line)
|
|
|
|
alter = 1
|
|
|
|
# elif line.strip().startswith('DROP INDEX'):
|
|
|
|
# pass
|
|
|
|
# elif line.strip().startswith('DROP COLUMN'):
|
|
|
|
# pass
|
|
|
|
elif line.strip().startswith('[PASS]'):
|
|
|
|
pass
|
|
|
|
elif line.strip().startswith('+'):
|
|
|
|
pass
|
|
|
|
elif line.strip().startswith('-'):
|
|
|
|
pass
|
|
|
|
elif line.strip().startswith('@'):
|
|
|
|
pass
|
|
|
|
elif line.strip().startswith('ALTER VIEW'):
|
|
|
|
pass
|
|
|
|
elif line.strip().startswith('('):
|
|
|
|
pass
|
|
|
|
elif line.strip().startswith('ALTER DEFINER'):
|
|
|
|
temp.append(line)
|
|
|
|
alter_definer = 1
|
|
|
|
elif line.strip() == '':
|
|
|
|
if len(temp) > 1 and alter_definer == 0:
|
|
|
|
sql_list.extend(temp)
|
|
|
|
if alter_definer == 1:
|
|
|
|
alter_definer = 0
|
|
|
|
sql_list.extend('\n')
|
|
|
|
temp = []
|
|
|
|
alter = 0
|
|
|
|
else:
|
|
|
|
if alter == 1 or alter_definer == 1:
|
|
|
|
temp.append(line)
|
|
|
|
else:
|
|
|
|
sql_list.append(line)
|
|
|
|
f.close()
|
|
|
|
# 将清洗过的sql列表写入文件
|
|
|
|
with open(self.clear_diff_sql_path, 'w', encoding='utf-8') as f:
|
|
|
|
f.writelines(sql_list)
|
|
|
|
print('生成新的对比文件:', self.clear_diff_sql_path)
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
# 生成新表sql
|
|
|
|
def gen_create_file(self):
|
|
|
|
# 如果有已生成的文件则删除
|
|
|
|
print('开始生成创建文件')
|
|
|
|
if os.path.exists(self.create_sql_path):
|
|
|
|
print(f'清理之前生成的文件 {self.create_sql_path}')
|
|
|
|
os.remove(self.create_sql_path)
|
|
|
|
if os.path.exists(self.create_sql_path):
|
|
|
|
print('清除失败')
|
|
|
|
print('清除成功')
|
|
|
|
# 在生成的差异文件中查找原始版本没有,目标版本中存在的表明
|
|
|
|
create_sql_list = []
|
|
|
|
with open(self.diff_sql_path, 'r', encoding='utf-8') as f:
|
|
|
|
for line in f.readlines():
|
|
|
|
if line.startswith('# TABLE'):
|
|
|
|
create_sql_list.append(line.split(':')[1].strip())
|
|
|
|
f.close()
|
|
|
|
# 通过上步中找到的表名,在目标版本的cine.sql中查找创建表的sql语句,并组成sql语句列表
|
|
|
|
create_table_sql_list = ['USE `cine`;\n\n']
|
|
|
|
with open(self.cine_sql_path, 'r', encoding='utf-8') as f:
|
|
|
|
content = f.read()
|
|
|
|
for sql in content.split(';\n'):
|
|
|
|
for table in create_sql_list:
|
|
|
|
if f'CREATE TABLE `{table}`' in sql:
|
|
|
|
create_table_sql_list.append(sql + ';\n\n')
|
|
|
|
f.close()
|
|
|
|
# 将上步中的sql语句列表些入create.sql文件中
|
|
|
|
with open(self.create_sql_path, 'w', encoding='utf-8') as f:
|
|
|
|
f.writelines(create_table_sql_list)
|
|
|
|
print('生成新的创建文件:', self.create_sql_path)
|
|
|
|
f.close()
|
|
|
|
return self.create_sql_path
|
|
|
|
|
|
|
|
# 执行差异
|
|
|
|
def exec_diff_sql(self):
|
|
|
|
self.gen_diff_file()
|
|
|
|
self.remove_drop()
|
|
|
|
self.gen_create_file()
|
|
|
|
diff_cmd = f'mysql -h{self.target_server} -P{self.target_port} -u{self.target_user} -p{self.target_pwd} < {self.clear_diff_sql_path}'
|
|
|
|
create_cmd = f'mysql -h{self.target_server} -P{self.target_port} -u{self.target_user} -p{self.target_pwd} < {self.create_sql_path}'
|
|
|
|
print('执行命令:', diff_cmd)
|
|
|
|
# diff_result = os.system(diff_cmd)
|
|
|
|
# print('diff_result', diff_result)
|
|
|
|
diff_result = subprocess.getstatusoutput(diff_cmd)
|
|
|
|
if diff_result[0] != 0:
|
|
|
|
print('执行失败:', diff_result[1])
|
|
|
|
print('执行成功:', diff_result[1])
|
|
|
|
|
|
|
|
print('执行命令:', create_cmd)
|
|
|
|
# create_result = os.system(create_cmd)
|
|
|
|
# print('create_result', create_result)
|
|
|
|
create_result = subprocess.getstatusoutput(create_cmd)
|
|
|
|
if create_result[0] != 0:
|
|
|
|
print('执行失败:', create_result[1])
|
|
|
|
print('执行成功:', create_result[1])
|
|
|
|
|
|
|
|
return '数据库对比成功' if diff_result[0] == 0 and create_result[0] == 0 else '数据库对比失败' + diff_result[
|
|
|
|
1] + create_result[1]
|