from flask import Flask, render_template, abort, send_file from flask_assets import Environment, Bundle import os import json from typing import List import markdown as md app = Flask(__name__) assets = Environment(app) assets.url = app.static_url_path scss = Bundle('style/main.scss', filters='libsass', output='all.css', depends='**/*.scss') assets.config['PYSCSS_LOAD_PATHS'] = assets.load_path assets.config['PYSCSS_STATIC_URL'] = assets.url assets.config['PYSCSS_STATIC_ROOT'] = assets.directory assets.config['PYSCSS_ASSETS_URL'] = assets.url assets.config['PYSCSS_ASSETS_ROOT'] = assets.directory assets.register('scss_all', scss) class ArtifactItem: file: str description: str def __init__(self, file, description): self.file = file self.description = description class Artifact: id: str date: str changelog: str artifacts: List[ArtifactItem] def __init__(self, id, date, changelog, artifacts): self.id = id self.date = date self.changelog = changelog self.artifacts = [ArtifactItem(**item) for item in artifacts] @classmethod def from_json(cls, json_str): json_dict = json.loads(json_str) return cls(**json_dict) class ProjectInfo: name: str def __init__(self, name): self.name = name @classmethod def from_json(cls, json_str): json_dict = json.loads(json_str) return cls(**json_dict) class Project: id: str info: ProjectInfo def get_artifacts(self) -> List[Artifact]: result = [] artifacts_path = os.path.join("../builds", self.id, "artifacts") artifact_folders = sorted([folder.path for folder in os.scandir( artifacts_path) if folder.is_dir()], reverse=True) for artifact_folder in artifact_folders: info_file_path = os.path.join(artifact_folder, "info.json") if not os.path.exists(info_file_path): continue try: with open(info_file_path, "r", encoding="utf-8") as f: artifact = Artifact.from_json(f.read()) result.append(artifact) except: continue return result def get_projects() -> List[Project]: result = [] projects = [f.path for f in os.scandir("../builds") if f.is_dir()] for project in projects: info_path = os.path.join(project, "info.json") if not os.path.exists(info_path): continue try: proj = Project() _, proj.id = os.path.split(project) with open(info_path, "r", encoding="utf-8") as f: proj.info = ProjectInfo.from_json(f.read()) result.append(proj) except: continue return result @app.route("/projects///") def download_item(project_id, artifact_id, download_item): file_path = os.path.join("../builds", project_id, "artifacts", artifact_id, download_item) if not os.path.exists(file_path): return abort(404) return send_file(file_path) @app.route("/projects/") def display_project(project_id): projects = get_projects() selected_project = next( (project for project in projects if project.id == project_id), None) if not selected_project: return abort(404) info_path = os.path.join("../builds", selected_project.id, "info.md") readme = None try: if os.path.exists(info_path): with open(info_path, "r", encoding="utf-8") as f: readme = md.markdown(f.read()) except: readme = None artifacts = selected_project.get_artifacts() return render_template("project_view.html", projects=projects, selected_project=selected_project, readme=readme, artifacts=artifacts) @app.route("/") def index(): projects = get_projects() return render_template("main.html", projects=projects) if __name__ == "__main__": app.run(host='0.0.0.0')