123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- import sys
- if sys.version_info[0] != 2:
- raise Exception("Blockly build only compatible with Python 2.x.\n"
- "You are using: " + sys.version)
- import errno, glob, httplib, json, os, re, subprocess, threading, urllib
- def import_path(fullpath):
- """Import a file with full path specification.
- Allows one to import from any directory, something __import__ does not do.
- Args:
- fullpath: Path and filename of import.
- Returns:
- An imported module.
- """
- path, filename = os.path.split(fullpath)
- filename, ext = os.path.splitext(filename)
- sys.path.append(path)
- module = __import__(filename)
- reload(module)
- del sys.path[-1]
- return module
- HEADER = ("// Do not edit this file; automatically generated by build.py.\n"
- "'use strict';\n")
- class Gen_uncompressed(threading.Thread):
- """Generate a JavaScript file that loads Blockly's raw files.
- Runs in a separate thread.
- """
- def __init__(self, search_paths):
- threading.Thread.__init__(self)
- self.search_paths = search_paths
- def run(self):
- target_filename = "blockly_uncompressed.js"
- f = open(target_filename, "w")
- f.write(HEADER)
- f.write("""
- // 'this' is 'window' in a browser, or 'global' in node.js.
- this.BLOCKLY_DIR = (function() {
- // Find name of current directory.
- var scripts = document.getElementsByTagName('script');
- var re = new RegExp('(.+)[\/]blockly_uncompressed\.js$');
- for (var x = 0, script; script = scripts[x]; x++) {
- var match = re.exec(script.src);
- if (match) {
- return match[1];
- }
- }
- alert('Could not detect Blockly\\'s directory name.');
- return '';
- })();
- this.BLOCKLY_BOOT = function() {
- // Execute after Closure has loaded.
- if (!this.goog) {
- alert('Error: Closure not found. Read this:\\n' +
- 'developers.google.com/blockly/hacking/closure');
- }
- // Build map of all dependencies (used and unused).
- var dir = this.BLOCKLY_DIR.match(/[^\\/]+$/)[0];
- """)
- add_dependency = []
- base_path = calcdeps.FindClosureBasePath(self.search_paths)
- for dep in calcdeps.BuildDependenciesFromFiles(self.search_paths):
- add_dependency.append(calcdeps.GetDepsLine(dep, base_path))
- add_dependency = "\n".join(add_dependency)
-
-
-
- m = re.search("[\\/]([^\\/]+)[\\/]core[\\/]blockly.js", add_dependency)
- add_dependency = re.sub("([\\/])" + re.escape(m.group(1)) +
- "([\\/]core[\\/])", '\\1" + dir + "\\2', add_dependency)
- f.write(add_dependency + "\n")
- provides = []
- for dep in calcdeps.BuildDependenciesFromFiles(self.search_paths):
- if not dep.filename.startswith(os.pardir + os.sep):
- provides.extend(dep.provides)
- provides.sort()
- f.write("\n")
- f.write("// Load Blockly.\n")
- for provide in provides:
- f.write("goog.require('%s');\n" % provide)
- f.write("""
- delete this.BLOCKLY_DIR;
- delete this.BLOCKLY_BOOT;
- };
- if (typeof DOMParser == 'undefined' && typeof require == 'function') {
- // Node.js needs DOMParser loaded separately.
- var DOMParser = require('xmldom').DOMParser;
- }
- // Delete any existing Closure (e.g. Soy's nogoog_shim).
- document.write('<script>var goog = undefined;</script>');
- // Load fresh Closure Library.
- document.write('<script src="' + this.BLOCKLY_DIR +
- '/../closure-library/closure/goog/base.js"></script>');
- document.write('<script>this.BLOCKLY_BOOT()</script>');
- """)
- f.close()
- print("SUCCESS: " + target_filename)
- class Gen_compressed(threading.Thread):
- """Generate a JavaScript file that contains all of Blockly's core and all
- required parts of Closure, compiled together.
- Uses the Closure Compiler's online API.
- Runs in a separate thread.
- """
- def __init__(self, search_paths):
- threading.Thread.__init__(self)
- self.search_paths = search_paths
- def run(self):
- self.gen_core()
- self.gen_blocks()
- self.gen_generator("arduino")
- def gen_core(self):
- target_filename = "blockly_compressed.js"
-
- params = [
- ("compilation_level", "SIMPLE_OPTIMIZATIONS"),
- ("use_closure_library", "true"),
- ("output_format", "json"),
- ("output_info", "compiled_code"),
- ("output_info", "warnings"),
- ("output_info", "errors"),
- ("output_info", "statistics"),
- ]
-
- filenames = calcdeps.CalculateDependencies(self.search_paths,
- [os.path.join("core", "blockly.js")])
- for filename in filenames:
-
- if filename.startswith(os.pardir + os.sep):
- continue
- f = open(filename)
- params.append(("js_code", "".join(f.readlines())))
- f.close()
- self.do_compile(params, target_filename, filenames, "")
- def gen_blocks(self):
- target_filename = "blocks_compressed.js"
-
- params = [
- ("compilation_level", "SIMPLE_OPTIMIZATIONS"),
- ("output_format", "json"),
- ("output_info", "compiled_code"),
- ("output_info", "warnings"),
- ("output_info", "errors"),
- ("output_info", "statistics"),
- ]
-
-
- params.append(("js_code", "goog.provide('Blockly.Blocks');"))
- filenames = glob.glob(os.path.join("blocks", "*.js"))
- for filename in filenames:
- f = open(filename)
- params.append(("js_code", "".join(f.readlines())))
- f.close()
-
- remove = "var Blockly={Blocks:{}};"
- self.do_compile(params, target_filename, filenames, remove)
- def gen_generator(self, language):
- target_filename = language + "_compressed.js"
-
- params = [
- ("compilation_level", "SIMPLE_OPTIMIZATIONS"),
- ("output_format", "json"),
- ("output_info", "compiled_code"),
- ("output_info", "warnings"),
- ("output_info", "errors"),
- ("output_info", "statistics"),
- ]
-
-
- params.append(("js_code", "goog.provide('Blockly.Generator');"))
- filenames = glob.glob(
- os.path.join("generators", language, "*.js"))
- filenames.insert(0, os.path.join("generators", language + ".js"))
- for filename in filenames:
- f = open(filename)
- params.append(("js_code", "".join(f.readlines())))
- f.close()
- filenames.insert(0, "[goog.provide]")
-
- remove = "var Blockly={Generator:{}};"
- self.do_compile(params, target_filename, filenames, remove)
- def do_compile(self, params, target_filename, filenames, remove):
-
- headers = {"Content-type": "application/x-www-form-urlencoded"}
- conn = httplib.HTTPConnection("closure-compiler.appspot.com")
- conn.request("POST", "/compile", urllib.urlencode(params), headers)
- response = conn.getresponse()
- json_str = response.read()
- conn.close()
-
- json_data = json.loads(json_str)
- def file_lookup(name):
- if not name.startswith("Input_"):
- return "???"
- n = int(name[6:]) - 1
- return filenames[n]
- if json_data.has_key("serverErrors"):
- errors = json_data["serverErrors"]
- for error in errors:
- print("SERVER ERROR: %s" % target_filename)
- print(error["error"])
- elif json_data.has_key("errors"):
- errors = json_data["errors"]
- for error in errors:
- print("FATAL ERROR")
- print(error["error"])
- if error["file"]:
- print("%s at line %d:" % (
- file_lookup(error["file"]), error["lineno"]))
- print(error["line"])
- print((" " * error["charno"]) + "^")
- sys.exit(1)
- else:
- if json_data.has_key("warnings"):
- warnings = json_data["warnings"]
- for warning in warnings:
- print("WARNING")
- print(warning["warning"])
- if warning["file"]:
- print("%s at line %d:" % (
- file_lookup(warning["file"]), warning["lineno"]))
- print(warning["line"])
- print((" " * warning["charno"]) + "^")
- print()
- if not json_data.has_key("compiledCode"):
- print("FATAL ERROR: Compiler did not return compiledCode.")
- sys.exit(1)
- code = HEADER + "\n" + json_data["compiledCode"]
- code = code.replace(remove, "")
-
- LICENSE = re.compile("""/\\*
- [\w ]+
- (Copyright \\d+ Google Inc.)
- https://developers.google.com/blockly/
- Licensed under the Apache License, Version 2.0 \(the "License"\);
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- \\*/""")
- code = re.sub(LICENSE, r"\n// \1 Apache License 2.0", code)
- stats = json_data["statistics"]
- original_b = stats["originalSize"]
- compressed_b = stats["compressedSize"]
- if original_b > 0 and compressed_b > 0:
- f = open(target_filename, "w")
- f.write(code)
- f.close()
- original_kb = int(original_b / 1024 + 0.5)
- compressed_kb = int(compressed_b / 1024 + 0.5)
- ratio = int(float(compressed_b) / float(original_b) * 100 + 0.5)
- print("SUCCESS: " + target_filename)
- print("Size changed from %d KB to %d KB (%d%%)." % (
- original_kb, compressed_kb, ratio))
- else:
- print("UNKNOWN ERROR")
- class Gen_langfiles(threading.Thread):
- """Generate JavaScript file for each natural language supported.
- Runs in a separate thread.
- """
- def __init__(self):
- threading.Thread.__init__(self)
- def _rebuild(self, srcs, dests):
-
- try:
- return (max(os.path.getmtime(src) for src in srcs) >
- min(os.path.getmtime(dest) for dest in dests))
- except OSError as e:
-
- if e.errno == errno.ENOENT:
-
- if e.filename in srcs:
- print("Source file missing: " + e.filename)
- sys.exit(1)
- else:
-
- return True
- else:
- print("Error checking file creation times: " + e)
- def run(self):
-
- if self._rebuild([os.path.join("msg", "messages.js")],
- [os.path.join("msg", "json", f) for f in
- ["en.json", "qqq.json", "synonyms.json"]]):
- try:
- subprocess.check_call([
- "python",
- os.path.join("i18n", "js_to_json.py"),
- "--input_file", "msg/messages.js",
- "--output_dir", "msg/json/",
- "--quiet"])
- except (subprocess.CalledProcessError, OSError) as e:
-
-
- print("Error running i18n/js_to_json.py: ", e)
- sys.exit(1)
-
-
-
- try:
-
- cmd = [
- "python",
- os.path.join("i18n", "create_messages.py"),
- "--source_lang_file", os.path.join("msg", "json", "en.json"),
- "--source_synonym_file", os.path.join("msg", "json", "synonyms.json"),
- "--key_file", os.path.join("msg", "json", "keys.json"),
- "--output_dir", os.path.join("msg", "js"),
- "--quiet"]
- json_files = glob.glob(os.path.join("msg", "json", "*.json"))
- json_files = [file for file in json_files if not
- (file.endswith(("keys.json", "synonyms.json", "qqq.json")))]
- cmd.extend(json_files)
- subprocess.check_call(cmd)
- except (subprocess.CalledProcessError, OSError) as e:
- print("Error running i18n/create_messages.py: ", e)
- sys.exit(1)
-
- for f in json_files:
-
- f = f.replace("json", "js")
- if os.path.isfile(f):
- print("SUCCESS: " + f)
- else:
- print("FAILED to create " + f)
- if __name__ == "__main__":
- try:
- calcdeps = import_path(os.path.join(
- os.path.pardir, "closure-library", "closure", "bin", "calcdeps.py"))
- except ImportError:
- if os.path.isdir(os.path.join(os.path.pardir, "closure-library-read-only")):
-
- print("Error: Closure directory needs to be renamed from"
- "'closure-library-read-only' to 'closure-library'.\n"
- "Please rename this directory.")
- else:
- print("""Error: Closure not found. Read this:
- https://developers.google.com/blockly/hacking/closure""")
- sys.exit(1)
- search_paths = calcdeps.ExpandDirectories(
- ["core", os.path.join(os.path.pardir, "closure-library")])
-
-
-
- Gen_uncompressed(search_paths).start()
- Gen_compressed(search_paths).start()
-
- Gen_langfiles().start()
|