123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675 |
- #!/usr/bin/python2.7
- # Compresses the core Blockly files into a single JavaScript file.
- #
- # Copyright 2012 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.
- # Usage: build.py <0 or more of accessible, core, generators, langfiles>
- # build.py with no parameters builds all files.
- # core builds blockly_compressed, blockly_uncompressed, and blocks_compressed.
- # accessible builds blockly_accessible_compressed,
- # blockly_accessible_uncompressed, and blocks_compressed.
- # generators builds every <language>_compressed.js.
- # langfiles builds every msg/js/<LANG>.js file.
- # This script generates four versions of Blockly's core files. The first pair
- # are:
- # blockly_compressed.js
- # blockly_uncompressed.js
- # The compressed file is a concatenation of all of Blockly's core files which
- # have been run through Google's Closure Compiler. This is done using the
- # online API (which takes a few seconds and requires an Internet connection).
- # The uncompressed file is a script that loads in each of Blockly's core files
- # one by one. This takes much longer for a browser to load, but is useful
- # when debugging code since line numbers are meaningful and variables haven't
- # been renamed. The uncompressed file also allows for a faster development
- # cycle since there is no need to rebuild or recompile, just reload.
- #
- # The second pair are:
- # blockly_accessible_compressed.js
- # blockly_accessible_uncompressed.js
- # These files are analogous to blockly_compressed and blockly_uncompressed,
- # but also include the visually-impaired module for Blockly.
- #
- # This script also generates:
- # blocks_compressed.js: The compressed Blockly language blocks.
- # javascript_compressed.js: The compressed JavaScript generator.
- # python_compressed.js: The compressed Python generator.
- # php_compressed.js: The compressed PHP generator.
- # lua_compressed.js: The compressed Lua generator.
- # dart_compressed.js: The compressed Dart generator.
- # msg/js/<LANG>.js for every language <LANG> defined in msg/js/<LANG>.json.
- 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, fnmatch, httplib, json, os, re, subprocess, threading, urllib
- REMOTE_COMPILER = "remote"
- CLOSURE_DIR = os.path.pardir
- CLOSURE_ROOT = os.path.pardir
- CLOSURE_LIBRARY = "closure-library"
- CLOSURE_COMPILER = REMOTE_COMPILER
- CLOSURE_DIR_NPM = "node_modules"
- CLOSURE_ROOT_NPM = os.path.join("node_modules")
- CLOSURE_LIBRARY_NPM = "google-closure-library"
- CLOSURE_COMPILER_NPM = "google-closure-compiler"
- 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) # Might be out of date.
- del sys.path[-1]
- return module
- def read(filename):
- f = open(filename)
- content = "".join(f.readlines())
- f.close()
- return content
- 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, target_filename, closure_env):
- threading.Thread.__init__(self)
- self.search_paths = search_paths
- self.target_filename = target_filename
- self.closure_env = closure_env
- def run(self):
- f = open(self.target_filename, 'w')
- f.write(HEADER)
- f.write(self.format_js("""
- var isNodeJS = !!(typeof module !== 'undefined' && module.exports &&
- typeof window === 'undefined');
- if (isNodeJS) {
- var window = {};
- require('{closure_library}');
- }
- window.BLOCKLY_DIR = (function() {
- if (!isNodeJS) {
- // Find name of current directory.
- var scripts = document.getElementsByTagName('script');
- var re = new RegExp('(.+)[\/]blockly_uncompressed(_vertical|_horizontal|)\.js$');
- for (var i = 0, script; script = scripts[i]; i++) {
- var match = re.exec(script.src);
- if (match) {
- return match[1];
- }
- }
- alert('Could not detect Blockly\\'s directory name.');
- }
- return '';
- })();
- window.BLOCKLY_BOOT = function() {
- var dir = '';
- if (isNodeJS) {
- require('{closure_library}');
- dir = 'blockly';
- } else {
- // Execute after Closure has loaded.
- if (!window.goog) {
- alert('Error: Closure not found. Read this:\\n' +
- 'developers.google.com/blockly/guides/modify/web/closure');
- }
- if (window.BLOCKLY_DIR.search(/node_modules/)) {
- dir = '..';
- } else {
- dir = window.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.sort() # Deterministic build.
- add_dependency = '\n'.join(add_dependency)
- # Find the Blockly directory name and replace it with a JS variable.
- # This allows blockly_uncompressed.js to be compiled on one computer and be
- # used on another, even if the directory name differs.
- 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(self.closure_env["closure_root"] + os.sep): # '../'
- provides.extend(dep.provides)
- provides.sort() # Deterministic build.
- f.write('\n')
- f.write('// Load Blockly.\n')
- for provide in provides:
- f.write("goog.require('%s');\n" % provide)
- f.write(self.format_js("""
- delete this.BLOCKLY_DIR;
- delete this.BLOCKLY_BOOT;
- };
- if (isNodeJS) {
- window.BLOCKLY_BOOT();
- module.exports = Blockly;
- } else {
- // 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="' + window.BLOCKLY_DIR +
- '/{closure_dir}/{closure_library}/closure/goog/base.js"></script>');
- document.write('<script>window.BLOCKLY_BOOT();</script>');
- }
- """))
- f.close()
- print("SUCCESS: " + self.target_filename)
- def format_js(self, code):
- """Format JS in a way that python's format method can work with to not
- consider brace-wrapped sections to be format replacements while still
- replacing known keys.
- """
- key_whitelist = self.closure_env.keys()
- keys_pipe_separated = reduce(lambda accum, key: accum + "|" + key, key_whitelist)
- begin_brace = re.compile(r"\{(?!%s)" % (keys_pipe_separated,))
- end_brace = re.compile(r"\}")
- def end_replacement(match):
- try:
- maybe_key = match.string[match.string[:match.start()].rindex("{") + 1:match.start()]
- except ValueError:
- return "}}"
- if maybe_key and maybe_key in key_whitelist:
- return "}"
- else:
- return "}}"
- return begin_brace.sub("{{", end_brace.sub(end_replacement, code)).format(**self.closure_env)
- 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, closure_env):
- threading.Thread.__init__(self)
- self.search_paths = search_paths
- self.closure_env = closure_env
- def run(self):
- self.gen_core()
- self.gen_blocks()
- self.gen_generator("arduino")
- self.gen_generator("python")
- def gen_core(self):
- target_filename = "blockly_compressed.js"
- if self.closure_env["closure_compiler"] == REMOTE_COMPILER:
- # Define the parameters for the POST request.
- 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"),
- ("warning_level", "DEFAULT"),
- ]
- # Read in all the source files.
- filenames = calcdeps.CalculateDependencies(self.search_paths,
- [os.path.join("core", "blockly.js")])
- filenames.sort() # Deterministic build.
- for filename in filenames:
- # Filter out the Closure files (the compiler will add them).
- if filename.startswith(os.pardir + os.sep): # '../'
- continue
- f = open(filename)
- params.append(("js_code", "".join(f.readlines())))
- f.close()
- else:
- # Define the parameters for the POST request.
- params = [
- ("compilation_level", "SIMPLE"),
- ("language_in", "ECMASCRIPT_2017"),
- ("language_out", "ECMASCRIPT5"),
- ("rewrite_polyfills", "false"),
- ("define", "goog.DEBUG=false"),
- ]
- # Read in all the source files.
- filenames = calcdeps.CalculateDependencies(search_paths,
- [os.path.join("core", "blockly.js")])
- filenames.sort() # Deterministic build.
- for filename in filenames:
- # Append filenames as false arguments the step before compiling will
- # either transform them into arguments for local or remote compilation
- params.append(("js_file", filename))
- self.do_compile(params, target_filename, filenames, [])
- def gen_blocks(self):
- target_filename = "blocks_compressed.js"
- if self.closure_env["closure_compiler"] == REMOTE_COMPILER:
- # Define the parameters for the POST request.
- params = [
- ("compilation_level", "SIMPLE_OPTIMIZATIONS"),
- ("output_format", "json"),
- ("output_info", "compiled_code"),
- ("output_info", "warnings"),
- ("output_info", "errors"),
- ("output_info", "statistics"),
- ("warning_level", "DEFAULT"),
- ]
- # Read in all the source files.
- # Add Blockly.Blocks to be compatible with the compiler.
- params.append(("js_code", "goog.provide('Blockly');goog.provide('Blockly.Blocks');"))
- params.append(("js_code", "goog.provide('Blockly.Types');"))
- filenames = []
- for root, folders, files in os.walk("blocks"):
- for filename in fnmatch.filter(files, "*.js"):
- filenames.append(os.path.join(root, filename))
- for filename in filenames:
- f = open(filename)
- params.append(("js_code", "".join(f.readlines())))
- f.close()
- else:
- # Define the parameters for the POST request.
- params = [
- ("compilation_level", "SIMPLE"),
- ]
- # Read in all the source files.
- # Add Blockly.Blocks to be compatible with the compiler.
- params.append(("js_file", os.path.join("build", "gen_blocks.js")))
- # Add Blockly.Colours for use of centralized colour bank
- filenames = []
- for root, folders, files in os.walk("blocks"):
- for filename in fnmatch.filter(files, "*.js"):
- filenames.append(os.path.join(root, filename))
- for filename in filenames:
- # Append filenames as false arguments the step before compiling will
- # either transform them into arguments for local or remote compilation
- params.append(("js_file", filename))
- # Remove Blockly.Blocks to be compatible with Blockly.
- remove = ["var Blockly={Blocks:{}};", "Blockly.Types={};", "var Blockly={Blocks:{},Types:{}};"]
- self.do_compile(params, target_filename, filenames, remove)
- def gen_generator(self, language):
- target_filename = language + "_compressed.js"
- if self.closure_env["closure_compiler"] == REMOTE_COMPILER:
- # Define the parameters for the POST request.
- params = [
- ("compilation_level", "SIMPLE_OPTIMIZATIONS"),
- ("output_format", "json"),
- ("output_info", "compiled_code"),
- ("output_info", "warnings"),
- ("output_info", "errors"),
- ("output_info", "statistics"),
- ]
- # Read in all the source files.
- # Add Blockly.Generator to be compatible with the compiler.
- params.append(("js_code", "goog.provide('Blockly.Generator');"))
- params.append(("js_code", "goog.provide('Blockly.StaticTyping');"))
- 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]")
- else:
- # Define the parameters for the POST request.
- params = [
- ("compilation_level", "SIMPLE"),
- ]
- # Read in all the source files.
- # Add Blockly.Generator to be compatible with the compiler.
- params.append(("js_file", os.path.join("build", "gen_generator.js")))
- filenames = glob.glob(
- os.path.join("generators", language, "*.js"))
- filenames.insert(0, os.path.join("generators", language + ".js"))
- for filename in filenames:
- # Append filenames as false arguments the step before compiling will
- # either transform them into arguments for local or remote compilation
- params.append(("js_file", filename))
- filenames.insert(0, "[goog.provide]")
- # Remove Blockly.Generator to be compatible with Blockly.
- remove = ["var Blockly={Generator:{}};", "Blockly.StaticTyping={};", "var Blockly={Generator:{},StaticTyping:{}};"]
- self.do_compile(params, target_filename, filenames, remove)
- def do_compile(self, params, target_filename, filenames, remove):
- if self.closure_env["closure_compiler"] == REMOTE_COMPILER:
- do_compile = self.do_compile_remote
- else:
- do_compile = self.do_compile_local
- json_data = do_compile(params, target_filename)
- if self.report_errors(target_filename, filenames, json_data):
- self.write_output(target_filename, remove, json_data)
- self.report_stats(target_filename, json_data)
- def do_compile_local(self, params, target_filename):
- filter_keys = ["use_closure_library"]
- # Drop arg if arg is js_file else add dashes
- dash_params = []
- for (arg, value) in params:
- dash_params.append((value,) if arg == "js_file" else ("--" + arg, value))
- # Flatten dash_params into dash_args if their keys are not in filter_keys
- dash_args = []
- for pair in dash_params:
- if pair[0][2:] not in filter_keys:
- dash_args.extend(pair)
- # Build the final args array by prepending google-closure-compiler to
- # dash_args and dropping any falsy members
- args = []
- for group in [["google-closure-compiler"], dash_args]:
- args.extend(filter(lambda item: item, group))
- proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
- (stdout, stderr) = proc.communicate()
- # Build the JSON response.
- filesizes = [os.path.getsize(value) for (arg, value) in params if arg == "js_file"]
- return dict(
- compiledCode=stdout,
- statistics=dict(
- originalSize=reduce(lambda v, size: v + size, filesizes, 0),
- compressedSize=len(stdout),
- )
- )
- def do_compile_remote(self, params, target_filename):
- # Send the request to Google.
- headers = {"Content-type": "application/x-www-form-urlencoded"}
- conn = httplib.HTTPSConnection("closure-compiler.appspot.com")
- conn.request("POST", "/compile", urllib.urlencode(params), headers)
- response = conn.getresponse()
- json_str = response.read()
- conn.close()
- # Parse the JSON response.
- return json.loads(json_str)
- def report_errors(self, target_filename, filenames, json_data):
- 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()
- return True
- return False
- def write_output(self, target_filename, remove, json_data):
- if not json_data.has_key("compiledCode"):
- print("FATAL ERROR: Compiler did not return compiledCode.")
- sys.exit(1)
- code = HEADER + "\n" + json_data["compiledCode"]
- for code_statement in remove:
- code = code.replace(code_statement, "")
- # Trim down Google's (and only Google's) Apache licences.
- # The Closure Compiler preserves these.
- 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, "", 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()
- def report_stats(self, target_filename, json_data):
- stats = json_data["statistics"]
- original_b = stats["originalSize"]
- compressed_b = stats["compressedSize"]
- if original_b > 0 and compressed_b > 0:
- 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):
- # Determine whether any of the files in srcs is newer than any in 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:
- # Was a file not found?
- if e.errno == errno.ENOENT:
- # If it was a source file, we can't proceed.
- if e.filename in srcs:
- print("Source file missing: " + e.filename)
- sys.exit(1)
- else:
- # If a destination file was missing, rebuild.
- return True
- else:
- print("Error checking file creation times: " + e)
- def run(self):
- # The files msg/json/{en,qqq,synonyms}.json depend on msg/messages.js.
- 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:
- # Documentation for subprocess.check_call says that CalledProcessError
- # will be raised on failure, but I found that OSError is also possible.
- print("Error running i18n/js_to_json.py: ", e)
- sys.exit(1)
- # Checking whether it is necessary to rebuild the js files would be a lot of
- # work since we would have to compare each <lang>.json file with each
- # <lang>.js file. Rebuilding is easy and cheap, so just go ahead and do it.
- try:
- # Use create_messages.py to create .js files from .json files.
- 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)
- # Output list of .js files created.
- for f in json_files:
- # This assumes the path to the current directory does not contain "json".
- f = f.replace("json", "js")
- if os.path.isfile(f):
- print("SUCCESS: " + f)
- else:
- print("FAILED to create " + f)
- if __name__ == "__main__":
- try:
- closure_dir = CLOSURE_DIR_NPM
- closure_root = CLOSURE_ROOT_NPM
- closure_library = CLOSURE_LIBRARY_NPM
- closure_compiler = CLOSURE_COMPILER_NPM
-
- # Load calcdeps from the local library
- calcdeps = import_path(os.path.join(
- closure_root, closure_library, "closure", "bin", "calcdeps.py"))
- # Sanity check the local compiler
- test_args = [closure_compiler, os.path.join("build", "test_input.js")]
- test_proc = subprocess.Popen(test_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
- (stdout, _) = test_proc.communicate()
- assert stdout == read(os.path.join("build", "test_expect.js"))
- print("Using local compiler: google-closure-compiler ...\n")
- except (ImportError, AssertionError):
- print("Using remote compiler: closure-compiler.appspot.com ...\n")
- try:
- closure_dir = CLOSURE_DIR
- closure_root = CLOSURE_ROOT
- closure_library = CLOSURE_LIBRARY
- closure_compiler = CLOSURE_COMPILER
-
- calcdeps = import_path(os.path.join(
- closure_root, closure_library, "closure", "bin", "calcdeps.py"))
- except ImportError:
- if os.path.isdir(os.path.join(os.path.pardir, "closure-library-read-only")):
- # Dir got renamed when Closure moved from Google Code to GitHub in 2014.
- print("Error: Closure directory needs to be renamed from"
- "'closure-library-read-only' to 'closure-library'.\n"
- "Please rename this directory.")
- elif os.path.isdir(os.path.join(os.path.pardir, "google-closure-library")):
- # When Closure is installed by npm, it is named "google-closure-library".
- #calcdeps = import_path(os.path.join(
- # os.path.pardir, "google-closure-library", "closure", "bin", "calcdeps.py"))
- print("Error: Closure directory needs to be renamed from"
- "'google-closure-library' to 'closure-library'.\n"
- "Please rename this directory.")
- else:
- print("""Error: Closure not found. Read this:developers.google.com/blockly/guides/modify/web/closure""")
- sys.exit(1)
- search_paths = calcdeps.ExpandDirectories(["core", os.path.join(os.path.pardir, "closure-library")])
- search_paths.sort() # Deterministic build.
- closure_env = {
- "closure_dir": closure_dir,
- "closure_root": closure_root,
- "closure_library": closure_library,
- "closure_compiler": closure_compiler,
- }
- # Uncompressed and compressed are run in parallel threads.
- # Uncompressed is limited by processor speed.
- Gen_uncompressed(search_paths, 'blockly_uncompressed.js', closure_env).start()
- # Compressed is limited by network and server speed.
- Gen_compressed(search_paths, closure_env).start()
- # This is run locally in a separate thread
- # defaultlangfiles checks for changes in the msg files, while manually asking
- # to build langfiles will force the messages to be rebuilt.
- Gen_langfiles().start()
|