nsdk_builder.py 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124
  1. #!/usr/bin/env python3
  2. import os
  3. import sys
  4. import time
  5. import copy
  6. import shutil
  7. import glob
  8. import traceback
  9. SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
  10. requirement_file = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "requirements.txt"))
  11. try:
  12. import serial
  13. import tempfile
  14. import json
  15. import argparse
  16. from threading import Thread
  17. import subprocess
  18. except:
  19. print("Please install requried packages using: pip3 install -r %s" % (requirement_file))
  20. sys.exit(1)
  21. from nsdk_utils import *
  22. VALID_MAKEFILE_NAMES = ['Makefile', 'makefile', "GNUMakefile"]
  23. def is_nuclei_evalsoc(soc):
  24. if soc == "hbird" or soc == "demosoc" or soc == "evalsoc" or soc == "xlspike":
  25. return True
  26. else:
  27. return False
  28. class nsdk_builder(object):
  29. def __init__(self):
  30. pass
  31. @staticmethod
  32. def is_app(appdir):
  33. if os.path.isdir(appdir) == False:
  34. return False
  35. appdir = os.path.realpath(appdir)
  36. for mkname in VALID_MAKEFILE_NAMES:
  37. mkfile_path = os.path.join(appdir, mkname)
  38. if os.path.isfile(mkfile_path):
  39. return True
  40. return False
  41. @staticmethod
  42. def copy_objects(appsts, copydir):
  43. if isinstance(appsts, dict) and "objects" in appsts:
  44. os.makedirs(copydir, exist_ok=True)
  45. objects = appsts["objects"]
  46. if "saved_objects" not in appsts:
  47. appsts["saved_objects"] = dict()
  48. cp_keys = get_sdk_copyobjects()
  49. if cp_keys != None:
  50. cp_keys = cp_keys.strip().split(",")
  51. for obj in objects:
  52. obj_file = objects[obj]
  53. if os.path.isfile(obj_file): # only copy when exist
  54. filename = os.path.basename(obj_file)
  55. filesuffix = os.path.splitext(filename)[-1].strip(".")
  56. newfile = os.path.join(copydir, filename)
  57. if cp_keys is None or filesuffix in cp_keys:
  58. shutil.copyfile(obj_file, newfile)
  59. appsts["saved_objects"][obj] = newfile
  60. pass
  61. @staticmethod
  62. def get_objects(appdir, target=None, timestamp=None):
  63. if nsdk_builder.is_app(appdir) == False:
  64. return None
  65. def find_app_object(pattern):
  66. files = find_files(appdir, pattern)
  67. found_file = ""
  68. latest_timestamp = 0
  69. for fl in files:
  70. flct = os.stat(fl).st_ctime
  71. if timestamp:
  72. if flct >= timestamp:
  73. found_file = fl
  74. break
  75. else:
  76. # find a latest file
  77. if flct > latest_timestamp:
  78. latest_timestamp = flct
  79. found_file = fl
  80. return found_file
  81. build_objects = dict()
  82. if target:
  83. build_objects["elf"] = find_app_object("*%s.elf" % (target))
  84. build_objects["map"] = find_app_object("*%s.map" % (target))
  85. build_objects["dump"] = find_app_object("*%s.dump" % (target) )
  86. build_objects["dasm"] = find_app_object("*%s.dasm" % (target))
  87. build_objects["verilog"] = find_app_object("*%s.verilog" % (target))
  88. else:
  89. build_objects["elf"] = find_app_object("*.elf")
  90. build_objects["map"] = find_app_object("*.map")
  91. build_objects["dump"] = find_app_object("*.dump")
  92. build_objects["dasm"] = find_app_object("*.dasm")
  93. build_objects["verilog"] = find_app_object("*.verilog")
  94. return build_objects
  95. def build_target_only(self, appdir, make_options="", target="clean", show_output=True, logfile=None, parallel=""):
  96. if self.is_app(appdir) == False:
  97. return COMMAND_NOTAPP, 0
  98. # Parallel must start with -j
  99. if isinstance(parallel, str):
  100. parallel = parallel.strip()
  101. if parallel != "" and parallel.startswith("-j") == False:
  102. parallel = ""
  103. else:
  104. parallel = ""
  105. if parallel != "": # need to split targets
  106. build_targets = target.strip().split()
  107. if get_sdk_verb_buildmsg():
  108. print("Target \"%s\" are split to seperated targets %s in parallel mode." %(target, build_targets))
  109. else:
  110. build_targets = [target]
  111. if os.path.isfile(logfile):
  112. os.remove(logfile)
  113. total_ticks = 0
  114. ignore_targets = ["info", "showtoolver", "showflags", "clean", "bin", "size"]
  115. for btg in build_targets:
  116. build_cmd = "make %s -C %s %s %s" % (parallel, appdir, make_options, btg)
  117. if get_sdk_verb_buildmsg() and (not ((show_output == False) and (btg in ignore_targets))):
  118. print("Build application %s, with target: %s" % (appdir, btg))
  119. print("Build command: %s" % (build_cmd))
  120. ret, ticks = run_command(build_cmd, show_output, logfile=logfile, append=True)
  121. if get_sdk_verb_buildmsg() and (not ((show_output == False) and (btg in ignore_targets))):
  122. print("Build command return value: %s" % (ret))
  123. total_ticks += ticks
  124. if ret != 0: # if one target failed, then stop
  125. break
  126. return ret, ticks
  127. def get_build_info(self, appdir, make_options=""):
  128. infolog = tempfile.mktemp()
  129. ret, _ = self.build_target_only(appdir, make_options, "info", False, infolog)
  130. build_info = dict()
  131. if ret != COMMAND_RUNOK:
  132. os.remove(infolog)
  133. return build_info
  134. build_info = dict()
  135. with open(infolog, "r", errors='ignore') as inf:
  136. for line in inf.readlines():
  137. line = line.strip()
  138. INFO_TAG = "Current Configuration:"
  139. if line.startswith(INFO_TAG):
  140. infos = line.replace(INFO_TAG, "").strip().split()
  141. for info in infos:
  142. splits = info.split("=")
  143. if len(splits) == 2:
  144. build_info[splits[0]] = splits[1]
  145. os.remove(infolog)
  146. return build_info
  147. def get_build_flags(self, appdir, make_options=""):
  148. flagslog = tempfile.mktemp()
  149. ret, _ = self.build_target_only(appdir, make_options, "showflags", False, flagslog)
  150. build_flags = dict()
  151. if ret != COMMAND_RUNOK:
  152. os.remove(flagslog)
  153. return build_flags
  154. build_flags = dict()
  155. with open(flagslog, "r", errors='ignore') as inf:
  156. for line in inf.readlines():
  157. line = line.strip()
  158. if ":" in line:
  159. splits = line.split(":")
  160. if len(splits) != 2:
  161. continue
  162. key, value = splits
  163. key = key.strip()
  164. value = value.strip()
  165. build_flags[key] = value
  166. os.remove(flagslog)
  167. return build_flags
  168. def get_build_toolver(self, appdir, make_options=""):
  169. log = tempfile.mktemp()
  170. ret, _ = self.build_target_only(appdir, make_options, "showtoolver", False, log)
  171. buildout = dict()
  172. if ret != COMMAND_RUNOK:
  173. os.remove(log)
  174. return buildout
  175. buildout = dict()
  176. toolname = ""
  177. with open(log, "r", errors='ignore') as inf:
  178. for line in inf.readlines():
  179. line = line.strip()
  180. if line.startswith("Show"):
  181. toolname = line.split()[1].strip()
  182. buildout[toolname] = ""
  183. elif line.startswith("make:") == False:
  184. if toolname != "":
  185. buildout[toolname] += line + "\n"
  186. os.remove(log)
  187. return buildout
  188. def build_target(self, appdir, make_options="", target="clean", show_output=True, logfile=None, parallel=""):
  189. if self.is_app(appdir) == False:
  190. return False, None
  191. build_status = dict()
  192. ret, ticks = self.build_target_only(appdir, make_options, target, show_output, logfile, parallel)
  193. cmdsts = True
  194. if ret == COMMAND_INTERRUPTED:
  195. print("%s: Exit program due to CTRL - C pressed" % (sys._getframe().f_code.co_name))
  196. sys.exit(1)
  197. elif ret == COMMAND_RUNOK:
  198. cmdsts = True
  199. else:
  200. cmdsts = False
  201. build_status["app"] = { "path": appdir, \
  202. "make_options": make_options, \
  203. "ci": get_ci_info(), \
  204. "target": target }
  205. build_status["status"] = {"build": cmdsts}
  206. build_status["status_code"] = {"build": ret}
  207. build_status["logs"] = {"build": logfile}
  208. build_status["time"] = {"build": round(ticks, 2)}
  209. build_status["info"] = self.get_build_info(appdir, make_options)
  210. build_status["toolver"] = self.get_build_toolver(appdir, make_options)
  211. build_status["flags"] = self.get_build_flags(appdir, make_options)
  212. apptarget = None
  213. if build_status["flags"]:
  214. apptarget = build_status["flags"].get("TARGET", None)
  215. build_status["objects"] = nsdk_builder.get_objects(appdir, apptarget)
  216. build_status["size"] = get_elfsize(build_status["objects"].get("elf", ""))
  217. return cmdsts, build_status
  218. def clean_app(self, appdir, make_options="", show_output=True, logfile=None):
  219. return self.build_target(appdir, make_options, "clean", show_output, logfile)
  220. def compile_app(self, appdir, make_options="", show_output=True, logfile=None, parallel=""):
  221. return self.build_target(appdir, make_options, "all", show_output, logfile, parallel)
  222. def upload_app(self, appdir, make_options="", show_output=True, logfile=None):
  223. if logfile is None:
  224. uploadlog = tempfile.mktemp()
  225. else:
  226. uploadlog = logfile
  227. cmdsts, build_status = self.build_target(appdir, make_options, "upload", show_output, uploadlog)
  228. uploader = dict()
  229. upload_sts = False
  230. # some error might happened error, try catch protect it
  231. try:
  232. with open(uploadlog, 'r', errors='ignore') as uf:
  233. for line in uf.readlines():
  234. if "-ex" in line or "\\" in line:
  235. # strip extra newline and \
  236. uploader["cmd"] = uploader.get("cmd", "") + line.strip().strip("\\")
  237. if "On-Chip Debugger" in line:
  238. uploader["version"] = line.strip()
  239. if "A problem internal to GDB has been detected" in line:
  240. uploader["gdbstatus"] = "hang"
  241. if "Quit this debugging session?" in line:
  242. uploader["gdbstatus"] = "hang"
  243. if "Remote communication error" in line:
  244. uploader["gdbstatus"] = "lostcon"
  245. if "Start address" in line:
  246. uploader["gdbstatus"] = "ok"
  247. upload_sts = True
  248. break
  249. # append openocd log to upload log
  250. openocd_log = os.path.join(appdir, "openocd.log")
  251. if os.path.isfile(openocd_log):
  252. with open(uploadlog, 'a', errors='ignore') as uf:
  253. uf.write("\n=====OpenOCD log content dumped as below:=====\n")
  254. with open(openocd_log, "r", errors='ignore') as of:
  255. for line in of.readlines():
  256. if "Error: Target not examined yet" in line:
  257. uploader["cpustatus"] = "hang"
  258. if "Examined RISC-V core" in line:
  259. uploader["cpustatus"] = "ok"
  260. if "Unable to halt hart" in line:
  261. uploader["cpustatus"] = "hang"
  262. uf.write(line)
  263. except Exception as exc:
  264. print("Some error happened during upload application, %s" % (str(exc)))
  265. traceback.print_exc()
  266. if upload_sts == False: # actually not upload successfully
  267. cmdsts = False
  268. if "app" in build_status:
  269. build_status["app"]["uploader"] = uploader
  270. if logfile is None:
  271. os.remove(uploadlog)
  272. print("Upload application %s status: %s" % (appdir, cmdsts))
  273. return cmdsts, build_status
  274. class MonitorThread(Thread):
  275. def __init__(self, port:str, baudrate:str, timeout:int, checks:dict, checktime=time.time(), sdk_check=False, logfile=None, show_output=False):
  276. super().__init__()
  277. self.port = port
  278. self.baudrate = baudrate
  279. self.timeout = timeout
  280. self.checks = checks
  281. self.checktime = checktime
  282. self.tty_iserr = False
  283. self.sdk_check = sdk_check
  284. self.logfile = logfile
  285. self.show_output = show_output
  286. self._exit_req = False
  287. self._check_sdk = False
  288. self._check_sdk_timeout = 10
  289. self.result = False
  290. self.reason = ""
  291. pass
  292. def get_result(self):
  293. try:
  294. return self.result
  295. except Exception:
  296. return False
  297. def get_reason(self):
  298. try:
  299. return self.reason
  300. except Exception:
  301. return ""
  302. def get_tty_iserror(self):
  303. return self.tty_iserr
  304. def exit_request(self):
  305. self._exit_req = True
  306. pass
  307. def set_check_sdk_timeout(self, timeout=10):
  308. self._check_sdk_timestart = time.time()
  309. self._check_sdk_timeout = timeout
  310. self._check_sdk = True # start to check timeout monitor
  311. pass
  312. def run(self):
  313. start_time = time.time()
  314. serial_prelog = ""
  315. serial_log = ""
  316. check_status = False
  317. check_reason = ""
  318. pass_checks = self.checks.get("PASS", [])
  319. fail_checks = self.checks.get("FAIL", [])
  320. def test_in_check(string, checks):
  321. if type(checks) == list:
  322. for check in checks:
  323. if check in string:
  324. return True
  325. return False
  326. NSDK_CHECK_TAG = get_sdk_checktag()
  327. if get_sdk_verb_buildmsg():
  328. print("Read serial log from %s, baudrate %s" %(self.port, self.baudrate))
  329. print("Checker used: ", self.checks)
  330. print("SDK Checker Tag \"%s\", checker enable %s" % (NSDK_CHECK_TAG, self.sdk_check))
  331. print("SDK run timeout %s, banner timeout %s" % (self.timeout, self._check_sdk_timeout))
  332. check_finished = False
  333. try:
  334. ser = None
  335. ser = serial.Serial(self.port, self.baudrate, timeout=3)
  336. while (time.time() - start_time) < self.timeout:
  337. if self._exit_req:
  338. break
  339. # Remove '\r' in serial read line
  340. sline = ser.readline()
  341. line = str(try_decode_bytes(sline)).replace('\r', '')
  342. if self.sdk_check == True:
  343. if self.show_output:
  344. print("XXX Check " + line, end='')
  345. if self._check_sdk:
  346. chk_time_cost = time.time() - self._check_sdk_timestart
  347. if chk_time_cost > self._check_sdk_timeout:
  348. print("No SDK banner found in %s s, quit now!" % (self._check_sdk_timeout))
  349. check_reason = BANNER_TMOUT
  350. break
  351. if NSDK_CHECK_TAG in line:
  352. timestr = line.split(NSDK_CHECK_TAG)[-1].strip()
  353. if "Download" in timestr:
  354. print("Warning: Download and SDK tag in same line which should not happen!")
  355. #timestr = timestr.split("Download")[0].strip()
  356. try:
  357. cur_time = time.mktime(time.strptime(timestr, "%b %d %Y, %H:%M:%S"))
  358. except:
  359. print("Warning: Failed to parse time string %s" % (timestr))
  360. cur_time = 0
  361. if int(cur_time) >= int(self.checktime):
  362. self.sdk_check = False
  363. line = NSDK_CHECK_TAG + " " + timestr + "\n"
  364. serial_log = serial_log + str(line)
  365. else:
  366. # record previous log of this application
  367. serial_prelog = serial_prelog + str(line)
  368. else:
  369. serial_log = serial_log + str(line)
  370. if self.show_output:
  371. print(line, end='')
  372. if check_finished == False:
  373. if test_in_check(line, fail_checks):
  374. check_reason = "FAIL line: %s" % (line)
  375. check_status = False
  376. check_finished = True
  377. if test_in_check(line, pass_checks):
  378. check_reason = "PASS line: %s" % (line)
  379. check_status = True
  380. check_finished = True
  381. if check_finished:
  382. # record another 2 seconds by reset start_time and timeout to 2
  383. start_time = time.time()
  384. self.timeout = 2
  385. except serial.serialutil.SerialException:
  386. # https://stackoverflow.com/questions/21050671/how-to-check-if-device-is-connected-pyserial
  387. print("serial port %s might not exist or in use" % self.port)
  388. # set tty is error
  389. self.tty_iserr = True
  390. check_reason = TTY_OP_ERR
  391. except Exception as exc:
  392. print("Some error happens during serial operations, %s" % (str(exc)))
  393. check_reason = TTY_UNKNOWN_ERR
  394. finally:
  395. if ser:
  396. ser.close()
  397. if self.logfile:
  398. with open(self.logfile, 'w') as lf:
  399. lf.write(serial_log)
  400. prelogfile = os.path.splitext(self.logfile)[0] + "pre.log"
  401. # record prestep serial log
  402. if serial_prelog.strip() != "":
  403. with open(prelogfile, 'w') as lf:
  404. lf.write(serial_prelog)
  405. self.result = check_status
  406. self.reason = check_reason
  407. return check_status
  408. class nsdk_runner(nsdk_builder):
  409. def __init__(self):
  410. super().__init__()
  411. self.hangup_action = None
  412. self.ttyerrcnt = 0
  413. self.fpgaprogramcnt = 0
  414. self.gdberrcnt = 0
  415. self.bannertmoutcnt = 0
  416. self.uploaderrcnt = 0
  417. pass
  418. @staticmethod
  419. def find_apps(rootdir):
  420. subdirectories = [x[0] for x in os.walk(rootdir)]
  421. appdirs = []
  422. for subdir in subdirectories:
  423. if nsdk_runner.is_app(subdir):
  424. appdirs.append(os.path.normpath(subdir))
  425. return appdirs
  426. def reset_counters(self):
  427. self.ttyerrcnt = 0
  428. self.uploaderrcnt = 0
  429. self.fpgaprogramcnt = 0
  430. self.gdberrcnt = 0
  431. self.bannertmoutcnt = 0
  432. pass
  433. def need_exit_now(self):
  434. if self.ttyerrcnt > get_sdk_ttyerr_maxcnt():
  435. return True
  436. if self.fpgaprogramcnt > get_sdk_fpgaprog_maxcnt():
  437. return True
  438. if self.gdberrcnt > get_sdk_gdberr_maxcnt():
  439. return True
  440. if self.bannertmoutcnt > get_sdk_bannertmout_maxcnt():
  441. return True
  442. if self.uploaderrcnt > get_sdk_uploaderr_maxcnt():
  443. return True
  444. return False
  445. def show_counters(self):
  446. print("TTY Error counter %d, limit count %d" % (self.ttyerrcnt, get_sdk_ttyerr_maxcnt()))
  447. print("GDB Internal Error counter %d, limit count %d" % (self.gdberrcnt, get_sdk_gdberr_maxcnt()))
  448. print("Upload Error counter %d, limit count %d" % (self.uploaderrcnt, get_sdk_uploaderr_maxcnt()))
  449. print("Banner Timeout Error counter %d, limit count %d" % (self.bannertmoutcnt, get_sdk_bannertmout_maxcnt()))
  450. print("FPGA Program Error counter %d, limit count %d" % (self.fpgaprogramcnt, get_sdk_fpgaprog_maxcnt()))
  451. pass
  452. def set_cpu_hangup_action(self, hangaction):
  453. self.hangup_action = hangaction
  454. pass
  455. def build_target_in_directory(self, rootdir, make_options="", target="", \
  456. show_output=True, logdir=None, stoponfail=False):
  457. appdirs = self.find_apps(rootdir)
  458. if len(appdirs) == 0:
  459. return False, None
  460. cmdsts = True
  461. build_status = dict()
  462. createlog = False
  463. if isinstance(logdir, str):
  464. createlog = True
  465. if os.path.isdir(logdir) == False:
  466. os.makedirs(logdir)
  467. for appdir in appdirs:
  468. appdir = appdir.replace("\\", "/") # Change windows \\ path to /
  469. applogfile = None
  470. if createlog:
  471. applogfile = get_logfile(appdir, rootdir, logdir, "build.log")
  472. appcmdsts, appsts = self.build_target(appdir, make_options, \
  473. target, show_output, logfile=applogfile)
  474. build_status[appdir] = appsts
  475. if appcmdsts == False:
  476. cmdsts = appcmdsts
  477. if stoponfail == True:
  478. print("Stop build directory due to fail on application %s" %(appdir))
  479. return cmdsts, build_status
  480. return cmdsts, build_status
  481. def analyze_runlog(self, logfile, parsescript=None):
  482. result = {"type": "unknown", "value": {}}
  483. if os.path.isfile(logfile):
  484. try:
  485. result_lines = open(logfile, "r", errors='ignore').readlines()
  486. except:
  487. result_lines = []
  488. program_found, subtype, result_parsed = parse_benchmark_runlog(result_lines, lgf=logfile)
  489. if program_found == PROGRAM_UNKNOWN:
  490. program_found, subtype, result_parsed = parse_benchmark_use_pyscript(result_lines, logfile, parsescript)
  491. if program_found != PROGRAM_UNKNOWN:
  492. result = {"type": program_found, "subtype": subtype, "value": result_parsed}
  493. return result
  494. def run_app_onhw(self, appdir, runcfg:dict(), show_output=True, logfile=None, uploadlog=None):
  495. app_runcfg = runcfg.get("run_config", dict())
  496. app_runchecks = runcfg.get("checks", dict())
  497. make_options = runcfg["misc"]["make_options"]
  498. checktime = runcfg["misc"]["build_time"]
  499. hwconfig = app_runcfg.get("hardware", None)
  500. serport = None
  501. timeout = 60
  502. baudrate = 115200
  503. fpgabit = None
  504. fpgaserial = None
  505. run_tmout = get_sdk_run_tmout()
  506. if hwconfig is not None:
  507. most_possible_serport = find_most_possible_serport()
  508. serport = hwconfig.get("serport", most_possible_serport)
  509. baudrate = hwconfig.get("baudrate", 115200)
  510. # priority: environment var SDK_RUN_TMOUT > hwconfig in app.json
  511. timeout = run_tmout if run_tmout is not None else hwconfig.get("timeout", 60)
  512. fpgabit = hwconfig.get("fpgabit", None)
  513. fpgaserial = hwconfig.get("fpgaserial", None)
  514. ser_thread = None
  515. uploader = None
  516. sdk_check = get_sdk_check()
  517. banner_tmout = get_sdk_banner_tmout()
  518. retry_cnt = 0
  519. max_retrycnt = 1
  520. while True:
  521. try:
  522. if retry_cnt > max_retrycnt: # do retry
  523. break
  524. retry_cnt += 1
  525. print("Hardware configuration: serial port %s, baudrate %s, timeout %ds, retry counter %d" % (serport, baudrate, timeout, retry_cnt))
  526. if serport: # only monitor serial port when port found
  527. ser_thread = MonitorThread(serport, baudrate, timeout, app_runchecks, checktime, \
  528. sdk_check, logfile, show_output)
  529. ser_thread.start()
  530. else:
  531. print("Warning: No available serial port found, please check!")
  532. self.ttyerrcnt += 1
  533. cmdsts, upload_sts = self.upload_app(appdir, make_options, show_output, uploadlog)
  534. uploader = upload_sts.get("app", dict()).get("uploader", None)
  535. uploader["retried"] = retry_cnt
  536. status = True
  537. check_reason = ""
  538. if ser_thread:
  539. if cmdsts == False:
  540. ser_thread.exit_request()
  541. else:
  542. ser_thread.set_check_sdk_timeout(banner_tmout)
  543. while ser_thread.is_alive():
  544. ser_thread.join(1)
  545. status = ser_thread.get_result()
  546. check_reason = ser_thread.get_reason()
  547. if ser_thread.get_tty_iserror(): # tty is in use or not exist
  548. print("tty serial port error count %d" % (self.ttyerrcnt))
  549. self.ttyerrcnt += 1
  550. del ser_thread
  551. if uploader.get("cpustatus", "") == "hang": # cpu hangs then call cpu hangup action and retry this application
  552. max_retrycnt = 1 # when upload error happened, do retry once
  553. self.uploaderrcnt += 1
  554. if self.hangup_action is not None:
  555. print("Execute hangup action for hangup case!")
  556. if self.hangup_action() == True:
  557. print("hangup action success!")
  558. continue
  559. else:
  560. print("hangup action failed!")
  561. elif fpgabit and fpgaserial:
  562. print("Reprogram fpga bit %s on fpga board serial number %s, total fpga reprogam count %d" % (fpgabit, fpgaserial, self.fpgaprogramcnt))
  563. self.fpgaprogramcnt += 1
  564. if program_fpga(fpgabit, fpgaserial) == True:
  565. print("Reprogram fpga sucessfully!")
  566. continue
  567. else:
  568. print("Reprogram fpga failed!")
  569. else:
  570. print("No cpu hangup action found, just continue with other cases")
  571. if uploader.get("gdbstatus", "") == "hang": # gdb hangs with internal error retry upload this application
  572. max_retrycnt = 2 # when gdb internal error happened, do retry twice
  573. print("GDB internal error happened, re-upload application, total re-upload count %d" % (self.gdberrcnt))
  574. self.gdberrcnt += 1
  575. continue
  576. if status == False and check_reason == BANNER_TMOUT: # banner timeout error, so retry upload application
  577. max_retrycnt = 1 # when banner timeout error happened, do retry once
  578. print("Banner timeout, re-upload application, total re-upload count %d" % (self.bannertmoutcnt))
  579. self.bannertmoutcnt += 1
  580. continue
  581. # exit with upload status
  582. break
  583. except (KeyboardInterrupt, SystemExit):
  584. print("%s: Exit program due to CTRL - C pressed or SystemExit" % (sys._getframe().f_code.co_name))
  585. if ser_thread:
  586. ser_thread.exit_request()
  587. sys.exit(1)
  588. final_status = cmdsts and status
  589. return final_status, uploader
  590. def run_app_onqemu(self, appdir, runcfg:dict(), show_output=True, logfile=None):
  591. app_runcfg = runcfg.get("run_config", dict())
  592. app_runchecks = runcfg.get("checks", dict())
  593. build_info = runcfg["misc"]["build_info"]
  594. build_config = runcfg["misc"]["build_config"]
  595. build_objects = runcfg["misc"]["build_objects"]
  596. checktime = runcfg["misc"]["build_time"]
  597. hwconfig = app_runcfg.get("qemu", dict())
  598. timeout = 60
  599. qemu_exe = None
  600. qemu_extraopt = ""
  601. if hwconfig is not None:
  602. qemu32_exe = hwconfig.get("qemu32", "qemu-system-riscv32")
  603. qemu64_exe = hwconfig.get("qemu64", "qemu-system-riscv64")
  604. qemu_machine = hwconfig.get("qemu_machine", None)
  605. qemu_cpu = hwconfig.get("qemu_cpu", None)
  606. qemu_exe = qemu32_exe
  607. build_soc = build_info["SOC"]
  608. build_board = build_info["BOARD"]
  609. build_core = build_info["CORE"]
  610. build_download = build_info["DOWNLOAD"]
  611. build_smp = build_info.get("SMP", "")
  612. build_arch_ext = build_config.get("ARCH_EXT", "")
  613. build_semihost = False
  614. if build_config.get("SEMIHOST", "") != "":
  615. build_semihost = True
  616. if build_arch_ext == "":
  617. build_arch_ext = build_info.get("ARCH_EXT", "")
  618. if build_smp != "":
  619. qemu_extraopt = "%s -smp %s" % (qemu_extraopt, build_smp)
  620. if build_semihost: # use qemu semihosting, if program build with semihost feature
  621. qemu_extraopt = "%s -semihosting " % (qemu_extraopt)
  622. if qemu_machine is None:
  623. if is_nuclei_evalsoc(build_soc):
  624. machine = "nuclei_evalsoc"
  625. else:
  626. if build_board == "gd32vf103v_rvstar":
  627. machine = "gd32vf103_rvstar"
  628. elif build_board == "gd32vf103v_eval":
  629. machine = "gd32vf103_eval"
  630. else:
  631. machine = "nuclei_evalsoc"
  632. # machine combined with download
  633. machine = machine + ",download=%s" %(build_download.lower())
  634. else:
  635. machine = qemu_machine
  636. if qemu_cpu is None:
  637. qemu_sel_cpu = "nuclei-%s" % (build_core.lower())
  638. if build_arch_ext != "":
  639. qemu_sel_cpu = qemu_sel_cpu + ",ext=%s" %(build_arch_ext)
  640. else:
  641. qemu_sel_cpu = qemu_cpu
  642. if "rv64" in build_info["RISCV_ARCH"]:
  643. qemu_exe = qemu64_exe
  644. timeout = hwconfig.get("timeout", 60)
  645. runner = None
  646. cmdsts = False
  647. sdk_check = get_sdk_check()
  648. if qemu_exe:
  649. if os.path.isfile(build_objects["elf"]):
  650. vercmd = "%s --version" % (qemu_exe)
  651. verchk = "QEMU emulator version"
  652. ret, verstr = check_tool_version(vercmd, verchk)
  653. if ret:
  654. command = "%s %s -M %s -cpu %s -nodefaults -nographic -icount shift=0 -serial stdio -kernel %s" \
  655. % (qemu_exe, qemu_extraopt, machine, qemu_sel_cpu, build_objects["elf"])
  656. print("Run command: %s" %(command))
  657. runner = {"cmd": command, "version": verstr}
  658. cmdsts, _ = run_cmd_and_check(command, timeout, app_runchecks, checktime, \
  659. sdk_check, logfile, show_output)
  660. else:
  661. print("%s doesn't exist in PATH, please check!" % qemu_exe)
  662. else:
  663. print("ELF file %s doesn't exist, can't run on qemu" % (build_objects["elf"]))
  664. final_status = cmdsts
  665. return final_status, runner
  666. def run_app_onxlmodel(self, appdir, runcfg:dict(), show_output=True, logfile=None):
  667. app_runcfg = runcfg.get("run_config", dict())
  668. app_runchecks = runcfg.get("checks", dict())
  669. build_info = runcfg["misc"]["build_info"]
  670. build_config = runcfg["misc"]["build_config"]
  671. build_objects = runcfg["misc"]["build_objects"]
  672. checktime = runcfg["misc"]["build_time"]
  673. hwconfig = app_runcfg.get("xlmodel", dict())
  674. timeout = 300 # xlmodel is slow compared with qemu
  675. xlmodel_exe = None
  676. xlmodel_extraopt = ""
  677. if hwconfig is not None:
  678. xlmodel_exe = hwconfig.get("xlmodel", "xl_cpumodel")
  679. xlmodel_machine = hwconfig.get("machine", "nuclei_evalsoc")
  680. xlmodel_cpu = hwconfig.get("xlmodel_cpu", None)
  681. build_soc = build_info["SOC"]
  682. build_board = build_info["BOARD"]
  683. build_core = build_info["CORE"]
  684. build_download = build_info["DOWNLOAD"]
  685. build_smp = build_info.get("SMP", "")
  686. build_arch_ext = build_config.get("ARCH_EXT", "")
  687. build_semihost = False
  688. if build_config.get("SEMIHOST", "") != "":
  689. build_semihost = True
  690. if build_arch_ext == "":
  691. build_arch_ext = build_info.get("ARCH_EXT", "")
  692. if build_smp != "":
  693. xlmodel_extraopt = "%s --smp=%s" % (xlmodel_extraopt, build_smp)
  694. #if build_semihost: # use xlmodel semihosting, if program build with semihost feature
  695. # xlmodel_extraopt = "%s -semihosting " % (xlmodel_extraopt)
  696. if xlmodel_cpu is None:
  697. xlmodel_sel_cpu = "%s" % (build_core.lower())
  698. xlmodel_archext_opt = ""
  699. if build_arch_ext and build_arch_ext.strip() != "":
  700. xlmodel_archext_opt = "--ext=%s" % (build_arch_ext)
  701. timeout = hwconfig.get("timeout", timeout)
  702. runner = None
  703. cmdsts = False
  704. sdk_check = get_sdk_check()
  705. if xlmodel_exe:
  706. if os.path.isfile(build_objects["elf"]):
  707. vercmd = "%s -v" % (xlmodel_exe)
  708. verchk = "xl_cpumodel Version"
  709. ret, verstr = check_tool_version(vercmd, verchk)
  710. if ret:
  711. command = "%s %s -M %s --cpu=%s %s %s" \
  712. % (xlmodel_exe, xlmodel_extraopt, xlmodel_machine, xlmodel_sel_cpu, xlmodel_archext_opt, build_objects["elf"])
  713. print("Run command: %s" %(command))
  714. runner = {"cmd": command, "version": verstr}
  715. cmdsts, _ = run_cmd_and_check(command, timeout, app_runchecks, checktime, \
  716. sdk_check, logfile, show_output)
  717. else:
  718. print("%s doesn't exist in PATH, please check!" % xlmodel_exe)
  719. else:
  720. print("ELF file %s doesn't exist, can't run on xlmodel" % (build_objects["elf"]))
  721. final_status = cmdsts
  722. return final_status, runner
  723. def run_app_onxlspike(self, appdir, runcfg:dict(), show_output=True, logfile=None):
  724. app_runcfg = runcfg.get("run_config", dict())
  725. app_runchecks = runcfg.get("checks", dict())
  726. build_info = runcfg["misc"]["build_info"]
  727. build_config = runcfg["misc"]["build_config"]
  728. build_objects = runcfg["misc"]["build_objects"]
  729. checktime = runcfg["misc"]["build_time"]
  730. hwconfig = app_runcfg.get("xlspike", dict())
  731. timeout = 300 # xlspike is slow compared with qemu
  732. xlspike_exe = None
  733. xlspike_extraopt = ""
  734. if hwconfig is not None:
  735. xlspike_exe = hwconfig.get("xlspike", "xl_spike")
  736. build_soc = build_info["SOC"]
  737. build_board = build_info["BOARD"]
  738. riscv_arch = build_info["RISCV_ARCH"]
  739. # replace e with i for xlspike
  740. riscv_arch = riscv_arch.replace("e", "i")
  741. build_arch_ext = build_info.get("ARCH_EXT", "")
  742. build_smp = build_info.get("SMP", "")
  743. if build_smp != "":
  744. xlspike_extraopt = "%s -p%s" % (xlspike_extraopt, build_smp)
  745. if not is_nuclei_evalsoc(build_soc):
  746. xlspike_exe = None
  747. print("SOC=%s BOARD=%s is not supported by xlspike" % (build_soc, build_board))
  748. timeout = hwconfig.get("timeout", timeout)
  749. runner = None
  750. cmdsts = False
  751. sdk_check = get_sdk_check()
  752. if xlspike_exe:
  753. if os.path.isfile(build_objects["elf"]):
  754. vercmd = "%s --help" % (xlspike_exe)
  755. verchk = "RISC-V ISA Simulator"
  756. ret, verstr = check_tool_version(vercmd, verchk)
  757. if ret:
  758. command = "%s %s --isa %s%s %s" % (xlspike_exe, xlspike_extraopt, riscv_arch, build_arch_ext, build_objects["elf"])
  759. print("Run command: %s" %(command))
  760. runner = {"cmd": command, "version": verstr}
  761. cmdsts, _ = run_cmd_and_check(command, timeout, app_runchecks, checktime, \
  762. sdk_check, logfile, show_output)
  763. else:
  764. print("%s doesn't exist in PATH, please check!" % xlspike_exe)
  765. else:
  766. print("ELF file %s doesn't exist, can't run on xlspike" % (build_objects["elf"]))
  767. else:
  768. print("Can't run on xlspike due to run config not exist or config not supported")
  769. final_status = cmdsts
  770. return final_status, runner
  771. def run_app_onncycm(self, appdir, runcfg:dict(), show_output=True, logfile=None):
  772. app_runcfg = runcfg.get("run_config", dict())
  773. app_runchecks = runcfg.get("checks", dict())
  774. build_info = runcfg["misc"]["build_info"]
  775. build_config = runcfg["misc"]["build_config"]
  776. build_objects = runcfg["misc"]["build_objects"]
  777. checktime = runcfg["misc"]["build_time"]
  778. hwconfig = app_runcfg.get("ncycm", dict())
  779. timeout = 600 # ncycm is slow compared with xlmodel or xlspike
  780. ncycm_exe = None
  781. if hwconfig is not None:
  782. ncycm_exe = hwconfig.get("ncycm", "ncycm")
  783. timeout = hwconfig.get("timeout", timeout)
  784. runner = None
  785. cmdsts = False
  786. sdk_check = get_sdk_check()
  787. if ncycm_exe:
  788. if os.path.isfile(build_objects["elf"]):
  789. vercmd = "%s -v" % (ncycm_exe)
  790. verchk = "version:"
  791. ret, verstr = check_tool_version(vercmd, verchk)
  792. if ret == False:
  793. verstr = "v1"
  794. ret = check_tool_exist(ncycm_exe) or os.path.isfile(ncycm_exe)
  795. if ret:
  796. if (verstr == "v1"):
  797. ncycm_verilog = fix_evalsoc_verilog_ncycm(build_objects["verilog"])
  798. if ncycm_verilog == "":
  799. command = ""
  800. else:
  801. command = "%s +TESTCASE=%s" % (ncycm_exe, ncycm_verilog)
  802. else:
  803. command = "%s %s" % (ncycm_exe, build_objects["elf"])
  804. if command != "":
  805. print("Run command: %s" %(command))
  806. runner = {"cmd": command, "version": verstr}
  807. cmdsts, _ = run_cmd_and_check(command, timeout, app_runchecks, checktime, \
  808. sdk_check, logfile, show_output, 480)
  809. else:
  810. print("Unable to run cycle model with %s" % (build_objects["elf"]))
  811. cmdsts = False
  812. else:
  813. print("%s doesn't exist in PATH, please check!" % ncycm_exe)
  814. else:
  815. print("ELF file %s doesn't exist, can't run on xlspike" % (build_objects["elf"]))
  816. else:
  817. print("Can't run on xlspike due to run config not exist or config not supported")
  818. final_status = cmdsts
  819. return final_status, runner
  820. def build_app_with_config(self, appdir, appconfig:dict, show_output=True, logfile=None):
  821. build_config = appconfig.get("build_config", None)
  822. target = appconfig.get("build_target", "all")
  823. parallel = appconfig.get("parallel", "")
  824. # Copy program objects if copy_objects is true
  825. copy_objects_required = get_sdk_need_copyobjects(appconfig)
  826. make_options = ""
  827. if isinstance(build_config, dict):
  828. for key, value in build_config.items():
  829. value = str(value).strip()
  830. if " " in key:
  831. continue
  832. if " " in value:
  833. make_options += " %s=\"%s\""%(key, value)
  834. else:
  835. make_options += " %s=%s"%(key, value)
  836. appcmdsts, appsts = self.build_target(appdir, make_options, target, show_output, logfile, parallel)
  837. objs_copydir = os.path.dirname(logfile) # where objects are copied to
  838. # copy objects if copy_objects_required
  839. if copy_objects_required:
  840. nsdk_builder.copy_objects(appsts, objs_copydir)
  841. buildtime = appsts["time"]["build"]
  842. print("Build application %s with target %s, make options %s, time cost %s seconds, passed: %s" %(appdir, target, make_options, buildtime, appcmdsts))
  843. sys.stdout.flush()
  844. appsts["config"] = appconfig
  845. return appcmdsts, appsts
  846. def run_app_with_config(self, appdir, appconfig:dict, show_output=True, buildlog=None, runlog=None):
  847. appconfig["build_target"] = "clean dasm"
  848. # build application
  849. build_cktime = time.time()
  850. appcmdsts, appsts = self.build_app_with_config(appdir, appconfig, show_output, buildlog)
  851. # run application
  852. if appcmdsts == False:
  853. print("Failed to build application %s, so we can't run it!" % (appdir))
  854. return appcmdsts, appsts
  855. # get run config
  856. app_runcfg = appconfig.get("run_config", dict())
  857. app_runtarget = app_runcfg.get("target", "hardware")
  858. app_parsescript = app_runcfg.get("parsescript", None)
  859. if app_parsescript is not None:
  860. if os.path.isfile(app_parsescript) == False:
  861. app_parsescript = os.path.join(appdir, app_parsescript)
  862. # get run checks
  863. DEFAULT_CHECKS = { "PASS": [ ], "FAIL": [ "MCAUSE:" ] }
  864. app_runchecks = appconfig.get("checks", DEFAULT_CHECKS)
  865. misc_config = {"make_options": appsts["app"]["make_options"], "build_config": appconfig["build_config"],\
  866. "build_info": appsts["info"], "build_objects": appsts["objects"], "build_time": build_cktime}
  867. runcfg = {"run_config": app_runcfg, "checks": app_runchecks, "misc": misc_config}
  868. # get copy fail objects flags
  869. copy_objects_required = get_sdk_need_copyobjects(appconfig)
  870. copy_failobj_required = get_sdk_copy_failobj()
  871. print("Run application on %s" % app_runtarget)
  872. runstarttime = time.time()
  873. runstatus = False
  874. ignorehw = False
  875. appsts["status_code"]["run"] = RUNSTATUS_NOTSTART
  876. if app_runtarget == "hardware":
  877. uploadlog = None
  878. if runlog:
  879. uploadlog = os.path.join(os.path.dirname(runlog), "upload.log")
  880. runstatus, uploader = self.run_app_onhw(appdir, runcfg, show_output, runlog, uploadlog)
  881. # If run successfully, then do log analyze
  882. if runlog and runstatus:
  883. appsts["result"] = self.analyze_runlog(runlog, app_parsescript)
  884. appsts["logs"]["run"] = runlog
  885. appsts["logs"]["upload"] = uploadlog
  886. appsts["status_code"]["run"] = RUNSTATUS_OK if runstatus else RUNSTATUS_FAIL
  887. if uploader:
  888. appsts["app"]["uploader"] = uploader
  889. elif app_runtarget == "qemu":
  890. runstatus, runner = self.run_app_onqemu(appdir, runcfg, show_output, runlog)
  891. # If run successfully, then do log analyze
  892. if runlog and runstatus:
  893. appsts["result"] = self.analyze_runlog(runlog, app_parsescript)
  894. appsts["logs"]["run"] = runlog
  895. appsts["status_code"]["run"] = RUNSTATUS_OK if runstatus else RUNSTATUS_FAIL
  896. if runner:
  897. appsts["app"]["qemu"] = runner
  898. elif app_runtarget == "xlmodel":
  899. runstatus, runner = self.run_app_onxlmodel(appdir, runcfg, show_output, runlog)
  900. # If run successfully, then do log analyze
  901. if runlog and runstatus:
  902. appsts["result"] = self.analyze_runlog(runlog, app_parsescript)
  903. appsts["logs"]["run"] = runlog
  904. appsts["status_code"]["run"] = RUNSTATUS_OK if runstatus else RUNSTATUS_FAIL
  905. if runner:
  906. appsts["app"]["xlmodel"] = runner
  907. elif app_runtarget == "xlspike":
  908. runstatus, runner = self.run_app_onxlspike(appdir, runcfg, show_output, runlog)
  909. # If run successfully, then do log analyze
  910. if runlog and runstatus:
  911. appsts["result"] = self.analyze_runlog(runlog, app_parsescript)
  912. appsts["logs"]["run"] = runlog
  913. appsts["status_code"]["run"] = RUNSTATUS_OK if runstatus else RUNSTATUS_FAIL
  914. if runner:
  915. appsts["app"]["xlspike"] = runner
  916. elif app_runtarget == "ncycm":
  917. runstatus, runner = self.run_app_onncycm(appdir, runcfg, show_output, runlog)
  918. # If run successfully, then do log analyze
  919. if runlog and runstatus:
  920. appsts["result"] = self.analyze_runlog(runlog, app_parsescript)
  921. appsts["logs"]["run"] = runlog
  922. appsts["status_code"]["run"] = RUNSTATUS_OK if runstatus else RUNSTATUS_FAIL
  923. if runner:
  924. appsts["app"]["ncycm"] = runner
  925. else:
  926. print("Unsupported run target %s" %(app_runtarget))
  927. ignorehw = True
  928. # only do copy when needed, fail copy enabled and copy objects disabled
  929. if copy_failobj_required == True and copy_objects_required == False \
  930. and runstatus == False and ignorehw == False and runlog is not None:
  931. objs_copydir = os.path.dirname(runlog) # where objects are copied to
  932. nsdk_builder.copy_objects(appsts, objs_copydir)
  933. runtime = round(time.time() - runstarttime, 2)
  934. print("Run application %s on %s, time cost %s seconds, passed: %s" %(appdir, app_runtarget, runtime, runstatus))
  935. sys.stdout.flush()
  936. appsts["status"]["run"] = runstatus
  937. appsts["time"]["run"] = runtime
  938. return runstatus, appsts
  939. def build_apps_with_config(self, config:dict, show_output=True, logdir=None, stoponfail=False):
  940. # Build all the applications, each application only has one configuration
  941. # "app" : { the_only_config }
  942. cmdsts = True
  943. build_status = dict()
  944. apps_config = copy.deepcopy(config)
  945. for appdir in apps_config:
  946. appconfig = apps_config[appdir]
  947. applogs = appconfig.get("logs", dict())
  948. applogfile = applogs.get("build", None)
  949. appcmdsts, appsts = self.build_app_with_config(appdir, appconfig, show_output, applogfile)
  950. build_status[appdir] = appsts
  951. if appcmdsts == False:
  952. if stoponfail == True:
  953. cmdsts = appcmdsts
  954. print("Stop build apps with config due to fail on application %s" %(appdir))
  955. return cmdsts, build_status
  956. return cmdsts, build_status
  957. def build_apps_with_configs(self, config:dict, show_output=True, logdir=None, stoponfail=False):
  958. # Build all the applications, each application has more than one configuration
  959. # "app" : {"configs": {"case1": case1_config}}
  960. cmdsts = True
  961. build_status = dict()
  962. apps_config = copy.deepcopy(config)
  963. for appdir in apps_config:
  964. appconfigs = apps_config[appdir]
  965. if "configs" not in appconfigs:
  966. continue
  967. build_status[appdir] = dict()
  968. app_allconfigs = appconfigs["configs"]
  969. for cfgname in app_allconfigs:
  970. appconfig = app_allconfigs[cfgname] # get configuration for each case for single app
  971. applogs = appconfig.get("logs", dict())
  972. applogfile = applogs.get("build", None)
  973. appcmdsts, appsts = self.build_app_with_config(appdir, appconfig, show_output, applogfile)
  974. build_status[appdir][cfgname] = appsts
  975. if appcmdsts == False:
  976. if stoponfail == True:
  977. cmdsts = appcmdsts
  978. print("Stop build apps with config due to fail on application %s" %(appdir))
  979. return cmdsts, build_status
  980. return cmdsts, build_status
  981. def run_apps_with_config(self, config:dict, show_output=True, stoponfail=False):
  982. # Run all the applications, each application only has one configuration
  983. # "app" : { the_only_config }
  984. cmdsts = True
  985. # reset error counters
  986. self.reset_counters()
  987. build_status = dict()
  988. apps_config = copy.deepcopy(config)
  989. for appdir in apps_config:
  990. appconfig = apps_config[appdir]
  991. # Used to filter application with certain pattern not acceptable
  992. filtered, reason = filter_app_config(appconfig)
  993. if filtered:
  994. print("INFO: Ignore this app config %s for application %s" % (reason, appdir))
  995. continue
  996. applogs = appconfig.get("logs", dict())
  997. app_buildlogfile = applogs.get("build", None)
  998. app_runlogfile = applogs.get("run", None)
  999. appcmdsts, appsts = self.run_app_with_config(appdir, appconfig, show_output, app_buildlogfile, app_runlogfile)
  1000. build_status[appdir] = appsts
  1001. if appcmdsts == False:
  1002. if stoponfail == True:
  1003. cmdsts = appcmdsts
  1004. print("ERROR: Stop run apps with config due to fail on application %s" %(appdir))
  1005. return cmdsts, build_status
  1006. # error exit check
  1007. if self.need_exit_now():
  1008. print("ERROR: Need to exit now due to error counter exceed limit!")
  1009. self.show_counters()
  1010. cmdsts = False
  1011. return cmdsts, build_status
  1012. return cmdsts, build_status
  1013. def run_apps_with_configs(self, config:dict, show_output=True, stoponfail=False):
  1014. # Run all the applications, each application has more than one configuration
  1015. # "app" : {"configs": {"case1": case1_config}}
  1016. cmdsts = True
  1017. # reset error counters
  1018. self.reset_counters()
  1019. build_status = dict()
  1020. apps_config = copy.deepcopy(config)
  1021. for appdir in apps_config:
  1022. appconfigs = apps_config[appdir]
  1023. if "configs" not in appconfigs:
  1024. continue
  1025. build_status[appdir] = dict()
  1026. app_allconfigs = appconfigs["configs"]
  1027. for cfgname in app_allconfigs:
  1028. appconfig = app_allconfigs[cfgname] # get configuration for each case for single app
  1029. # Used to filter application with certain pattern not acceptable
  1030. filtered, reason = filter_app_config(appconfig)
  1031. if filtered:
  1032. print("INFO: Ignore this app config %s for application %s" % (reason, appdir))
  1033. continue
  1034. applogs = appconfig.get("logs", dict())
  1035. app_buildlogfile = applogs.get("build", None)
  1036. app_runlogfile = applogs.get("run", None)
  1037. appcmdsts, appsts = self.run_app_with_config(appdir, appconfig, show_output, app_buildlogfile, app_runlogfile)
  1038. build_status[appdir][cfgname] = appsts
  1039. if appcmdsts == False:
  1040. if stoponfail == True:
  1041. cmdsts = appcmdsts
  1042. print("ERROR: Stop run apps with config due to fail on application %s" %(appdir))
  1043. return cmdsts, build_status
  1044. # error exit check
  1045. if self.need_exit_now():
  1046. print("ERROR: Need to exit now due to error counter exceed limit!")
  1047. self.show_counters()
  1048. cmdsts = False
  1049. return cmdsts, build_status
  1050. return cmdsts, build_status