25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

205 lines
6.2 KiB

  1. """Automatically setup docs for a project
  2. Call from command line:
  3. bench setup-docs app path
  4. """
  5. import os, json, frappe, markdown2, shutil
  6. import frappe.website.statics
  7. from frappe.website.context import get_context
  8. class setup_docs(object):
  9. def __init__(self, app, docs_version, target):
  10. """Generate source templates for models reference and module API
  11. and templates at `templates/autodoc`
  12. """
  13. self.app = app
  14. self.path = frappe.get_app_path(app, "docs", docs_version)
  15. self.target = target
  16. # build apis
  17. # self.build()
  18. # sync docs
  19. sync = frappe.website.statics.sync()
  20. sync.start(path="docs", rebuild=True)
  21. # write in target path
  22. self.write_files()
  23. def build(self):
  24. hooks = frappe.get_hooks(app_name = self.app)
  25. self.app_title = hooks.get("app_title")[0]
  26. self.app_path = frappe.get_app_path(self.app)
  27. print "Deleting current..."
  28. shutil.rmtree(self.path, ignore_errors = True)
  29. os.makedirs(self.path)
  30. self.app_context = {
  31. "app": {
  32. "name": self.app,
  33. "title": self.app_title,
  34. "description": markdown2.markdown(hooks.get("app_description")[0]),
  35. "version": hooks.get("app_version")[0],
  36. "publisher": hooks.get("app_publisher")[0],
  37. "github_link": hooks.get("github_link")[0],
  38. }
  39. }
  40. # make home page
  41. with open(os.path.join(self.path, "index.html"), "w") as home:
  42. home.write(frappe.render_template("templates/autodoc/docs_home.html",
  43. self.app_context))
  44. # make folders
  45. self.models_base_path = os.path.join(self.path, "models")
  46. self.make_folder(self.models_base_path,
  47. template = "templates/autodoc/models_home.html")
  48. self.api_base_path = os.path.join(self.path, "api")
  49. self.make_folder(self.api_base_path,
  50. template = "templates/autodoc/api_home.html")
  51. for basepath, folders, files in os.walk(self.app_path):
  52. if "doctype" not in basepath:
  53. if "doctype" in folders:
  54. module = os.path.basename(basepath)
  55. module_folder = os.path.join(self.models_base_path, module)
  56. self.make_folder(module_folder,
  57. template = "templates/autodoc/module_home.html",
  58. context = {"name": module})
  59. self.update_index_txt(module_folder)
  60. if "doctype" in basepath:
  61. parts = basepath.split("/")
  62. #print parts
  63. module, doctype = parts[-3], parts[-1]
  64. if doctype not in ("doctype", "boilerplate"):
  65. self.write_model_file(basepath, module, doctype)
  66. elif self.is_py_module(basepath, folders, files):
  67. self.write_modules(basepath, folders, files)
  68. def is_py_module(self, basepath, folders, files):
  69. return "__init__.py" in files \
  70. and (not "/doctype" in basepath) \
  71. and (not "/patches" in basepath) \
  72. and (not "/change_log" in basepath) \
  73. and (not "/report" in basepath) \
  74. and (not "/page" in basepath) \
  75. and (not "/templates" in basepath) \
  76. and (not "/tests" in basepath) \
  77. and (not "doctype" in folders)
  78. def write_modules(self, basepath, folders, files):
  79. module_folder = os.path.join(self.api_base_path, os.path.relpath(basepath, self.app_path))
  80. self.make_folder(module_folder)
  81. for f in files:
  82. if f.endswith(".py"):
  83. module_name = os.path.relpath(os.path.join(basepath, f),
  84. self.app_path)[:-3].replace("/", ".").replace(".__init__", "")
  85. module_doc_path = os.path.join(module_folder,
  86. self.app + "." + module_name + ".html")
  87. self.make_folder(basepath)
  88. if not os.path.exists(module_doc_path):
  89. print "Writing " + module_doc_path
  90. with open(module_doc_path, "w") as f:
  91. context = {"name": self.app + "." + module_name}
  92. context.update(self.app_context)
  93. f.write(frappe.render_template("templates/autodoc/pymodule.html",
  94. context))
  95. self.update_index_txt(module_folder)
  96. def make_folder(self, path, template=None, context=None):
  97. if not template:
  98. template = "templates/autodoc/package_index.html"
  99. if not os.path.exists(path):
  100. os.makedirs(path)
  101. index_txt_path = os.path.join(path, "index.txt")
  102. print "Writing " + index_txt_path
  103. with open(index_txt_path, "w") as f:
  104. f.write("")
  105. index_html_path = os.path.join(path, "index.html")
  106. if not context:
  107. name = os.path.basename(path)
  108. if name==".":
  109. name = self.app
  110. context = {
  111. "title": name
  112. }
  113. context.update(self.app_context)
  114. print "Writing " + index_html_path
  115. with open(index_html_path, "w") as f:
  116. f.write(frappe.render_template(template, context))
  117. def update_index_txt(self, path):
  118. index_txt_path = os.path.join(path, "index.txt")
  119. pages = filter(lambda d: (d.endswith(".html") and d!="index.html") \
  120. or os.path.isdir(os.path.join(path, d)), os.listdir(path))
  121. pages = [d.rsplit(".", 1)[0] for d in pages]
  122. with open(index_txt_path, "r") as f:
  123. index_parts = filter(None, f.read().splitlines())
  124. if not set(pages).issubset(set(index_parts)):
  125. print "Updating " + index_txt_path
  126. with open(index_txt_path, "w") as f:
  127. f.write("\n".join(pages))
  128. def write_model_file(self, basepath, module, doctype):
  129. model_path = os.path.join(self.models_base_path, module, doctype + ".html")
  130. if not os.path.exists(model_path):
  131. model_json_path = os.path.join(basepath, doctype + ".json")
  132. if os.path.exists(model_json_path):
  133. with open(model_json_path, "r") as j:
  134. doctype_real_name = json.loads(j.read()).get("name")
  135. print "Writing " + model_path
  136. with open(model_path, "w") as f:
  137. context = {"doctype": doctype_real_name}
  138. context.update(self.app_context)
  139. f.write(frappe.render_template("templates/autodoc/doctype.html",
  140. context).encode("utf-8"))
  141. def write_files(self):
  142. frappe.local.flags.home_page = "index"
  143. for page in frappe.db.sql("""select parent_website_route,
  144. page_name from `tabWeb Page`""", as_dict=True):
  145. if page.parent_website_route:
  146. path = page.parent_website_route + "/" + page.page_name
  147. else:
  148. path = page.page_name
  149. frappe.local.path = path
  150. context = get_context(path)
  151. html = frappe.get_template(context.base_template_path).render(context)
  152. target_filename = os.path.join(self.target, context.template_path.split('/docs/')[1])
  153. if not os.path.exists(os.path.dirname(target_filename)):
  154. os.makedirs(os.path.dirname(target_filename))
  155. with open(target_filename, "w") as htmlfile:
  156. htmlfile.write(html.encode("utf-8"))
  157. print "wrote {0}".format(target_filename)