|
- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
- # MIT License. See license.txt
-
- from __future__ import unicode_literals, print_function
- from frappe.utils.minify import JavascriptMinify
- import subprocess
-
- """
- Build the `public` folders and setup languages
- """
-
- import os, frappe, json, shutil, re
- # from cssmin import cssmin
-
-
- app_paths = None
- def setup():
- global app_paths
- pymodules = []
- for app in frappe.get_all_apps(True):
- try:
- pymodules.append(frappe.get_module(app))
- except ImportError: pass
- app_paths = [os.path.dirname(pymodule.__file__) for pymodule in pymodules]
-
- def bundle(no_compress, make_copy=False, verbose=False):
- """concat / minify js files"""
- # build js files
- setup()
-
- make_asset_dirs(make_copy=make_copy)
-
- # new nodejs build system
- command = 'node --use_strict ../apps/frappe/frappe/build.js --build'
- if not no_compress:
- command += ' --minify'
- subprocess.call(command.split(' '))
-
- # build(no_compress, verbose)
-
- def watch(no_compress):
- """watch and rebuild if necessary"""
-
- # new nodejs file watcher
- command = 'node --use_strict ../apps/frappe/frappe/build.js --watch'
- subprocess.call(command.split(' '))
-
- # setup()
-
- # import time
- # compile_less()
- # build(no_compress=True)
-
- # while True:
- # compile_less()
- # if files_dirty():
- # build(no_compress=True)
-
- # time.sleep(3)
-
- def make_asset_dirs(make_copy=False):
- assets_path = os.path.join(frappe.local.sites_path, "assets")
- for dir_path in [
- os.path.join(assets_path, 'js'),
- os.path.join(assets_path, 'css')]:
-
- if not os.path.exists(dir_path):
- os.makedirs(dir_path)
-
- # symlink app/public > assets/app
- for app_name in frappe.get_all_apps(True):
- pymodule = frappe.get_module(app_name)
- app_base_path = os.path.abspath(os.path.dirname(pymodule.__file__))
-
- symlinks = []
- symlinks.append([os.path.join(app_base_path, 'public'), os.path.join(assets_path, app_name)])
- symlinks.append([os.path.join(app_base_path, 'docs'), os.path.join(assets_path, app_name + '_docs')])
-
- for source, target in symlinks:
- source = os.path.abspath(source)
- if not os.path.exists(target) and os.path.exists(source):
- if make_copy:
- shutil.copytree(source, target)
- else:
- os.symlink(source, target)
-
- def build(no_compress=False, verbose=False):
- assets_path = os.path.join(frappe.local.sites_path, "assets")
-
- for target, sources in get_build_maps().iteritems():
- pack(os.path.join(assets_path, target), sources, no_compress, verbose)
-
- def get_build_maps():
- """get all build.jsons with absolute paths"""
- # framework js and css files
-
- build_maps = {}
- for app_path in app_paths:
- path = os.path.join(app_path, 'public', 'build.json')
- if os.path.exists(path):
- with open(path) as f:
- try:
- for target, sources in json.loads(f.read()).iteritems():
- # update app path
- source_paths = []
- for source in sources:
- if isinstance(source, list):
- s = frappe.get_pymodule_path(source[0], *source[1].split("/"))
- else:
- s = os.path.join(app_path, source)
- source_paths.append(s)
-
- build_maps[target] = source_paths
- except ValueError as e:
- print(path)
- print('JSON syntax error {0}'.format(str(e)))
- return build_maps
-
- timestamps = {}
-
- def pack(target, sources, no_compress, verbose):
- from cStringIO import StringIO
-
- outtype, outtxt = target.split(".")[-1], ''
- jsm = JavascriptMinify()
-
- for f in sources:
- suffix = None
- if ':' in f: f, suffix = f.split(':')
- if not os.path.exists(f) or os.path.isdir(f):
- print("did not find " + f)
- continue
- timestamps[f] = os.path.getmtime(f)
- try:
- with open(f, 'r') as sourcefile:
- data = unicode(sourcefile.read(), 'utf-8', errors='ignore')
-
- extn = f.rsplit(".", 1)[1]
-
- if outtype=="js" and extn=="js" and (not no_compress) and suffix!="concat" and (".min." not in f):
- tmpin, tmpout = StringIO(data.encode('utf-8')), StringIO()
- jsm.minify(tmpin, tmpout)
- minified = tmpout.getvalue()
- if minified:
- outtxt += unicode(minified or '', 'utf-8').strip('\n') + ';'
-
- if verbose:
- print("{0}: {1}k".format(f, int(len(minified) / 1024)))
- elif outtype=="js" and extn=="html":
- # add to frappe.templates
- outtxt += html_to_js_template(f, data)
- else:
- outtxt += ('\n/*\n *\t%s\n */' % f)
- outtxt += '\n' + data + '\n'
-
- except Exception:
- print("--Error in:" + f + "--")
- print(frappe.get_traceback())
-
- if not no_compress and outtype == 'css':
- pass
- #outtxt = cssmin(outtxt)
-
- with open(target, 'w') as f:
- f.write(outtxt.encode("utf-8"))
-
- print("Wrote %s - %sk" % (target, str(int(os.path.getsize(target)/1024))))
-
- def html_to_js_template(path, content):
- '''returns HTML template content as Javascript code, adding it to `frappe.templates`'''
- return """frappe.templates["{key}"] = '{content}';\n""".format(\
- key=path.rsplit("/", 1)[-1][:-5], content=scrub_html_template(content))
-
- def scrub_html_template(content):
- '''Returns HTML content with removed whitespace and comments'''
- # remove whitespace to a single space
- content = re.sub("\s+", " ", content)
-
- # strip comments
- content = re.sub("(<!--.*?-->)", "", content)
-
- return content.replace("'", "\'")
-
- def files_dirty():
- for target, sources in get_build_maps().iteritems():
- for f in sources:
- if ':' in f: f, suffix = f.split(':')
- if not os.path.exists(f) or os.path.isdir(f): continue
- if os.path.getmtime(f) != timestamps.get(f):
- print(f + ' dirty')
- return True
- else:
- return False
-
- def compile_less():
- from distutils.spawn import find_executable
- if not find_executable("lessc"):
- return
-
- for path in app_paths:
- less_path = os.path.join(path, "public", "less")
- if os.path.exists(less_path):
- for fname in os.listdir(less_path):
- if fname.endswith(".less") and fname != "variables.less":
- fpath = os.path.join(less_path, fname)
- mtime = os.path.getmtime(fpath)
- if fpath in timestamps and mtime == timestamps[fpath]:
- continue
-
- timestamps[fpath] = mtime
-
- print("compiling {0}".format(fpath))
-
- css_path = os.path.join(path, "public", "css", fname.rsplit(".", 1)[0] + ".css")
- os.system("lessc {0} > {1}".format(fpath, css_path))
|