app.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. from flask import Flask, render_template, abort, send_file, jsonify
  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. @dataclass
  14. class Artifact(DataClassJsonMixin):
  15. id: str
  16. date: str
  17. changelog: str
  18. artifacts: List[ArtifactItem]
  19. hash: str = None
  20. @dataclass
  21. class ProjectInfo(DataClassJsonMixin):
  22. name: str
  23. commit_url: str
  24. class Project:
  25. id: str
  26. info: ProjectInfo
  27. def get_artifacts(self) -> List[Artifact]:
  28. result = []
  29. artifacts_path = os.path.join("../builds", self.id, "artifacts")
  30. artifact_folders = sorted([folder.path for folder in os.scandir(
  31. artifacts_path) if folder.is_dir()], reverse=True)
  32. for artifact_folder in artifact_folders:
  33. info_file_path = os.path.join(artifact_folder, "info.json")
  34. artifact = self._parse_artifact(info_file_path)
  35. if artifact:
  36. result.append(artifact)
  37. return result
  38. def get_lastest_artifact(self) -> Artifact:
  39. artifacts_path = os.path.join("../builds", self.id, "artifacts")
  40. artifact_folders = sorted([folder.path for folder in os.scandir(
  41. artifacts_path) if folder.is_dir()], reverse=True)
  42. if not artifact_folders:
  43. return None
  44. latest_artifact_folder = max(artifact_folders)
  45. info_file_path = os.path.join(latest_artifact_folder, "info.json")
  46. return self._parse_artifact(info_file_path)
  47. def get_artifact(self, artifact_id) -> Artifact:
  48. artifact_folder = os.path.join("../builds", self.id, "artifacts", artifact_id)
  49. if not os.path.isdir(artifact_folder):
  50. return None
  51. info_file_path = os.path.join(artifact_folder, "info.json")
  52. return self._parse_artifact(info_file_path)
  53. def _parse_artifact(self, info_file_path):
  54. if not os.path.exists(info_file_path):
  55. return None
  56. try:
  57. with open(info_file_path, "r", encoding="utf-8") as f:
  58. artifact = Artifact.from_json(f.read())
  59. artifact.date = artifact.date.strip()
  60. return artifact
  61. except:
  62. return None
  63. def get_projects() -> List[Project]:
  64. result = []
  65. projects = [f.path for f in os.scandir("../builds") if f.is_dir()]
  66. for project in projects:
  67. info_path = os.path.join(project, "info.json")
  68. if not os.path.exists(info_path):
  69. continue
  70. try:
  71. proj = Project()
  72. _, proj.id = os.path.split(project)
  73. with open(info_path, "r", encoding="utf-8") as f:
  74. proj.info = ProjectInfo.from_json(f.read())
  75. result.append(proj)
  76. except:
  77. continue
  78. return result
  79. @app.route("/api/projects/<string:project_id>/artifacts/latest")
  80. def get_latest_artifact(project_id):
  81. projects = get_projects()
  82. selected_project = next(
  83. (project for project in projects if project.id == project_id), None)
  84. if not selected_project:
  85. return abort(404)
  86. artifact = selected_project.get_lastest_artifact()
  87. if not artifact:
  88. return abort(404)
  89. return jsonify(artifact)
  90. @app.route("/api/projects/<string:project_id>/artifacts/<string:artifact_id>")
  91. def get_artifact_by_id(project_id, artifact_id):
  92. projects = get_projects()
  93. selected_project = next(
  94. (project for project in projects if project.id == project_id), None)
  95. if not selected_project:
  96. return abort(404)
  97. artifact = selected_project.get_artifact(artifact_id)
  98. if not artifact:
  99. return abort(404)
  100. return jsonify(artifact)
  101. @app.route("/projects/<string:project_id>/<string:artifact_id>/<string:download_item>")
  102. def download_item(project_id, artifact_id, download_item):
  103. file_path = os.path.join("../builds", project_id,
  104. "artifacts", artifact_id, download_item)
  105. if not os.path.exists(file_path):
  106. return abort(404)
  107. return send_file(file_path)
  108. @app.route("/projects/<string:project_id>")
  109. def display_project(project_id):
  110. projects = get_projects()
  111. selected_project = next(
  112. (project for project in projects if project.id == project_id), None)
  113. if not selected_project:
  114. return abort(404)
  115. info_path = os.path.join("../builds", selected_project.id, "info.md")
  116. readme = None
  117. try:
  118. if os.path.exists(info_path):
  119. with open(info_path, "r", encoding="utf-8") as f:
  120. readme = md.markdown(f.read())
  121. except:
  122. readme = None
  123. artifacts = selected_project.get_artifacts()
  124. return render_template("project_view.html", projects=projects, selected_project=selected_project, readme=readme, artifacts=artifacts)
  125. @app.route("/")
  126. def index():
  127. projects = get_projects()
  128. return render_template("main.html", projects=projects)
  129. if __name__ == "__main__":
  130. app.run(host='0.0.0.0')