158 lines
6.1 KiB
Python
158 lines
6.1 KiB
Python
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('<html><head><title>SStar Alkaid Release Flow Status</title><body>')
|
||
f.write(py_trees.display.xhtml_tree(
|
||
behaviour_tree.root,
|
||
show_status=True,
|
||
visited=snapshot_visitor.visited,
|
||
previously_visited=snapshot_visitor.visited
|
||
))
|
||
f.write("</body></html>")
|
||
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()
|