add:初始化工程

This commit is contained in:
drygrass
2025-10-18 21:32:31 +08:00
parent f55b636faa
commit e1b57847f9
48 changed files with 67186 additions and 0 deletions

416
uf30_buildMap_class.py Normal file
View File

@@ -0,0 +1,416 @@
import os
import public
import re
import json
from datetime import datetime
from collections import defaultdict
# 定义一个类用用来生成函数调用关系
class BuildMap:
def __init__(self, projectPath='F:\\sesCode\\',
# subProject=["upub", "uconvert", "umgr", "uqms", "ucbp", "uses", "ucrt"],
subProject=["umgr","uses", "ucrt", "ucbp", "uconvert", "uqms", "upub"],
uftatom="\\dev_codes\\uftatom",
uftbusiness="\\dev_codes\\uftbusiness",
extend_name=['uftservice', 'uftfunction', 'uftatomfunction', 'uftatomservice', 'extinterface'],
model_flag=1):
self.projectPath = projectPath # 工程目录地址
self.subProject = subProject
self.uftatom = uftatom
self.uftbusiness = uftbusiness
self.search_direction = 0 # 搜索方向默认为0 0 正向搜索 1反向搜索
self.model_flag = model_flag # 查询模式 0:默认 只显示搜到关键字的函数调用信息 1显示全部调用路径
self.extend = extend_name # 遍历的文件后缀名称
# find_function, find_txt, gene_file, model_flag, project='uses'
self.find_function = []
self.find_txt = ''
self.gene_file = 'UF30函数调用图.txt'
self.project = 'uses'
# 定义全局变量,用来保存函数信息
# 核心数据结构
# key:name value:self.FunctionInfo
self.function_map = {}
# 定义变量保存id和Chinese_name
# key:id value:name
self.id_name = {}
self.debug = 0
def set_project(self, project):
self.project = project
def set_project_path(self, projectPath):
self.projectPath = projectPath
def set_search_direction(self, search_direction):
# 获取当前时间并格式化
# current_time = datetime.now().strftime("%Y%m%d_%H%M%S") # 格式化为年月日_时分秒
self.search_direction = search_direction
# if search_direction == 0:
# self.set_gene_file(f'{self.find_function[0]}-函数调用图_{current_time}.txt')
# else:
# self.set_gene_file(f'{self.find_function[0]}-函数被调用图_{current_time}.txt')
def set_find_function(self, find_function):
self.find_function = find_function
def set_find_txt(self, find_txt):
self.find_txt = find_txt
def set_gene_file(self, gene_file):
self.gene_file = gene_file
# 用来存储函数信息
class FunctionInfo:
def __init__(self, name, id, path, pre_ids=None, next_ids=None):
self.name = name
self.id = id
self.path = path
self.pre_ids = pre_ids if pre_ids is not None else [] # 确保默认为空列表
self.next_ids = next_ids if next_ids is not None else [] # 确保默认为空列表
# 1.0 保存单个函数的信息,生成全图函数信息时使用
# 遍历目录,将函数对应中文名称,功能号,函数路径,提取出来;
# 先以"key":"value"形式保存到functions_map 和 id_name 里面
# 同时将其 记录到 sub_project + ".txt" 文件中 比如umgr.txt upbu.txt
def traverse_directory(self, dir_path, sub_project, functions_map, id_name):
# 获取当前目录下的所有文件和目录
# print('fir_path:', dir_path)
if os.path.exists(dir_path):
entries = os.scandir(dir_path)
for entry in entries:
# 拼接完整的文件或目录路径
full_path = os.path.join(dir_path, entry.name)
if entry.is_file():
file_ext = public.extract_file_extension(full_path)
if file_ext in self.extend:
# print(full_path)
# 读取第二行内容
temp_text = public.read_second_line(full_path)
# print(temp_text)
# 提取名称功能号
matches = public.extract_name_functionNo(temp_text)
if matches is None:
continue
chinese_name = matches[0]
object_id = matches[1]
if chinese_name is None:
continue
# print(f"chineseName: {chinese_name}")
# print(f"objectId: {object_id}")
if object_id not in id_name:
id_name[object_id] = chinese_name
# 确保name的唯一性
if chinese_name in functions_map:
# print(full_path)
# print(temp_text)
# print(f"Function name '{chinese_name}' is not unique.")
pass
# raise ValueError(f"Function name '{chinese_name}' is not unique.")
else:
new_func = self.FunctionInfo(chinese_name, object_id, full_path)
functions_map[chinese_name] = new_func
if self.debug == 1:
file_name = sub_project + ".txt"
with open(file_name, 'a', encoding='utf-8') as file:
file.write(f"\"function_id\":\"{object_id}\",")
file.write(f"\"chinese_name\":\"{chinese_name}\",")
file.write(f"\"full_path\":\"{full_path}\"\n")
# print(new_func)
elif entry.is_dir():
# 如果是目录,则递归调用本函数
self.traverse_directory(full_path, sub_project, functions_map, id_name)
# 1.1 遍历所有函数字典然后合并函数字典信息
def traverse_all(self):
projectPath = self.projectPath
subProject = self.subProject
find_function = self.find_function
find_txt = self.find_txt
gene_file = self.gene_file
model_flag = self.model_flag
project = self.project
if find_txt == '' or find_txt == None:
model_flag = 1
# 20250823 fix 优化生成函数关系图写法使用for循环扫描每个代码库
for model in subProject:
id_name = {}
func_map = {}
self.traverse_directory(projectPath + model, model, func_map, id_name)
self.function_map.update(func_map)
self.id_name.update(id_name)
# 再使用inner覆盖一下
inner_id_name = {}
inner_func_map = {}
if 'uses' in self.subProject:
# 再使用inner覆盖一下
self.traverse_directory(projectPath + 'uses' + '\\dev_codes\\uftbusiness\\inner', 'uses',
inner_func_map, inner_id_name)
if 'ucrt' in self.subProject:
innercrt_id_name = {}
innercrt_func_map = {}
self.traverse_directory(projectPath + 'ucrt' + '\\dev_codes\\uftbusiness\\inner', 'ucrt',
inner_func_map,
inner_id_name)
self.function_map.update(inner_func_map)
self.id_name.update(inner_id_name)
# 工具函数
# 将函数信息 字典内容 保存到txt中 file_name = "函数拓扑关系图.txt"
def save_map_totxt(self, func_map, file_name='函数拓扑关系图.txt'):
for name in func_map:
func = func_map[name]
with open(file_name, 'a', encoding='utf-8') as file:
file.write(f"\"function_id\":\"{func.id}\",")
file.write(f"\"chinese_name\":\"{func.name}\",")
file.write(f"\"full_path\":\"{func.path}\",")
file.write(f"\"pre_ids\":\"{func.pre_ids}\",")
file.write(f"\"next_ids\":\"{func.next_ids}\"\n")
# 2.扫描函数字典 根据函数信息 生成函数关系图,拓扑图
def scanl_func(self):
gene_file = self.gene_file
func_map = self.function_map
# 开始遍历功能号,逐行扫描文件内容 添加父子函数id 先搞uses的暂不支持跨模块查找
for c_name in func_map:
# print(c_name)
c_func = func_map[c_name]
c_id = c_func.id
full_path = c_func.path
if not os.path.exists(full_path):
print('full_path notexists:', full_path)
continue
# 使用with语句确保文件正确关闭
with open(full_path, 'r', encoding='utf-8') as file:
# 逐行读取文件
for line in file:
# 提取函数名称
sub_func_name = public.match_func_name(line)
# 过滤掉不存在的函数
if sub_func_name == "None" or sub_func_name == "":
continue
if sub_func_name not in func_map:
continue
# 提取函数对应的功能号
sub_func = func_map[sub_func_name]
fub_func_id = sub_func.id
if fub_func_id not in c_func.next_ids:
c_func.next_ids.append(fub_func_id)
# 添加完子节点后,再反过来添加父节点
if c_id not in sub_func.pre_ids:
sub_func.pre_ids.append(c_id)
with open('UF30函数关系图.txt', 'w', encoding='utf-8') as file:
pass # 文件内容被清空pass语句在这里不执行任何操作
# 建图完毕将其保存到test.txt文件中
self.save_map_totxt(func_map, "UF30函数关系图.txt")
# 使用 'w' 模式打开文件,这会清空文件内容
with open(gene_file, 'w', encoding='utf-8') as file:
pass # 文件内容被清空pass语句在这里不执行任何操作
# 生成函数调用图
# self.geneAllFucn2(find_function, func_map, id_name, "", gene_file, find_txt, model_flag, 0)
# if self.debug:
# print('生成完成')
# 3.生成函数调用或者被调用图
# 直接for循环遍历 扫描生成函数调用图 或者被调用图
def geneAllFucn2(self,find_function, tab='', call_path="\t\t【Start"):
func_map = self.function_map
id_name = self.id_name
projectPath = self.projectPath
subProject = self.subProject
# find_function = self.find_function
find_txt = self.find_txt
gene_file = self.gene_file
model_flag = self.model_flag
# print('model_flag', model_flag)
project = self.project
file_name = self.gene_file
count = 0
# call_path = "\t\t【Start"
find_flag = 0
for func_id in find_function:
if func_id not in id_name:
print(f"Not this function_id:{func_id}")
else:
index = find_function.index(func_id)
# 函数名称提取出来
func_name = id_name[func_id]
if '融资融券' in func_name:
continue
func_path = func_map[func_name].path
if find_txt != "":
with open(file_name, 'r', encoding='utf-8') as file1:
if public.check_string_in_file(func_path, find_txt):
find_flag = 1
with open(file_name, 'a', encoding='utf-8') as file:
if find_flag == 1:
file.write(tab + func_id + ":" + func_name + "\t\t" + find_txt + call_path + "->" + str(
func_id) + "\n")
elif model_flag == 1:
if (self.search_direction == 1 and 'LS' in func_name and '内部远程调用' not in func_name) or call_path == "\t\t【Start":
file.write(tab + func_id + ":" + func_name + "\n")
elif self.search_direction == 0:
file.write(tab + func_id + ":" + func_name + "\n")
find_flag = 0
# 提取 next_ids 此处可以设置函数调用图或者函数被调用图
next_ids = func_map[func_name].next_ids
pre_ids = func_map[func_name].pre_ids
if self.search_direction == 1:
# 如果标志为1 代表搜索反向调用图
next_ids = pre_ids
if len(next_ids) > 0:
self.geneAllFucn2(next_ids, '\t' + tab, call_path + "->" + str(func_id))
def loadInfoFromTxt(self):
# 读取并处理文件
with open('UF30函数关系图.txt', 'r', encoding='utf-8') as file:
for line in file:
line = line.strip()
if not line:
continue
# 使用正则表达式解析键值对
data = {}
pattern = r'"([^"]+)":"(.*?)"(?=,|$)'
matches = re.findall(pattern, line)
for key, value in matches:
# 处理列表类型的字段pre_ids/next_ids
if key in ['pre_ids', 'next_ids']:
# 将字符串列表转换为实际列表
value = value.replace("'", '"') # 替换单引号为双引号
try:
data[key] = json.loads(value)
except json.JSONDecodeError:
data[key] = []
else:
data[key] = value
# 确保所有必要字段都存在
required_fields = ['function_id', 'chinese_name', 'full_path']
if all(field in data for field in required_fields):
# 创建FunctionInfo对象
func_info = self.FunctionInfo(
name=data['chinese_name'],
id=data['function_id'],
path=data['full_path'],
pre_ids=data.get('pre_ids', []),
next_ids=data.get('next_ids', [])
)
# 更新function_map
self.function_map[func_info.name] = func_info
# 更新id_name
self.id_name[func_info.id] = func_info.name
def update_func_map(self):
# 1.遍历所有文件 生成每个库的函数字典 然后合并数据字典
self.traverse_all()
# 2.扫描函数字典 生成函数关系拓扑图
self.scanl_func()
# 初始化函数关系图到字典中
def init_func_call_map(self, forceUpdate=False):
# self.set_project(project)
# self.set_find_function(find_function)
# self.set_find_txt(find_txt)
# self.set_search_direction(search_direction)
# if find_txt:
# # 查询模式 0: 只显示搜到关键字的函数调用信息 1显示全部调用路径
# self.model_flag = 0
# if gene_file:
# self.set_gene_file(gene_file)
# build.set_gene_file('函数调用图2-1.txt')
if os.path.exists('UF30函数关系图.txt') and forceUpdate == False:
# 从文件中加载配置
self.loadInfoFromTxt()
else:
# print('111')
# 1.遍历所有文件 生成每个库的函数字典 然后合并数据字典
self.traverse_all()
# print('222')
# 2.扫描函数字典 生成函数关系拓扑图
self.scanl_func()
# 20250712 add 合并远程调用的和外部接口的 函数字典信息 pre_id和next_id解决部分函数反向调用无法穿透问题
self.merge_func_info()
def gene_func_call_map(self, find_function, find_txt, search_direction=0, project='uses', gene_file=''):
self.set_project(project)
self.set_find_function(find_function)
self.set_find_txt(find_txt)
self.set_search_direction(search_direction)
print('find_txt', find_txt)
if find_txt == ' ' or find_txt == None or find_txt == '':
# 查询模式 0: 只显示搜到关键字的函数调用信息 1显示全部调用路径
self.set_find_txt("")
self.model_flag = 1
else:
self.model_flag = 0
if gene_file:
self.set_gene_file(gene_file)
# 每次生成调用图之前,先清空文件
with open(self.gene_file, 'w', encoding='utf-8') as file:
pass # 文件内容被清空pass语句在这里不执行任何操作
# build.set_gene_file('函数调用图2-1.txt')
# # 1.遍历所有文件 生成每个库的函数字典 然后合并数据字典
# self.traverse_all()
# # 2.扫描函数字典 生成函数关系拓扑图
# self.scanl_func()
# 3.根据函数关系拓扑图 生成函数调用图/被调用图
self.geneAllFucn2(find_function)
# print('生成完成')
if self.debug:
print('生成完成')
# 20250712 add 添加函数用来合并远程调用函数的pre_id和next_id解决部分函数反向调用无法穿透问题
def merge_func_info(self):
# 更新function_map
# self.function_map[func_info.name] = func_info
# 1. 按 id 收集所有的 pre_ids 和 next_ids
id_to_combined = defaultdict(lambda: {"pre_ids": set(), "next_ids": set()})
for func in self.function_map.values():
id_to_combined[func.id]["pre_ids"].update(func.pre_ids)
id_to_combined[func.id]["next_ids"].update(func.next_ids)
# 2. 更新每一个 FunctionInfo 对象的 pre_ids 和 next_ids
for key in self.function_map:
if '远程调用' in key or '外部接口' in key:
func = self.function_map[key]
combined = id_to_combined.get(func.id, {"pre_ids": [], "next_ids": []})
# 转回 list 并排序(可选)
func.pre_ids = list(combined["pre_ids"])
func.next_ids = list(combined["next_ids"])
# 遍历所有目录
def main():
build = BuildMap()
build.init_func_call_map()
build.gene_func_call_map(['332648'], 'trade_handling_instr', search_direction=0, project='ucbp', gene_file='')
if __name__ == '__main__':
# 1.记录每个文件自己的信息,功能号,中英文名称
# 2.生成函数关系拓扑图
# 3.根据生成的函数关系图,来进行搜索之类的操作
main()