diff options
| author | toufic ar <contact@toufy.me> | 2026-05-15 02:24:12 +0300 |
|---|---|---|
| committer | toufic ar <contact@toufy.me> | 2026-05-15 02:24:12 +0300 |
| commit | fda7315f43b02cfae3050ece68a4d7cb26a826b4 (patch) | |
| tree | def28890a3c92cd7c2cb53d01f8e76c74fe362e7 /web/__init__.py | |
| parent | b36868f1fc3a6df0da4d931f94f3c39f1c50ee59 (diff) | |
| download | makeshiftci-fda7315f43b02cfae3050ece68a4d7cb26a826b4.tar.gz makeshiftci-fda7315f43b02cfae3050ece68a4d7cb26a826b4.zip | |
restructure webUI
Diffstat (limited to 'web/__init__.py')
| -rw-r--r-- | web/__init__.py | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/web/__init__.py b/web/__init__.py new file mode 100644 index 0000000..3daef78 --- /dev/null +++ b/web/__init__.py @@ -0,0 +1,166 @@ +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, +) + +MSCI_HOME = os.environ.get("MSCI_HOME") + + +def get_project(project: str) -> dict[str, Any]: + with open(f"{MSCI_HOME}/projects/{project}.json", "r") as p: + return json.loads(p.read()) + + +def get_run(project: str, run: int) -> str: + with open(f"{MSCI_HOME}/stdout/public/{project}/{run}", "r") as r: + return r.read() + + +def stream_run(project: str, run: int): + while True: + with open(f"{MSCI_HOME}/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(f"{MSCI_HOME}/projects"): + _projects = os.listdir(f"{MSCI_HOME}/projects") + for _p in _projects: + loaded = get_project(_p.replace(".json", "")) + if not loaded["hidden"]: + q.put((_p.replace(".json", ""), loaded)) + else: + os.mkdir(f"{MSCI_HOME}/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"{MSCI_HOME}/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"{MSCI_HOME}/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"{MSCI_HOME}/stdout/public/{project}/{run}"): + return False + return True + return False + + +_app = Flask(__name__) +_empty = Flask(__name__) + + +@_empty.route("/", methods=["GET"]) +def ey(): + return "MSCI_HOME not set" + + +@_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("/<string:project>", 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("/<string:project>/<int:run>", 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) + + +def create_app(): + if not MSCI_HOME: + return _empty + else: + return _app |
