app.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. from flask import Flask, render_template, abort, send_file
  2. import os
  3. import json
  4. from typing import List
  5. import markdown as md
  6. from dataclasses import dataclass
  7. from dataclasses_json import DataClassJsonMixin
  8. app = Flask(__name__)
  9. @dataclass
  10. class ArtifactItem(DataClassJsonMixin):
  11. file: str
  12. description: str
  13. width: int = 0
  14. @dataclass
  15. class Artifact(DataClassJsonMixin):
  16. id: str
  17. date: str
  18. changelog: str
  19. artifacts: List[ArtifactItem]
  20. hash: str = None
  21. @dataclass
  22. class ProjectInfo(DataClassJsonMixin):
  23. name: str
  24. commit_url: str
  25. class Project:
  26. id: str
  27. info: ProjectInfo
  28. def get_artifacts(self) -> List[Artifact]:
  29. result = []
  30. artifacts_path = os.path.join("../builds", self.id, "artifacts")
  31. artifact_folders = sorted([folder.path for folder in os.scandir(
  32. artifacts_path) if folder.is_dir()], reverse=True)
  33. for artifact_folder in artifact_folders:
  34. info_file_path = os.path.join(artifact_folder, "info.json")
  35. if not os.path.exists(info_file_path):
  36. continue
  37. try:
  38. with open(info_file_path, "r", encoding="utf-8") as f:
  39. artifact = Artifact.from_json(f.read())
  40. artifact.date = artifact.date.strip()
  41. maxwidth = max((len(a.file)
  42. for a in artifact.artifacts), default=0)
  43. for a in artifact.artifacts:
  44. a.width = maxwidth
  45. result.append(artifact)
  46. except:
  47. continue
  48. return result
  49. def get_projects() -> List[Project]:
  50. result = []
  51. projects = [f.path for f in os.scandir("../builds") if f.is_dir()]
  52. for project in projects:
  53. info_path = os.path.join(project, "info.json")
  54. if not os.path.exists(info_path):
  55. continue
  56. try:
  57. proj = Project()
  58. _, proj.id = os.path.split(project)
  59. with open(info_path, "r", encoding="utf-8") as f:
  60. proj.info = ProjectInfo.from_json(f.read())
  61. result.append(proj)
  62. except:
  63. continue
  64. return result
  65. @app.route("/projects/<string:project_id>/<string:artifact_id>/<string:download_item>")
  66. def download_item(project_id, artifact_id, download_item):
  67. file_path = os.path.join("../builds", project_id,
  68. "artifacts", artifact_id, download_item)
  69. if not os.path.exists(file_path):
  70. return abort(404)
  71. return send_file(file_path)
  72. @app.route("/projects/<string:project_id>")
  73. def display_project(project_id):
  74. projects = get_projects()
  75. selected_project = next(
  76. (project for project in projects if project.id == project_id), None)
  77. if not selected_project:
  78. return abort(404)
  79. info_path = os.path.join("../builds", selected_project.id, "info.md")
  80. readme = None
  81. try:
  82. if os.path.exists(info_path):
  83. with open(info_path, "r", encoding="utf-8") as f:
  84. readme = md.markdown(f.read())
  85. except:
  86. readme = None
  87. artifacts = selected_project.get_artifacts()
  88. return render_template("project_view.html", projects=projects, selected_project=selected_project, readme=readme, artifacts=artifacts)
  89. @app.route("/")
  90. def index():
  91. projects = get_projects()
  92. return render_template("main.html", projects=projects)
  93. if __name__ == "__main__":
  94. app.run(host='0.0.0.0')