diff --git a/src/config.py b/src/config.py index 0d2ddbd..16510ce 100644 --- a/src/config.py +++ b/src/config.py @@ -47,7 +47,7 @@ } RUN_LOG_SIZE_LIMIT = 5 * 1024 * 1024 # 5MB - +SEND_MAIL_URL = 'maksyuki@qq.com' def exec_cmd(cmd: str) -> str: try: diff --git a/src/config_parser.py b/src/config_parser.py index ba42ebb..ad38a04 100644 --- a/src/config_parser.py +++ b/src/config_parser.py @@ -4,24 +4,25 @@ from typing import Any, Dict, Tuple, List import tomli import config -from data_type import DUTConfig, IverilogConfig -from data_type import VerilatorConfig, VCSConfig -from data_type import DCConfig, SubmitConfig +from data_type import MetaConfig, DUTConfig +from data_type import IverilogConfig, VerilatorConfig +from data_type import VCSConfig, DCConfig, SubmitConfig class ConfigParser(object): def __init__(self): + self.def_meta = MetaConfig('', '', '', ('', 'off')) self.def_dut = DUTConfig('', '', '', '', '') self.def_iv = IverilogConfig('') self.def_ver = VerilatorConfig('') self.def_vcs = VCSConfig(25, ('', ''), False) self.def_dc = DCConfig('', 100, 'TYP', '', '', False, '') - self.sub_cfg = SubmitConfig(self.def_dut, self.def_iv, self.def_ver, - self.def_vcs, self.def_dc) + self.sub_cfg = SubmitConfig(self.def_meta, self.def_dut, self.def_iv, + self.def_ver, self.def_vcs, self.def_dc) def clear(self): - self.sub_cfg = SubmitConfig(self.def_dut, self.def_iv, self.def_ver, - self.def_vcs, self.def_dc) + self.sub_cfg = SubmitConfig(self.def_meta, self.def_dut, self.def_iv, + self.def_ver, self.def_vcs, self.def_dc) def check_item(self, item: str, cfg_list: Dict[str, Any], option_list: List[str]) -> Tuple[bool, str, str]: @@ -35,6 +36,35 @@ def check_item(self, item: str, cfg_list: Dict[str, Any], return (False, f'{item} cfg item value is wrong', '') + #NOTE: no check the code + def check_proj_auth_ver(self, cfg_list: Dict[str, + Any]) -> Tuple[bool, str]: + if cfg_list.get('project') is not None: + self.sub_cfg.meta_cfg.proj = cfg_list['project'] + + if cfg_list.get('author') is not None: + self.sub_cfg.meta_cfg.auth = cfg_list['author'] + + if cfg_list.get('version') is not None: + self.sub_cfg.meta_cfg.ver = cfg_list['version'] + + return (True, 'proj, auth and ver check done with no error') + + #NOTE: no check the code + def check_notif(self, cfg_list: Dict[str, Any]) -> Tuple[bool, str]: + if cfg_list.get('notif') is not None: + (notif_mail, notif_ena) = cfg_list['notif'] + if notif_ena != 'off' and notif_ena != 'on': + return (False, 'notif ena item value is wrong') + + # HACK: add more detailed check function + if not '@' in notif_mail: + return (False, 'notif mail item value is wrong') + + self.sub_cfg.meta_cfg.notif = cfg_list['notif'] + + return (True, 'notif check done with no error') + def check_arch(self, cfg_list: Dict[str, Any]) -> Tuple[bool, str]: option_list = ['rv32e', 'rv32i', 'rv32im', 'rv64i', 'rv64im'] (ck_state, ck_info, ck_val) = self.check_item('arch', cfg_list, @@ -172,6 +202,12 @@ def check_commit(self, cfg_list: Dict[str, Any]) -> Tuple[bool, str]: self.sub_cfg.dut_cfg.commit = ck_val return (ck_state, ck_info) + def check_meta(self, cfg_list: Dict[str, Any]) -> Tuple[bool, str]: + if cfg_list.get('meta') is None: + return (False, 'dont have meta cfg table') + + return (True, 'check meta cfg table done with no error') + def check_dut(self, cfg_list: Dict[str, Any]) -> Tuple[bool, str]: if cfg_list.get('dut') is None: return (False, 'dont have dut cfg table') @@ -245,6 +281,10 @@ def check(self, repo) -> Tuple[bool, str]: logging.info(msg=toml_cfg) os.chdir(core_dir) # check and parse config + check_res = self.check_meta(toml_cfg) + if check_res[0] is False: + return check_res + check_res = self.check_dut(toml_cfg) if check_res[0] is False: return check_res diff --git a/src/data_type.py b/src/data_type.py index 4adde09..e3b464e 100644 --- a/src/data_type.py +++ b/src/data_type.py @@ -13,6 +13,17 @@ def __str__(self) -> str: return f'url: {self.url} repo: {self.repo} flag: {self.flag}' +class MetaConfig(object): + def __init__(self, proj: str, auth: str, ver: str, notif: Tuple[str, str]): + self.proj = proj + self.auth = auth + self.ver = ver + self.notif = notif + + def __str__(self) -> str: + return f'proj: {self.proj} auth: {self.auth} ver: {self.ver} notif: {self.notif}' + + class DUTConfig(object): def __init__(self, arch: str, file: str, top: str, clk: str, commit: str): self.arch = arch @@ -80,9 +91,10 @@ def __str__(self) -> str: class SubmitConfig(object): - def __init__(self, dut_cfg: DUTConfig, iv_cfg: IverilogConfig, - ver_cfg: VerilatorConfig, vcs_cfg: VCSConfig, - dc_cfg: DCConfig): + def __init__(self, meta_cfg: MetaConfig, dut_cfg: DUTConfig, + iv_cfg: IverilogConfig, ver_cfg: VerilatorConfig, + vcs_cfg: VCSConfig, dc_cfg: DCConfig): + self.meta_cfg = meta_cfg self.dut_cfg = dut_cfg self.iv_cfg = iv_cfg self.ver_cfg = ver_cfg @@ -90,9 +102,9 @@ def __init__(self, dut_cfg: DUTConfig, iv_cfg: IverilogConfig, self.dc_cfg = dc_cfg def __str__(self) -> str: - return f'''dut_cfg: {self.dut_cfg} iv_cfg: {self.iv_cfg} - ver_cfg: {self.ver_cfg} vcs_cfg: {self.vcs_cfg} - dc_cfg: {self.dc_cfg}''' + return f'''meta_cfg: {self.meta_cfg} dut_cfg: {self.dut_cfg} + iv_cfg: {self.iv_cfg} ver_cfg: {self.ver_cfg} + vcs_cfg: {self.vcs_cfg} dc_cfg: {self.dc_cfg}''' class QueueInfo(object): diff --git a/src/demo.py b/src/demo.py index f03ccb4..0635724 100644 --- a/src/demo.py +++ b/src/demo.py @@ -2,6 +2,7 @@ import re from typing import Tuple +from enum import Enum def find_str(file: str, pat: str) -> Tuple[bool, int]: @@ -20,7 +21,8 @@ def find_str(file: str, pat: str) -> Tuple[bool, int]: top = 'ysyx_22000000' clk = 'clock' -(top_state, top_pos) = find_str(file_path, f'\\s*module\\s*{top}\\s*[\\(\\)|\\(|\\s*]') +(top_state, top_pos) = find_str(file_path, + f'\\s*module\\s*{top}\\s*[\\(\\)|\\(|\\s*]') if top_state is False: print('error') @@ -29,3 +31,42 @@ def find_str(file: str, pat: str) -> Tuple[bool, int]: print('error') else: print('right') + + +class LogState(Enum): + start = 0 + end = 1 + + +file_path = '/home/liaoyuchi/Desktop/ysyx_ci_env/ysyx_ci_result/submit/' + +lint = [] +warn = [] +err = [] +log_state = [LogState.end, LogState.end, LogState.end] +with open(f'{file_path}/../../vcs/run/compile.log', 'r', + encoding='utf-8') as fp: + for line in fp: + if line[0:4] == 'Lint': + log_state[0] = LogState.start + elif line[0:7] == 'Warning': + log_state[1] = LogState.start + elif line[0:5] == 'Error': + log_state[2] = LogState.start + elif line == '\n': + log_state = [LogState.end, LogState.end, LogState.end] + if log_state[0] == LogState.start: + lint.append(line) + elif log_state[1] == LogState.start: + warn.append(line) + elif log_state[2] == LogState.start: + err.append(line) + +print(len(lint)) +print(len(warn)) +print(len(err)) + +if len(lint) == 0 and len(warn) == 0 and len(err) == 0: + print('all clear') +else: + print('error') \ No newline at end of file diff --git a/src/dispatch.py b/src/dispatch.py index 8d4a7c3..6fdd9cf 100644 --- a/src/dispatch.py +++ b/src/dispatch.py @@ -60,6 +60,12 @@ def parse(self) -> bool: config.git_commit(config.RPT_DIR, '[bot] new report!', True) # NOTE: need to set 'True' when in product env + report.send_mail( + ('maksyuki@126.com', 'on'), + f'{sub_cfg.dut_cfg.top}-{cmt_cfg.date}-{cmt_cfg.time}') + report.send_mail( + sub_cfg.meta_cfg.notif, + f'{sub_cfg.dut_cfg.top}-{cmt_cfg.date}-{cmt_cfg.time}') return True diff --git a/src/report.py b/src/report.py index fe38a8e..8278c7e 100644 --- a/src/report.py +++ b/src/report.py @@ -1,8 +1,10 @@ #!/bin/python import os import logging +from typing import Tuple import config + # helper class class Report(object): def __init__(self): @@ -17,12 +19,44 @@ def create_dir(repo: str): os.system(f'mkdir -p {report.dut_rpt_dir}') +def send_mail(notif_cfg: Tuple[str, str], commit: str): + (rcpt_mail_url, send_ena) = notif_cfg + if send_ena == 'on': + cmd = 'curl --url smtp://smtp.qq.com' + cmd += f' --mail-from {config.SEND_MAIL_URL}' + cmd += f' --mail-rcpt {rcpt_mail_url}' + os.system( + f'cp -rf {config.TEMPLATE_DIR}/mail.info {config.DATA_DIR}/tmp_mail.info' + ) + + config.repl_str(f'{config.DATA_DIR}/tmp_mail.info', + 'TEMPLATE_SEND_MAIL_URL', config.SEND_MAIL_URL) + + config.repl_str(f'{config.DATA_DIR}/tmp_mail.info', + 'TEMPLATE_RCPT_MAIL_URL', rcpt_mail_url) + + config.repl_str(f'{config.DATA_DIR}/tmp_mail.info', 'TEMPLATE_NAME', + rcpt_mail_url.split('@')[0]) + + config.repl_str(f'{config.DATA_DIR}/tmp_mail.info', 'TEMPLATE_COMMIT', + commit) + + cmd += f' --upload-file {config.DATA_DIR}/tmp_mail.info' + with open(f'{config.TEMPLATE_DIR}/mail.token', 'r', + encoding='utf-8') as fp: + for v in fp: + cmd += f' --user {v.rstrip()}' + print(cmd) + os.system(cmd) + + def gen_state(stat: str): os.system(f'echo {stat} > {report.dut_rpt_dir}/state') def main(): logging.info(msg='[return report]') + send_mail('maksyuki@126.com', '2024-03-11-09:52:51') if __name__ == '__main__': diff --git a/src/vcs_test.py b/src/vcs_test.py index 927ee76..17c8a33 100644 --- a/src/vcs_test.py +++ b/src/vcs_test.py @@ -1,6 +1,7 @@ #!/bin/python from enum import Enum +from typing import Tuple import os import logging import config @@ -65,6 +66,7 @@ def program(self, arch: str, prog_name: str, prog_type: str): def collect_comp_log(self): log_state = [LogState.end, LogState.end, LogState.end] + block_info = [] with open(f'{config.VCS_RUN_DIR}/compile.log', 'r', encoding='utf-8') as fp: for line in fp: @@ -75,14 +77,26 @@ def collect_comp_log(self): elif line[0:5] == 'Error': log_state[2] = LogState.start elif line == '\n': + if log_state[0] == LogState.start and len(block_info) >= 2: + self.lint += block_info + elif log_state[1] == LogState.start: + self.warn += block_info + elif log_state[2] == LogState.start: + self.err += block_info log_state = [LogState.end, LogState.end, LogState.end] + block_info = [] + + if log_state[0] == LogState.start or log_state[ + 1] == LogState.start or log_state[2] == LogState.start: + if 'vga_ctrl' in line: + log_state[0] = LogState.end + else: + block_info.append(line) + + # filter the vga ctrl no used lint + for v in self.lint: + print(v) - if log_state[0] == LogState.start: - self.lint.append(line) - elif log_state[1] == LogState.start: - self.warn.append(line) - elif log_state[2] == LogState.start: - self.err.append(line) logging.info(msg=f'lint: {self.lint}') logging.info(msg=f'warn: {self.warn}') logging.info(msg=f'err: {self.err}') @@ -104,7 +118,8 @@ def gen_wave_rpt(self): (prog_name, prog_type) = self.vcs_cfg.prog os.chdir(config.VCS_RUN_DIR) - wave_name = f'{self.dut_cfg.top}_{prog_name}_{prog_type}' + wave_name = f'{self.dut_cfg.top}_{self.cmt_cfg.date}-{self.cmt_cfg.time.replace(":", "-")}' + wave_name += f'_{prog_name}_{prog_type}' os.system(f'fsdb2vcd asic_top.fsdb -o {wave_name}.vcd') os.system(f'vcd2fst -v {wave_name}.vcd -f {wave_name}.fst') os.system(f'tar -czvf {wave_name}.fst.tar.bz2 {wave_name}.fst') @@ -126,7 +141,7 @@ def gen_wave_rpt(self): os.system(cmd) os.system(f'rm -rf {wave_name}.fst') os.system(f'rm -rf {wave_name}.vcd') - os.system(f'rm -rf {wave_name}.fst.tar.bz2') + # os.system(f'rm -rf {wave_name}.fst.tar.bz2') # config.git_commit( # config.WAVE_DIR, '[bot] new wave!', # True) # NOTE: need to set 'True' when in product env @@ -188,22 +203,24 @@ def gen_comp_rpt(self) -> bool: fp.writelines(self.err + self.warn + self.lint) return False - def gen_run_res(self, prog_name: str, prog_type: str) -> str: - res = '' - + def gen_run_res(self, prog_name: str, prog_type: str) -> Tuple[bool, str]: + run_state = False + run_res = '' if self.run_res[f'{prog_name}-{prog_type}'] == '': - res += f'{prog_name} test in {prog_type} pass!!\n' + run_res += f'{prog_name} test in {prog_type} pass!!\n' + run_state = True else: - res += f'{prog_name} test in {prog_type} fail!!\n' - res += '======================================================\n' - res += self.run_res[f'{prog_name}-{prog_type}'] - res += '======================================================\n\n' + run_res += f'{prog_name} test in {prog_type} fail!!\n' + run_res += '======================================================\n' + run_res += self.run_res[f'{prog_name}-{prog_type}'] + run_res += '======================================================\n\n' - return res + return (run_state, run_res) def gen_run_rpt(self) -> bool: rpt_path = self.gen_rpt_dir() (prog_name, prog_type) = self.vcs_cfg.prog + run_res = True with open(f'{rpt_path}/vcs_report', 'a+', encoding='utf-8') as fp: fp.writelines( '\n#####################\n#vcs program test\n#####################\n' @@ -212,11 +229,17 @@ def gen_run_rpt(self) -> bool: if prog_name == 'all': for pl in config.TESTCASE_NAME_LIST: for mt in config.TESTCASE_TYPE_LIST: - fp.writelines(self.gen_run_res(pl, mt)) + (test_res, test_info) = self.gen_run_res(pl, mt) + if test_res is False: + run_res = False + fp.writelines(test_info) else: - fp.writelines(self.gen_run_res(prog_name, prog_type)) + (test_res, test_info) = self.gen_run_res(prog_name, prog_type) + if test_res is False: + run_res = False + fp.writelines(test_info) - return True + return run_res vcstest = VCSTest()