app.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. from flask import Flask, render_template, abort, send_file
  2. from flask_assets import Environment, Bundle
  3. import os
  4. import json
  5. from typing import List
  6. import markdown as md
  7. app = Flask(__name__)
  8. assets = Environment(app)
  9. assets.url = app.static_url_path
  10. scss = Bundle('style/main.scss', filters='libsass',
  11. output='all.css', depends='**/*.scss')
  12. assets.config['PYSCSS_LOAD_PATHS'] = assets.load_path
  13. assets.config['PYSCSS_STATIC_URL'] = assets.url
  14. assets.config['PYSCSS_STATIC_ROOT'] = assets.directory
  15. assets.config['PYSCSS_ASSETS_URL'] = assets.url
  16. assets.config['PYSCSS_ASSETS_ROOT'] = assets.directory
  17. assets.register('scss_all', scss)
  18. class ArtifactItem:
  19. file: str
  20. description: str
  21. width: int = 0
  22. def __init__(self, file, description):
  23. self.file = file
  24. self.description = description
  25. class Artifact:
  26. id: str
  27. date: str
  28. changelog: str
  29. artifacts: List[ArtifactItem]
  30. def __init__(self, id, date, changelog, artifacts):
  31. self.id = id
  32. self.date = date
  33. self.changelog = changelog
  34. self.artifacts = [ArtifactItem(**item)
  35. for item in artifacts]
  36. maxwidth = max((len(a.file) for a in self.artifacts), default=0)
  37. for a in self.artifacts:
  38. a.width = maxwidth
  39. @classmethod
  40. def from_json(cls, json_str):
  41. json_dict = json.loads(json_str)
  42. return cls(**json_dict)
  43. class ProjectInfo:
  44. name: str
  45. def __init__(self, name):
  46. self.name = name
  47. @classmethod
  48. def from_json(cls, json_str):
  49. json_dict = json.loads(json_str)
  50. return cls(**json_dict)
  51. class Project:
  52. id: str
  53. info: ProjectInfo
  54. def get_artifacts(self) -> List[Artifact]:
  55. result = []
  56. artifacts_path = os.path.join("../builds", self.id, "artifacts")
  57. artifact_folders = sorted([folder.path for folder in os.scandir(
  58. artifacts_path) if folder.is_dir()], reverse=True)
  59. for artifact_folder in artifact_folders:
  60. info_file_path = os.path.join(artifact_folder, "info.json")
  61. if not os.path.exists(info_file_path):
  62. continue
  63. try:
  64. with open(info_file_path, "r", encoding="utf-8") as f:
  65. artifact = Artifact.from_json(f.read())
  66. result.append(artifact)
  67. except:
  68. continue
  69. return result
  70. def get_projects() -> List[Project]:
  71. result = []
  72. projects = [f.path for f in os.scandir("../builds") if f.is_dir()]
  73. for project in projects:
  74. info_path = os.path.join(project, "info.json")
  75. if not os.path.exists(info_path):
  76. continue
  77. try:
  78. proj = Project()
  79. _, proj.id = os.path.split(project)
  80. with open(info_path, "r", encoding="utf-8") as f:
  81. proj.info = ProjectInfo.from_json(f.read())
  82. result.append(proj)
  83. except:
  84. continue
  85. return result
  86. @app.route("/projects/<string:project_id>/<string:artifact_id>/<string:download_item>")
  87. def download_item(project_id, artifact_id, download_item):
  88. file_path = os.path.join("../builds", project_id,
  89. "artifacts", artifact_id, download_item)
  90. if not os.path.exists(file_path):
  91. return abort(404)
  92. return send_file(file_path)
  93. @app.route("/projects/<string:project_id>")
  94. def display_project(project_id):
  95. projects = get_projects()
  96. selected_project = next(
  97. (project for project in projects if project.id == project_id), None)
  98. if not selected_project:
  99. return abort(404)
  100. info_path = os.path.join("../builds", selected_project.id, "info.md")
  101. readme = None
  102. try:
  103. if os.path.exists(info_path):
  104. with open(info_path, "r", encoding="utf-8") as f:
  105. readme = md.markdown(f.read())
  106. except:
  107. readme = None
  108. artifacts = selected_project.get_artifacts()
  109. return render_template("project_view.html", projects=projects, selected_project=selected_project, readme=readme, artifacts=artifacts)
  110. @app.route("/")
  111. def index():
  112. projects = get_projects()
  113. return render_template("main.html", projects=projects)
  114. @app.template_filter('timestamp')
  115. def timestamp_filter(filename):
  116. try:
  117. timestamp = str(os.path.getmtime(filename[1:]))
  118. except OSError:
  119. return filename
  120. newfilename = "{0}?v={1}".format(filename, timestamp)
  121. return newfilename
  122. if __name__ == "__main__":
  123. app.run(host='0.0.0.0')