app.py 5.0 KB

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