import json import os import queue import re import threading import time from typing import Any from flask import ( Flask, abort, send_from_directory, stream_template, ) def get_project(project: str) -> dict[str, Any]: with open(f"./projects/{project}.json", "r") as p: return json.loads(p.read()) def get_run(project: str, run: int) -> str: with open(f"./stdout/public/{project}/{run}", "r") as r: return r.read() def stream_run(project: str, run: int): while True: with open(f"./stdout/public/{project}/{run}", "r") as r: txt = r.read() yield txt if "--MSCI_EXIT_" in txt: break time.sleep(0.5) def _projects(q: queue.Queue[tuple[str, dict[str, Any]] | None]): if os.path.isdir("./projects"): _projects = os.listdir("./projects") for _p in _projects: loaded = get_project(_p.replace(".json", "")) if not loaded["hidden"]: q.put((_p.replace(".json", ""), loaded)) else: os.mkdir("./projects") q.put(None) def projects(): q: queue.Queue[tuple[str, dict[str, Any]] | None] = queue.Queue() threading.Thread(target=_projects, args=(q,), daemon=True).start() while True: pr = q.get() if pr is None: break yield pr def _project_runs(project: str, q: queue.Queue[dict[str, Any] | None]): pr_stdout = f"./stdout/public/{project}" if os.path.isdir(pr_stdout): _runs = sorted(os.listdir(pr_stdout), key=int) for _r in _runs: run_str = get_run(project, int(_r)) run_date = re.search(r"--MSCI_DATE\((.*?)\)--", run_str) run_status = ( True if "--MSCI_EXIT_SUCCESS--" in run_str else False if "--MSCI_EXIT_FAILURE--" in run_str else None ) run_data = { "number": int(_r), "date": run_date.group(1) if run_date else None, "status": run_status, } q.put(run_data) q.put(None) def project_runs(project: str): q: queue.Queue[dict[str, Any] | None] = queue.Queue() threading.Thread( target=_project_runs, args=( project, q, ), daemon=True, ).start() while True: pr = q.get() if pr is None: break yield pr def project_exists(name: str): return ( os.path.isfile(f"./projects/{name}.json") and get_project(name)["hidden"] == False ) def run_exists(project: str, run: int): if project_exists(project): if not os.path.isfile(f"./stdout/public/{project}/{run}"): return False return True return False app = Flask(__name__) @app.route("/favicon.ico") def favicon(): return send_from_directory( app.root_path, "favicon.ico", mimetype="image/vnd.microsoft.icon", ) @app.route("/", methods=["GET"]) def home(): return stream_template("home.html", projects=projects()) @app.route("/", methods=["GET"]) def project(project: str): if project_exists(project): return stream_template( "project.html", project=get_project(project), project_path=project, runlist=project_runs(project), ) abort(404) @app.route("//", methods=["GET"]) def run(project: str, run: int): if run_exists(project, run): return stream_template( "run.html", project=get_project(project), project_path=project, run=stream_run(project, run), run_number=run, ) abort(404)