Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

218 wiersze
6.1 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals, print_function
  4. from frappe.utils.minify import JavascriptMinify
  5. import subprocess
  6. from six import iteritems
  7. """
  8. Build the `public` folders and setup languages
  9. """
  10. import os, frappe, json, shutil, re
  11. # from cssmin import cssmin
  12. app_paths = None
  13. def setup():
  14. global app_paths
  15. pymodules = []
  16. for app in frappe.get_all_apps(True):
  17. try:
  18. pymodules.append(frappe.get_module(app))
  19. except ImportError: pass
  20. app_paths = [os.path.dirname(pymodule.__file__) for pymodule in pymodules]
  21. def bundle(no_compress, make_copy=False, verbose=False):
  22. """concat / minify js files"""
  23. # build js files
  24. setup()
  25. make_asset_dirs(make_copy=make_copy)
  26. # new nodejs build system
  27. command = 'node --use_strict ../apps/frappe/frappe/build.js --build'
  28. if not no_compress:
  29. command += ' --minify'
  30. subprocess.call(command.split(' '))
  31. # build(no_compress, verbose)
  32. def watch(no_compress):
  33. """watch and rebuild if necessary"""
  34. # new nodejs file watcher
  35. command = 'node --use_strict ../apps/frappe/frappe/build.js --watch'
  36. subprocess.call(command.split(' '))
  37. # setup()
  38. # import time
  39. # compile_less()
  40. # build(no_compress=True)
  41. # while True:
  42. # compile_less()
  43. # if files_dirty():
  44. # build(no_compress=True)
  45. # time.sleep(3)
  46. def make_asset_dirs(make_copy=False):
  47. assets_path = os.path.join(frappe.local.sites_path, "assets")
  48. for dir_path in [
  49. os.path.join(assets_path, 'js'),
  50. os.path.join(assets_path, 'css')]:
  51. if not os.path.exists(dir_path):
  52. os.makedirs(dir_path)
  53. # symlink app/public > assets/app
  54. for app_name in frappe.get_all_apps(True):
  55. pymodule = frappe.get_module(app_name)
  56. app_base_path = os.path.abspath(os.path.dirname(pymodule.__file__))
  57. symlinks = []
  58. symlinks.append([os.path.join(app_base_path, 'public'), os.path.join(assets_path, app_name)])
  59. symlinks.append([os.path.join(app_base_path, 'docs'), os.path.join(assets_path, app_name + '_docs')])
  60. for source, target in symlinks:
  61. source = os.path.abspath(source)
  62. if not os.path.exists(target) and os.path.exists(source):
  63. if make_copy:
  64. shutil.copytree(source, target)
  65. else:
  66. os.symlink(source, target)
  67. def build(no_compress=False, verbose=False):
  68. assets_path = os.path.join(frappe.local.sites_path, "assets")
  69. for target, sources in iteritems(get_build_maps()):
  70. pack(os.path.join(assets_path, target), sources, no_compress, verbose)
  71. def get_build_maps():
  72. """get all build.jsons with absolute paths"""
  73. # framework js and css files
  74. build_maps = {}
  75. for app_path in app_paths:
  76. path = os.path.join(app_path, 'public', 'build.json')
  77. if os.path.exists(path):
  78. with open(path) as f:
  79. try:
  80. for target, sources in iteritems(json.loads(f.read())):
  81. # update app path
  82. source_paths = []
  83. for source in sources:
  84. if isinstance(source, list):
  85. s = frappe.get_pymodule_path(source[0], *source[1].split("/"))
  86. else:
  87. s = os.path.join(app_path, source)
  88. source_paths.append(s)
  89. build_maps[target] = source_paths
  90. except ValueError as e:
  91. print(path)
  92. print('JSON syntax error {0}'.format(str(e)))
  93. return build_maps
  94. timestamps = {}
  95. def pack(target, sources, no_compress, verbose):
  96. from cStringIO import StringIO
  97. outtype, outtxt = target.split(".")[-1], ''
  98. jsm = JavascriptMinify()
  99. for f in sources:
  100. suffix = None
  101. if ':' in f: f, suffix = f.split(':')
  102. if not os.path.exists(f) or os.path.isdir(f):
  103. print("did not find " + f)
  104. continue
  105. timestamps[f] = os.path.getmtime(f)
  106. try:
  107. with open(f, 'r') as sourcefile:
  108. data = unicode(sourcefile.read(), 'utf-8', errors='ignore')
  109. extn = f.rsplit(".", 1)[1]
  110. if outtype=="js" and extn=="js" and (not no_compress) and suffix!="concat" and (".min." not in f):
  111. tmpin, tmpout = StringIO(data.encode('utf-8')), StringIO()
  112. jsm.minify(tmpin, tmpout)
  113. minified = tmpout.getvalue()
  114. if minified:
  115. outtxt += unicode(minified or '', 'utf-8').strip('\n') + ';'
  116. if verbose:
  117. print("{0}: {1}k".format(f, int(len(minified) / 1024)))
  118. elif outtype=="js" and extn=="html":
  119. # add to frappe.templates
  120. outtxt += html_to_js_template(f, data)
  121. else:
  122. outtxt += ('\n/*\n *\t%s\n */' % f)
  123. outtxt += '\n' + data + '\n'
  124. except Exception:
  125. print("--Error in:" + f + "--")
  126. print(frappe.get_traceback())
  127. if not no_compress and outtype == 'css':
  128. pass
  129. #outtxt = cssmin(outtxt)
  130. with open(target, 'w') as f:
  131. f.write(outtxt.encode("utf-8"))
  132. print("Wrote %s - %sk" % (target, str(int(os.path.getsize(target)/1024))))
  133. def html_to_js_template(path, content):
  134. '''returns HTML template content as Javascript code, adding it to `frappe.templates`'''
  135. return """frappe.templates["{key}"] = '{content}';\n""".format(\
  136. key=path.rsplit("/", 1)[-1][:-5], content=scrub_html_template(content))
  137. def scrub_html_template(content):
  138. '''Returns HTML content with removed whitespace and comments'''
  139. # remove whitespace to a single space
  140. content = re.sub("\s+", " ", content)
  141. # strip comments
  142. content = re.sub("(<!--.*?-->)", "", content)
  143. return content.replace("'", "\'")
  144. def files_dirty():
  145. for target, sources in iteritems(get_build_maps()):
  146. for f in sources:
  147. if ':' in f: f, suffix = f.split(':')
  148. if not os.path.exists(f) or os.path.isdir(f): continue
  149. if os.path.getmtime(f) != timestamps.get(f):
  150. print(f + ' dirty')
  151. return True
  152. else:
  153. return False
  154. def compile_less():
  155. from distutils.spawn import find_executable
  156. if not find_executable("lessc"):
  157. return
  158. for path in app_paths:
  159. less_path = os.path.join(path, "public", "less")
  160. if os.path.exists(less_path):
  161. for fname in os.listdir(less_path):
  162. if fname.endswith(".less") and fname != "variables.less":
  163. fpath = os.path.join(less_path, fname)
  164. mtime = os.path.getmtime(fpath)
  165. if fpath in timestamps and mtime == timestamps[fpath]:
  166. continue
  167. timestamps[fpath] = mtime
  168. print("compiling {0}".format(fpath))
  169. css_path = os.path.join(path, "public", "css", fname.rsplit(".", 1)[0] + ".css")
  170. os.system("lessc {0} > {1}".format(fpath, css_path))