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.

bundlejs.py 5.2 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
14 years ago
14 years ago
13 years ago
14 years ago
13 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. #
  3. # MIT License (MIT)
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. # and/or sell copies of the Software, and to permit persons to whom the
  10. # Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #
  22. from __future__ import unicode_literals
  23. from webnotes.utils.minify import JavascriptMinify
  24. import os, sys
  25. class Bundle:
  26. """
  27. Concatenate, compress and mix (if required) js+css files from build.json
  28. """
  29. no_compress = False
  30. timestamps = {}
  31. path = '.'
  32. def concat(self, filelist, outfile=None):
  33. """
  34. Concat css and js files into a bundle
  35. """
  36. from cStringIO import StringIO
  37. out_type = outfile and outfile.split('.')[-1] or 'js'
  38. outtxt = ''
  39. for f in filelist:
  40. suffix = None
  41. if ':' in f:
  42. f, suffix = f.split(':')
  43. if not os.path.exists(f) or os.path.isdir(f):
  44. continue
  45. self.timestamps[f] = os.path.getmtime(f)
  46. # get datas
  47. with open(f, 'r') as infile:
  48. # get file type
  49. ftype = f.split('.')[-1]
  50. data = infile.read()
  51. if os.path.basename(f)=='core.js':
  52. import webnotes
  53. data = data % {"_version_number": webnotes.generate_hash() }
  54. outtxt += ('\n/*\n *\t%s\n */' % f)
  55. # append
  56. if suffix=='concat' or out_type != 'js' or self.no_compress or ('.min.' in f):
  57. outtxt += '\n' + data + '\n'
  58. else:
  59. jsm = JavascriptMinify()
  60. tmpin = StringIO(data)
  61. tmpout = StringIO()
  62. jsm.minify(tmpin, tmpout)
  63. tmpmin = tmpout.getvalue() or ''
  64. tmpmin.strip('\n')
  65. outtxt += tmpmin
  66. with open(outfile, 'w') as f:
  67. f.write(outtxt)
  68. print "Wrote %s - %sk" % (outfile, str(int(os.path.getsize(outfile)/1024)))
  69. def dirty(self):
  70. """check if build files are dirty"""
  71. self.make_build_data()
  72. for builddict in self.bdata:
  73. for f in self.get_infiles(builddict):
  74. if ':' in f:
  75. f, suffix = f.split(':')
  76. if not os.path.exists(f) or os.path.isdir(f):
  77. continue
  78. if os.path.getmtime(f) != self.timestamps.get(f):
  79. print f + ' dirty'
  80. return True
  81. else:
  82. return False
  83. def make(self):
  84. """Build (stitch + compress) the file defined in build.json"""
  85. print "Building js and css files..."
  86. self.make_build_data()
  87. for builddict in self.bdata:
  88. outfile = builddict.keys()[0]
  89. infiles = self.get_infiles(builddict)
  90. self.concat(infiles, os.path.relpath(os.path.join(self.path, outfile), os.curdir))
  91. def get_infiles(self, builddict):
  92. """make list of files to merge"""
  93. outfile = builddict.keys()[0]
  94. infiles = builddict[outfile]
  95. # add app js and css to the list
  96. if outfile in self.appfiles:
  97. for f in self.appfiles[outfile]:
  98. if f not in infiles:
  99. infiles.append(f)
  100. fl = []
  101. for f in infiles:
  102. ## load files from directory
  103. if f.endswith('/'):
  104. # add init js first
  105. fl += [os.path.relpath(os.path.join(f, 'init.js'), os.curdir)]
  106. # files other than init.js and beginning with "_"
  107. fl += [os.path.relpath(os.path.join(f, tmp), os.curdir) \
  108. for tmp in os.listdir(f) if (tmp != 'init.js' and not tmp.startswith('_'))]
  109. else:
  110. fl.append(os.path.relpath(os.path.join(self.path, f), os.curdir))
  111. return fl
  112. def make_build_data(self):
  113. """merge build.json and lib/build.json"""
  114. # framework js and css files
  115. with open('lib/public/build.json', 'r') as bfile:
  116. bdata = eval(bfile.read())
  117. # app js and css files
  118. if os.path.exists('app/public/build.json'):
  119. with open('app/public/build.json', 'r') as bfile:
  120. appfiles = eval(bfile.read())
  121. else:
  122. appfiles = {}
  123. # add additional app files in bdata
  124. buildfile_list = [builddict.keys()[0] for builddict in bdata]
  125. for f in appfiles:
  126. if f not in buildfile_list:
  127. bdata.append({f: appfiles[f]})
  128. self.appfiles = appfiles
  129. self.bdata = bdata
  130. def check_public():
  131. from webnotes.install_lib.setup_public_folder import make
  132. make()
  133. def bundle(no_compress, cms_make=True):
  134. """concat / minify js files"""
  135. # build js files
  136. check_public()
  137. bundle = Bundle()
  138. bundle.no_compress = no_compress
  139. bundle.make()
  140. if cms_make:
  141. # build index.html and app.html
  142. import webnotes.cms.make
  143. webnotes.cms.make.make()
  144. def watch(no_compress):
  145. """watch and rebuild if necessary"""
  146. import time
  147. bundle = Bundle()
  148. bundle.no_compress = no_compress
  149. while True:
  150. if bundle.dirty():
  151. bundle.make()
  152. time.sleep(3)