Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

271 рядки
8.3 KiB

  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe, os, time, sys
  5. from frappe.utils import cint
  6. from markdown2 import markdown
  7. # from frappe.website.sitemap import get_route_children, get_next
  8. def sync_statics(rebuild=False):
  9. s = sync()
  10. s.verbose = True
  11. while True:
  12. s.start(rebuild)
  13. frappe.db.commit()
  14. time.sleep(2)
  15. rebuild = False
  16. class sync(object):
  17. def start(self, rebuild=False):
  18. self.verbose = False
  19. self.synced = []
  20. self.synced_paths = []
  21. self.to_insert = []
  22. self.to_update = []
  23. self.updated = 0
  24. self.rebuild = rebuild
  25. for app in frappe.get_installed_apps():
  26. self.sync_for_app(app)
  27. self.insert_and_update()
  28. self.cleanup()
  29. def sync_for_app(self, app):
  30. self.statics_path = frappe.get_app_path(app, "templates", "statics")
  31. if os.path.exists(self.statics_path):
  32. for basepath, folders, files in os.walk(self.statics_path):
  33. self.sync_folder(basepath, folders, files)
  34. def sync_folder(self, basepath, folders, files):
  35. self.get_index_txt(basepath, files)
  36. index_found = self.sync_index_page(basepath, files)
  37. if not index_found and basepath!=self.statics_path:
  38. # not synced either by generator or by index.html
  39. return
  40. if self.index:
  41. self.sync_using_given_index(basepath, folders, files)
  42. else:
  43. self.sync_alphabetically(basepath, folders, [filename for filename in files if filename.endswith('html') or filename.endswith('md')])
  44. def get_index_txt(self, basepath, files):
  45. self.index = []
  46. if "index.txt" in files:
  47. with open(os.path.join(basepath, "index.txt"), "r") as indexfile:
  48. self.index = indexfile.read().splitlines()
  49. def sync_index_page(self, basepath, files):
  50. for extn in ("md", "html"):
  51. fname = "index." + extn
  52. if fname in files:
  53. self.sync_file(fname, os.path.join(basepath, fname), None)
  54. return True
  55. def sync_using_given_index(self, basepath, folders, files):
  56. for i, page_name in enumerate(self.index):
  57. if page_name in folders:
  58. # for folder, sync inner index first (so that idx is set)
  59. for extn in ("md", "html"):
  60. path = os.path.join(basepath, page_name, "index." + extn)
  61. if os.path.exists(path):
  62. self.sync_file("index." + extn, path, i)
  63. break
  64. # other files
  65. for extn in ("md", "html"):
  66. fname = page_name + "." + extn
  67. if fname in files:
  68. self.sync_file(fname, os.path.join(basepath, fname), i)
  69. break
  70. elif page_name not in folders:
  71. print page_name + " not found in " + basepath
  72. def sync_alphabetically(self, basepath, folders, files):
  73. files.sort()
  74. for fname in files:
  75. page_name = fname.rsplit(".", 1)[0]
  76. if not (page_name=="index" and basepath!=self.statics_path):
  77. self.sync_file(fname, os.path.join(basepath, fname), None)
  78. def sync_file(self, fname, fpath, priority):
  79. route = os.path.relpath(fpath, self.statics_path).rsplit(".", 1)[0]
  80. if fname.rsplit(".", 1)[0]=="index" and os.path.dirname(fpath) != self.statics_path:
  81. route = os.path.dirname(route)
  82. if route in self.synced:
  83. return
  84. parent_website_route = os.path.dirname(route)
  85. page_name = os.path.basename(route)
  86. route_details = frappe.db.get_value("Website Route", route,
  87. ["name", "idx", "static_file_timestamp", "docname"], as_dict=True)
  88. if route_details:
  89. page = self.get_route_details_for_update(route_details, fpath,
  90. priority, parent_website_route)
  91. if page:
  92. self.to_update.append(page)
  93. else:
  94. # Route does not exist, new page
  95. page = self.get_web_page_for_insert(route, fpath, page_name,
  96. priority, parent_website_route)
  97. self.to_insert.append(page)
  98. self.synced.append(route)
  99. def insert_and_update(self):
  100. if self.to_insert:
  101. for i, page in enumerate(self.to_insert):
  102. if self.verbose:
  103. print "Inserting " + page.route
  104. else:
  105. sys.stdout.write("\rInserting statics {0}/{1}".format(i+1, len(self.to_insert)))
  106. sys.stdout.flush()
  107. self.insert_web_page(page)
  108. if not self.verbose: print ""
  109. if self.to_update:
  110. for i, route_details in enumerate(self.to_update):
  111. if self.verbose:
  112. print "Updating " + route_details.name
  113. else:
  114. sys.stdout.write("\rUpdating statics {0}/{1}".format(i+1, len(self.to_update)))
  115. sys.stdout.flush()
  116. self.update_web_page(route_details)
  117. if not self.verbose: print ""
  118. def get_web_page_for_insert(self, route, fpath, page_name, priority, parent_website_route):
  119. page = frappe.get_doc({
  120. "doctype":"Web Page",
  121. "idx": priority,
  122. "page_name": page_name,
  123. "published": 1,
  124. "parent_website_route": parent_website_route
  125. })
  126. page.fpath = fpath
  127. page.route = route
  128. page.update(get_static_content(fpath, page_name, route))
  129. return page
  130. def insert_web_page(self, page):
  131. try:
  132. page.insert()
  133. except frappe.NameError, e:
  134. print e
  135. # page exists, if deleted static, delete it and try again
  136. old_route = frappe.get_doc("Website Route", {"ref_doctype":"Web Page",
  137. "docname": page.name})
  138. if old_route.static_file_timestamp and \
  139. not os.path.exists(os.path.join(self.statics_path, old_route.name)):
  140. frappe.delete_doc("Web Page", page.name)
  141. page.insert() # retry
  142. # update timestamp
  143. route_doc = frappe.get_doc("Website Route", {"ref_doctype": "Web Page",
  144. "docname": page.name})
  145. route_doc.static_file_timestamp = cint(os.path.getmtime(page.fpath))
  146. route_doc.save()
  147. def get_route_details_for_update(self, route_details, fpath, priority, parent_website_route):
  148. out = None
  149. if not route_details.docname:
  150. print "Ignoring {0} because page found".format(route_details.name)
  151. return
  152. if str(cint(os.path.getmtime(fpath)))!= route_details.static_file_timestamp \
  153. or (cint(route_details.idx) != cint(priority) and (priority is not None) \
  154. or self.rebuild):
  155. out = route_details
  156. out.idx = priority
  157. out.fpath = fpath
  158. return out
  159. def update_web_page(self, route_details):
  160. page = frappe.get_doc("Web Page", route_details.docname)
  161. page.update(get_static_content(route_details.fpath,
  162. route_details.docname, route_details.name))
  163. page.save()
  164. route_doc = frappe.get_doc("Website Route", route_details.name)
  165. route_doc.static_file_timestamp = cint(os.path.getmtime(route_details.fpath))
  166. route_doc.save()
  167. def cleanup(self):
  168. if self.synced:
  169. # delete static web pages that are not in immediate list
  170. frappe.delete_doc("Web Page", frappe.db.sql_list("""select docname
  171. from `tabWebsite Route`
  172. where ifnull(static_file_timestamp,'')!='' and name not in ({})
  173. order by (rgt-lft) asc""".format(', '.join(["%s"]*len(self.synced))),
  174. tuple(self.synced)))
  175. else:
  176. # delete all static web pages
  177. frappe.delete_doc("Web Page", frappe.db.sql_list("""select docname
  178. from `tabWebsite Route`
  179. where ifnull(static_file_timestamp,'')!=''
  180. order by (rgt-lft) asc"""))
  181. def delete_static_web_pages():
  182. for name in frappe.db.sql_list("""select docname from `tabWebsite Route`
  183. where ifnull(static_file_timestamp,'')!=''"""):
  184. frappe.db.sql("delete from `tabWeb Page` where name=%s", name)
  185. def get_static_content(fpath, docname, route):
  186. d = frappe._dict({})
  187. with open(fpath, "r") as contentfile:
  188. content = unicode(contentfile.read(), 'utf-8')
  189. if fpath.endswith(".md"):
  190. if content:
  191. lines = content.splitlines()
  192. first_line = lines[0].strip()
  193. if first_line.startswith("# "):
  194. d.title = first_line[2:]
  195. content = "\n".join(lines[1:])
  196. # if "{index}" in content:
  197. # children = get_route_children(route)
  198. # html = frappe.get_template("templates/includes/static_index.html").render({
  199. # "items":children})
  200. # content = content.replace("{index}", html)
  201. #
  202. # if "{next}" in content:
  203. # next_item = get_next(route)
  204. # html = ""
  205. # if next_item:
  206. # html = '''<p>
  207. # <br><a href="{name}" class="btn btn-primary">
  208. # {page_title} <i class="icon-chevron-right"></i></a>
  209. # </p>'''.format(**next_item)
  210. # content = content.replace("{next}", html)
  211. content = markdown(content)
  212. d.main_section = unicode(content.encode("utf-8"), 'utf-8')
  213. if not d.title:
  214. d.title = docname.replace("-", " ").replace("_", " ").title()
  215. for extn in ("js", "css"):
  216. fpath = fpath.rsplit(".", 1)[0] + "." + extn
  217. if os.path.exists(fpath):
  218. with open(fpath, "r") as f:
  219. d["css" if extn=="css" else "javascript"] = f.read()
  220. d.insert_style = 1 if d.css else 0
  221. d.insert_code = 1 if d.javascript else 0
  222. return d