You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

build.py 5.3 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
13 years ago
12 years ago
14 years ago
12 years ago
14 years ago
13 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. from webnotes.utils.minify import JavascriptMinify
  5. """
  6. Build the `public` folders and setup languages
  7. """
  8. import os, sys, webnotes
  9. from cssmin import cssmin
  10. def bundle(no_compress, cms_make=True):
  11. """concat / minify js files"""
  12. # build js files
  13. check_public()
  14. check_lang()
  15. bundle = Bundle()
  16. bundle.no_compress = no_compress
  17. bundle.make()
  18. if cms_make:
  19. try:
  20. from startup.event_handlers import on_build
  21. on_build()
  22. except ImportError, e:
  23. pass
  24. clear_pyc_files()
  25. def watch(no_compress):
  26. """watch and rebuild if necessary"""
  27. import time
  28. bundle = Bundle()
  29. bundle.no_compress = no_compress
  30. while True:
  31. if bundle.dirty():
  32. bundle.make()
  33. time.sleep(3)
  34. def check_public():
  35. from webnotes.install_lib.setup_public_folder import make
  36. make()
  37. def check_lang():
  38. from webnotes.translate import update_translations
  39. update_translations()
  40. def clear_pyc_files():
  41. from webnotes.utils import get_base_path
  42. for path, folders, files in os.walk(get_base_path()):
  43. if 'locale' in folders: folders.remove('locale')
  44. for f in files:
  45. if f.decode("utf-8").endswith(".pyc"):
  46. os.remove(os.path.join(path, f))
  47. class Bundle:
  48. """
  49. Concatenate, compress and mix (if required) js+css files from build.json
  50. """
  51. no_compress = False
  52. timestamps = {}
  53. path = '.'
  54. def concat(self, filelist, outfile=None):
  55. """
  56. Concat css and js files into a bundle
  57. """
  58. from cStringIO import StringIO
  59. out_type = outfile and outfile.split('.')[-1] or 'js'
  60. outtxt = ''
  61. for f in filelist:
  62. suffix = None
  63. if ':' in f:
  64. f, suffix = f.split(':')
  65. if not os.path.exists(f) or os.path.isdir(f):
  66. continue
  67. self.timestamps[f] = os.path.getmtime(f)
  68. # get datas
  69. try:
  70. with open(f, 'r') as infile:
  71. # get file type
  72. ftype = f.split('.')[-1]
  73. data = unicode(infile.read(), 'utf-8', errors='ignore')
  74. outtxt += ('\n/*\n *\t%s\n */' % f)
  75. # append
  76. if suffix=='concat' or out_type != 'js' or self.no_compress or ('.min.' in f):
  77. outtxt += '\n' + data + '\n'
  78. else:
  79. jsm = JavascriptMinify()
  80. tmpin = StringIO(data.encode('utf-8'))
  81. tmpout = StringIO()
  82. jsm.minify(tmpin, tmpout)
  83. tmpmin = unicode(tmpout.getvalue() or '', 'utf-8')
  84. tmpmin.strip('\n')
  85. outtxt += tmpmin
  86. except Exception, e:
  87. print "--Error in:" + f + "--"
  88. print webnotes.getTraceback()
  89. if not self.no_compress and out_type == 'css':
  90. outtxt = cssmin(outtxt)
  91. with open(outfile, 'w') as f:
  92. f.write(outtxt.encode("utf-8"))
  93. print "Wrote %s - %sk" % (outfile, str(int(os.path.getsize(outfile)/1024)))
  94. def dirty(self):
  95. """check if build files are dirty"""
  96. self.make_build_data()
  97. for builddict in self.bdata:
  98. for f in self.get_infiles(builddict):
  99. if ':' in f:
  100. f, suffix = f.split(':')
  101. if not os.path.exists(f) or os.path.isdir(f):
  102. continue
  103. if os.path.getmtime(f) != self.timestamps.get(f):
  104. print f + ' dirty'
  105. return True
  106. else:
  107. return False
  108. def make(self):
  109. """Build (stitch + compress) the file defined in build.json"""
  110. print "Building js and css files..."
  111. self.make_build_data()
  112. for builddict in self.bdata:
  113. outfile = builddict.keys()[0]
  114. infiles = self.get_infiles(builddict)
  115. self.concat(infiles, os.path.relpath(os.path.join(self.path, outfile), os.curdir))
  116. self.reset_app_html()
  117. def reset_app_html(self):
  118. import webnotes
  119. if os.path.exists("public/app.html"):
  120. os.remove("public/app.html")
  121. splash = ""
  122. if os.path.exists("public/app/images/splash.svg"):
  123. with open("public/app/images/splash.svg") as splash_file:
  124. splash = splash_file.read()
  125. with open('lib/public/html/app.html', 'r') as app_html:
  126. data = app_html.read()
  127. data = data % {
  128. "_version_number": webnotes.generate_hash(),
  129. "splash": splash
  130. }
  131. with open('public/app.html', 'w') as new_app_html:
  132. new_app_html.write(data)
  133. def get_infiles(self, builddict):
  134. """make list of files to merge"""
  135. outfile = builddict.keys()[0]
  136. infiles = builddict[outfile]
  137. # add app js and css to the list
  138. if outfile in self.appfiles:
  139. for f in self.appfiles[outfile]:
  140. if f not in infiles:
  141. infiles.append(f)
  142. fl = []
  143. for f in infiles:
  144. ## load files from directory
  145. if f.endswith('/'):
  146. # add init js first
  147. fl += [os.path.relpath(os.path.join(f, 'init.js'), os.curdir)]
  148. # files other than init.js and beginning with "_"
  149. fl += [os.path.relpath(os.path.join(f, tmp), os.curdir) \
  150. for tmp in os.listdir(f) if (tmp != 'init.js' and not tmp.startswith('_'))]
  151. else:
  152. fl.append(os.path.relpath(os.path.join(self.path, f), os.curdir))
  153. return fl
  154. def make_build_data(self):
  155. """merge build.json and lib/build.json"""
  156. # framework js and css files
  157. with open('lib/public/build.json', 'r') as bfile:
  158. bdata = eval(bfile.read())
  159. # app js and css files
  160. if os.path.exists('app/public/build.json'):
  161. with open('app/public/build.json', 'r') as bfile:
  162. appfiles = eval(bfile.read())
  163. else:
  164. appfiles = {}
  165. # add additional app files in bdata
  166. buildfile_list = [builddict.keys()[0] for builddict in bdata]
  167. for f in appfiles:
  168. if f not in buildfile_list:
  169. bdata.append({f: appfiles[f]})
  170. self.appfiles = appfiles
  171. self.bdata = bdata