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