import functools import os,sys import threading sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) import thirdparty.py_trees as py_trees from thirdparty.py_trees.trees import BehaviourTree from core.behavior_tree import ReleaseFlowBuilder from core.plugin import PluginManager from core.defines import ReleasePhase, ProcessStep, ReleaseErr, Dict from database import * import core.logger as logger log = logger.get_logger() def draw_release_flow_status(snapshot_visitor, behaviour_tree): """保存行为树状态为HTML文件""" mutex = threading.Lock() with mutex: # timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"alkaid_release_flow_status.html" with open(filename, 'w') as f: f.write('SStar Alkaid Release Flow Status') f.write(py_trees.display.xhtml_tree( behaviour_tree.root, show_status=True, visited=snapshot_visitor.visited, previously_visited=snapshot_visitor.visited )) f.write("") filename = f"alkaid_release_flow_status.dot" with open(filename, 'w') as f: f.write(str(py_trees.display.dot_tree(behaviour_tree.root, with_blackboard_variables=True))) # log.info(f"Behavior tree saved to {filename}") # 构建环境阶段 (验证配置、拉取code等基础环境的准备) def _construct_env_phase(builder: ReleaseFlowBuilder, plugins: PluginManager): with builder.sequence(ReleasePhase.ENV): with builder.sequence(ProcessStep.PRE): pass with builder.sequence(ProcessStep.PROCESS): if not ReleaseOptions.SkipSyncCode: builder.action(plugins.BaseLine.PhaseEnv.Process()) with builder.sequence(ProcessStep.POST): pass # 配置编译文件阶段 (defconfig mkfile 等编译控制文件的配置) def _construct_config_phase(builder: ReleaseFlowBuilder, plugins: PluginManager): with builder.sequence(ReleasePhase.CONFIG): with builder.sequence(ProcessStep.PRE): pass with builder.sequence(ProcessStep.PROCESS): pass with builder.sequence(ProcessStep.POST): pass # 构建阶段(编译构建sdk,根据上一步的配置执行编译构建) def _construct_build_phase(builder: ReleaseFlowBuilder, plugins: PluginManager): with builder.sequence(ReleasePhase.BUILD): with builder.sequence(ProcessStep.PRE): pass with builder.sequence(ProcessStep.PROCESS): pass with builder.sequence(ProcessStep.POST): pass # 检查阶段(检查SDK编译结果是否符合预期) def _construct_check_phase(builder: ReleaseFlowBuilder, plugins: PluginManager): with builder.sequence(ReleasePhase.CHECK): with builder.sequence(ProcessStep.PRE): pass with builder.sequence(ProcessStep.PROCESS): pass with builder.sequence(ProcessStep.POST): pass # 打包阶段 (将SDK其他文件诸如doc,tool等打包) def _construct_package_phase(builder: ReleaseFlowBuilder, plugins: PluginManager): with builder.sequence(ReleasePhase.PACKAGE): with builder.sequence(ProcessStep.PRE): pass with builder.sequence(ProcessStep.PROCESS): pass with builder.sequence(ProcessStep.POST): pass # 验证阶段 (验证Release的SDK是否可以正常工作) def _construct_verify_phase(builder: ReleaseFlowBuilder, plugins: PluginManager): with builder.sequence(ReleasePhase.VERIFY): with builder.sequence(ProcessStep.PRE): pass with builder.sequence(ProcessStep.PROCESS): pass with builder.sequence(ProcessStep.POST): pass class ReleaseFlow(): def __init__(self): # 我们的Flow默认是一个串行的流程,所以根节点用Sequence self.builder = ReleaseFlowBuilder() self.tree = None self.flow = None self.timer = None self.status_update_interval = 1 # 定时器间隔时间,单位秒 self.running = False # 构建 Alkaid Release流程 def construct(self, plugins: PluginManager): with self.builder.sequence("AlkaidReleaseFlow") as builder: _construct_env_phase(builder, plugins) _construct_config_phase(builder, plugins) _construct_build_phase(builder, plugins) _construct_check_phase(builder, plugins) _construct_package_phase(builder, plugins) _construct_verify_phase(builder, plugins) self.flow = self.builder.build() def _start_update_status(self, snapshot_visitor): """启动定时器""" if self.timer is not None: return def timer_callback(): if self.tree is not None: draw_release_flow_status(snapshot_visitor, self.tree) # 重新设置定时器 self.timer = threading.Timer(self.status_update_interval, timer_callback) self.timer.start() # 启动第一个定时器 self.timer = threading.Timer(self.status_update_interval, timer_callback) self.tree.add_post_tick_handler(functools.partial(draw_release_flow_status, snapshot_visitor)) self.timer.start() # 运行Release 流程 def run(self): if self.flow is None: raise ReleaseErr("Flow is not built") # 使用封装好的BehaviourTree去管理流程 self.tree = BehaviourTree(root=self.flow) snapshot_visitor = py_trees.visitors.SnapshotVisitor() self.tree.visitors.append(snapshot_visitor) self.tree.setup() # 初始化树 # 启动定时器 self._start_update_status(snapshot_visitor) # print( # py_trees.display.dot_tree( # self.tree.root # ) # ) self.tree.tick() # 触发tick进行执行 return self.tree.root.status def shutdown(self): if self.timer is not None: self.timer.cancel() self.timer = None if self.tree is not None: self.tree.shutdown()