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()