blockscad_build.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #!/usr/bin/python2.7
  2. # Compresses the Blockscad files into a single javascript file.
  3. #
  4. '''
  5. Copyright (C) 2014-2015 H3XL, Inc
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. '''
  17. import errno, httplib, json, os, re, subprocess, sys, threading, urllib
  18. # Define the parameters for the POST request and encode them in
  19. # a URL-safe format.
  20. HEADER = ('// Do not edit this file; automatically generated by blockscad_build.py.\n'
  21. '"use strict";');
  22. class Gen_compressed(threading.Thread):
  23. """Generate a JavaScript file that contains all of Blockly's core and all
  24. required parts of Closure, compiled together.
  25. Uses the Closure Compiler's online API.
  26. Runs in a separate thread.
  27. """
  28. def __init__(self, search_paths):
  29. threading.Thread.__init__(self)
  30. self.search_paths = search_paths
  31. def run(self):
  32. self.gen_blockscad()
  33. self.gen_viewer()
  34. def gen_blockscad(self):
  35. target_filename = 'blockscad_compressed.js'
  36. # Define the parameters for the POST request.
  37. params = [
  38. ('compilation_level', 'SIMPLE_OPTIMIZATIONS'),
  39. ('output_format', 'json'),
  40. ('language', 'ECMASCRIPT5'),
  41. ('output_info', 'compiled_code'),
  42. ('output_info', 'warnings'),
  43. ('output_info', 'errors'),
  44. ('output_info', 'statistics'),
  45. ]
  46. # Read in all the source files.
  47. filenames = ['bsPage.js','storage.js','utils.js','blockscad.js',
  48. 'text.js','lightgl.js','toolbox.js','deflate.js', 'stl.js']
  49. for filename in filenames:
  50. f = open(filename)
  51. print filename
  52. params.append(('js_code', ''.join(f.readlines())))
  53. f.close()
  54. self.do_compile(params, target_filename, filenames, '')
  55. def gen_viewer(self):
  56. target_filename = 'viewer_compressed.js'
  57. # Define the parameters for the POST request.
  58. params = [
  59. ('compilation_level', 'SIMPLE_OPTIMIZATIONS'),
  60. ('output_format', 'json'),
  61. ('language', 'ECMASCRIPT5'),
  62. ('output_info', 'compiled_code'),
  63. ('output_info', 'warnings'),
  64. ('output_info', 'errors'),
  65. ('output_info', 'statistics'),
  66. ]
  67. # Read in all the source files.
  68. filenames = ['viewer.js', 'csg.js', 'formats.js']
  69. for filename in filenames:
  70. f = open(filename)
  71. print filename
  72. params.append(('js_code', ''.join(f.readlines())))
  73. f.close()
  74. self.do_compile(params, target_filename, filenames, '')
  75. def do_compile(self, params, target_filename, filenames, remove):
  76. # Send the request to Google.
  77. headers = {'Content-type': 'application/x-www-form-urlencoded'}
  78. conn = httplib.HTTPConnection('closure-compiler.appspot.com')
  79. conn.request('POST', '/compile', urllib.urlencode(params), headers)
  80. response = conn.getresponse()
  81. json_str = response.read()
  82. conn.close()
  83. # Parse the JSON response.
  84. json_data = json.loads(json_str)
  85. def file_lookup(name):
  86. if not name.startswith('Input_'):
  87. return '???'
  88. n = int(name[6:])
  89. return filenames[n]
  90. if json_data.has_key('serverErrors'):
  91. errors = json_data['serverErrors']
  92. for error in errors:
  93. print('SERVER ERROR: %s' % target_filename)
  94. print(error['error'])
  95. elif json_data.has_key('errors'):
  96. errors = json_data['errors']
  97. for error in errors:
  98. print('FATAL ERROR')
  99. print(error['error'])
  100. if error['file']:
  101. print('%s at line %d:' % (
  102. file_lookup(error['file']), error['lineno']))
  103. print(error['line'])
  104. print((' ' * error['charno']) + '^')
  105. sys.exit(1)
  106. else:
  107. if json_data.has_key('warnings'):
  108. warnings = json_data['warnings']
  109. for warning in warnings:
  110. print('WARNING')
  111. print(warning['warning'])
  112. if warning['file']:
  113. print('%s at line %d:' % (
  114. file_lookup(warning['file']), warning['lineno']))
  115. print(warning['line'])
  116. print((' ' * warning['charno']) + '^')
  117. print()
  118. if not json_data.has_key('compiledCode'):
  119. print('FATAL ERROR: Compiler did not return compiledCode.')
  120. sys.exit(1)
  121. code = HEADER + '\n' + json_data['compiledCode']
  122. # code = code.replace(remove, '')
  123. stats = json_data['statistics']
  124. original_b = stats['originalSize']
  125. compressed_b = stats['compressedSize']
  126. if original_b > 0 and compressed_b > 0:
  127. f = open(target_filename, 'w')
  128. f.write(code)
  129. f.close()
  130. original_kb = int(original_b / 1024 + 0.5)
  131. compressed_kb = int(compressed_b / 1024 + 0.5)
  132. ratio = int(float(compressed_b) / float(original_b) * 100 + 0.5)
  133. print('SUCCESS: ' + target_filename)
  134. print('Size changed from %d KB to %d KB (%d%%).' % (
  135. original_kb, compressed_kb, ratio))
  136. else:
  137. print('UNKNOWN ERROR')
  138. def file_lookup(name):
  139. if not name.startswith('Input_'):
  140. return '???'
  141. n = int(name[6:])
  142. return filenames[n]
  143. if __name__ == '__main__':
  144. Gen_compressed('').start()