Index: Source/devtools/scripts/concatenate_application_code.py |
diff --git a/Source/devtools/scripts/concatenate_application_code.py b/Source/devtools/scripts/concatenate_application_code.py |
index 978dd061fd3f7d896e93082abc71f4cdcbcb0fe2..2418b92292c255da0bbce3fd1b53bdc27fc28fca 100755 |
--- a/Source/devtools/scripts/concatenate_application_code.py |
+++ b/Source/devtools/scripts/concatenate_application_code.py |
@@ -5,9 +5,14 @@ |
# found in the LICENSE file. |
""" |
-Concatenates autostart modules, application modules' module.json descriptors, |
-and the application loader into a single script. |
-Also concatenates all workers' dependencies into individual worker loader scripts. |
+Release: |
+ - Concatenates autostart modules, application modules' module.json descriptors, |
+ and the application loader into a single script. |
+ - Concatenates all workers' dependencies into individual worker loader scripts. |
+ - Builds app.html referencing the application script. |
+Debug: |
+ - Copies the module directories into their destinations. |
+ - Copies app.html as-is. |
""" |
from cStringIO import StringIO |
@@ -17,6 +22,7 @@ import copy |
import modular_build |
import os |
import re |
+import shutil |
import sys |
try: |
@@ -34,103 +40,191 @@ sys.path.append(rjsmin_path) |
import rjsmin |
-def minify_if_needed(javascript, minify): |
- return rjsmin.jsmin(javascript) if minify else javascript |
+def minify_js(javascript): |
+ return rjsmin.jsmin(javascript) |
def concatenated_module_filename(module_name, output_dir): |
return path.join(output_dir, module_name + '_module.js') |
-def concatenate_autostart_modules(descriptors, application_dir, output_dir, output): |
- non_autostart = set() |
- sorted_module_names = descriptors.sorted_modules() |
- for name in sorted_module_names: |
- desc = descriptors.modules[name] |
- name = desc['name'] |
- type = descriptors.application[name].get('type') |
- if type == 'autostart': |
- deps = set(desc.get('dependencies', [])) |
- non_autostart_deps = deps & non_autostart |
- if len(non_autostart_deps): |
- bail_error('Non-autostart dependencies specified for the autostarted module "%s": %s' % (name, non_autostart_deps)) |
- output.write('\n/* Module %s */\n' % name) |
- modular_build.concatenate_scripts(desc.get('scripts'), path.join(application_dir, name), output_dir, output) |
- elif type != 'worker': |
- non_autostart.add(name) |
- |
- |
-def concatenate_application_script(application_name, descriptors, application_dir, output_dir, minify): |
- application_loader_name = application_name + '.js' |
- output = StringIO() |
- runtime_contents = read_file(path.join(application_dir, 'Runtime.js')) |
- runtime_contents = re.sub('var allDescriptors = \[\];', 'var allDescriptors = %s;' % release_module_descriptors(descriptors.modules).replace("\\", "\\\\"), runtime_contents, 1) |
- output.write('/* Runtime.js */\n') |
- output.write(runtime_contents) |
- output.write('\n/* Autostart modules */\n') |
- concatenate_autostart_modules(descriptors, application_dir, output_dir, output) |
- output.write('/* Application descriptor %s */\n' % (application_name + '.json')) |
- output.write('applicationDescriptor = ') |
- output.write(descriptors.application_json) |
- output.write(';\n/* Application loader */\n') |
- output.write(read_file(path.join(application_dir, application_loader_name))) |
- |
- write_file(path.join(output_dir, application_loader_name), minify_if_needed(output.getvalue(), minify)) |
- output.close() |
- |
- |
-def concatenate_dynamic_module(module_name, descriptors, application_dir, output_dir, minify): |
- scripts = descriptors.modules[module_name].get('scripts') |
- if not scripts: |
- return |
- module_dir = path.join(application_dir, module_name) |
- output = StringIO() |
- modular_build.concatenate_scripts(scripts, module_dir, output_dir, output) |
- output_file_path = concatenated_module_filename(module_name, output_dir) |
- write_file(output_file_path, minify_if_needed(output.getvalue(), minify)) |
- output.close() |
- |
- |
-def concatenate_worker(module_name, descriptors, application_dir, output_dir, minify): |
- descriptor = descriptors.modules[module_name] |
- scripts = descriptor.get('scripts') |
- if not scripts: |
- return |
- worker_dir = path.join(application_dir, module_name) |
- output_file_path = concatenated_module_filename(module_name, output_dir) |
- |
- output = StringIO() |
- output.write('/* Worker %s */\n' % module_name) |
- dependencies = descriptors.sorted_dependencies_closure(module_name) |
- dep_descriptors = [] |
- for dep_name in dependencies: |
- dep_descriptor = descriptors.modules[dep_name] |
- dep_descriptors.append(dep_descriptor) |
- scripts = dep_descriptor.get('scripts') |
- if scripts: |
- output.write('\n/* Module %s */\n' % dep_name) |
- modular_build.concatenate_scripts(scripts, path.join(application_dir, dep_name), output_dir, output) |
- |
- write_file(output_file_path, minify_if_needed(output.getvalue(), minify)) |
- output.close() |
- |
- |
-def release_module_descriptors(module_descriptors): |
- result = [] |
- for name in module_descriptors: |
- module = copy.copy(module_descriptors[name]) |
- # Clear scripts, as they are not used at runtime |
- # (only the fact of their presence is important). |
- if module.get('scripts'): |
- module['scripts'] = [] |
- result.append(module) |
- return json.dumps(result) |
- |
- |
-def build_application(application_name, loader, application_dir, output_dir, minify): |
+def hardlink_or_copy_dir(src, dest): |
+ if path.exists(dest): |
+ shutil.rmtree(dest) |
+ os.mkdir(dest) |
+ for root, dirs, files in os.walk(src): |
+ for name in files: |
+ src_name = path.join(src, name) |
dgozman
2014/10/13 13:01:52
src_name = path.join(root, name)
apavlov
2014/10/13 15:02:21
Done.
|
+ dest_name = path.join(dest, name) |
dgozman
2014/10/13 13:01:52
dest_name = path.join(dest, path.relpath(root, src
apavlov
2014/10/13 15:02:21
dest_name = path.join(dest, path.join(path.relpath
|
+ if hasattr(os, 'link'): |
+ os.link(src_name, dest_name) |
+ else: |
+ shutil.copy(src_name, dest_name) |
+ for name in dirs: |
+ hardlink_or_copy_dir(path.join(src, name), path.join(dest, name)) |
dgozman
2014/10/13 13:01:52
os.walk is already recursive.
apavlov
2014/10/13 15:02:21
Acknowledged.
|
+ |
+ |
+class AppBuilder: |
dgozman
2014/10/13 13:01:52
You should probably have |build_app| function defi
apavlov
2014/10/13 15:02:21
We'd like to get a clear error thrown in case buil
|
+ def __init__(self, application_name, descriptors, application_dir, output_dir): |
+ self.application_name = application_name |
+ self.descriptors = descriptors |
+ self.application_dir = application_dir |
+ self.output_dir = output_dir |
+ |
+ |
+# Outputs: |
+# app_name.html |
dgozman
2014/10/13 13:01:52
Maybe <app_name>.html and <app_name>.js ?
apavlov
2014/10/13 15:02:21
Ugh, it's a bit outdated patch... I've got this lo
|
+# app_name.js |
+# <module_name>_module.js |
+class ReleaseBuilder(AppBuilder): |
+ def __init__(self, application_name, descriptors, application_dir, output_dir): |
+ AppBuilder.__init__(self, application_name, descriptors, application_dir, output_dir) |
+ |
+ def build_app(self): |
+ self._build_html() |
+ self._build_app_script() |
+ for module in filter(lambda desc: not desc.get('type'), self.descriptors.application.values()): |
+ self._concatenate_dynamic_module(module['name']) |
+ for module in filter(lambda desc: desc.get('type') == 'worker', self.descriptors.application.values()): |
+ self._concatenate_worker(module['name']) |
+ |
+ def _build_html(self): |
+ html_name = self.application_name + '.html' |
+ output = StringIO() |
+ with open(path.join(self.application_dir, html_name), 'r') as app_input_html: |
dgozman
2014/10/13 13:01:52
This whole processing tells us that we should gene
apavlov
2014/10/13 15:02:21
This is just code moved from generate_devtools_htm
dgozman
2014/10/14 09:21:08
I see, but my point about generating is still vali
apavlov
2014/10/14 10:02:58
I'm not questioning this, I'm just saying that we
|
+ for line in app_input_html: |
+ if '<script ' in line or '<link ' in line: |
+ continue |
+ if '</head>' in line: |
+ output.write(self._generate_include_tag("%s.css" % self.application_name)) |
+ output.write(self._generate_include_tag("%s.js" % self.application_name)) |
+ output.write(line) |
+ |
+ write_file(path.join(self.output_dir, html_name), output.getvalue()) |
+ output.close() |
+ |
+ def _build_app_script(self): |
+ script_name = self.application_name + '.js' |
+ output = StringIO() |
+ self._concatenate_application_script(output) |
+ write_file(path.join(self.output_dir, script_name), output.getvalue()) |
+ output.close() |
+ |
+ def _generate_include_tag(self, resource_path): |
+ if (resource_path.endswith('.js')): |
+ return ' <script type="text/javascript" src="%s"></script>\n' % resource_path |
+ elif (resource_path.endswith('.css')): |
+ return ' <link rel="stylesheet" type="text/css" href="%s">\n' % resource_path |
+ else: |
+ assert resource_path |
+ |
+ def _release_module_descriptors(self): |
+ module_descriptors = self.descriptors.modules |
+ result = [] |
+ for name in module_descriptors: |
+ module = copy.copy(module_descriptors[name]) |
+ # Clear scripts, as they are not used at runtime |
+ # (only the fact of their presence is important). |
+ if module.get('scripts'): |
+ module['scripts'] = [] |
+ result.append(module) |
+ return json.dumps(result) |
+ |
+ def _concatenate_autostart_modules(self, output): |
+ non_autostart = set() |
+ sorted_module_names = self.descriptors.sorted_modules() |
+ for name in sorted_module_names: |
+ desc = self.descriptors.modules[name] |
+ name = desc['name'] |
+ type = self.descriptors.application[name].get('type') |
+ if type == 'autostart': |
+ deps = set(desc.get('dependencies', [])) |
+ non_autostart_deps = deps & non_autostart |
+ if len(non_autostart_deps): |
+ bail_error('Non-autostart dependencies specified for the autostarted module "%s": %s' % (name, non_autostart_deps)) |
+ output.write('\n/* Module %s */\n' % name) |
+ modular_build.concatenate_scripts(desc.get('scripts'), path.join(self.application_dir, name), self.output_dir, output) |
+ elif type != 'worker': |
+ non_autostart.add(name) |
+ |
+ def _concatenate_application_script(self, output): |
+ application_loader_name = self.application_name + '.js' |
+ runtime_contents = read_file(path.join(self.application_dir, 'Runtime.js')) |
+ runtime_contents = re.sub('var allDescriptors = \[\];', 'var allDescriptors = %s;' % self._release_module_descriptors().replace("\\", "\\\\"), runtime_contents, 1) |
+ output.write('/* Runtime.js */\n') |
+ output.write(runtime_contents) |
+ output.write('\n/* Autostart modules */\n') |
+ self._concatenate_autostart_modules(output) |
+ output.write('/* Application descriptor %s */\n' % (self.application_name + '.json')) |
+ output.write('applicationDescriptor = ') |
+ output.write(self.descriptors.application_json) |
+ output.write('\n/* Application loader */\n') |
+ output.write(read_file(path.join(self.application_dir, application_loader_name))) |
+ |
+ def _concatenate_dynamic_module(self, module_name): |
+ module = self.descriptors.modules[module_name] |
+ scripts = module.get('scripts') |
+ if not scripts: |
+ return |
+ module_dir = path.join(self.application_dir, module_name) |
+ output = StringIO() |
+ modular_build.concatenate_scripts(scripts, module_dir, self.output_dir, output) |
+ output_file_path = concatenated_module_filename(module_name, self.output_dir) |
+ write_file(output_file_path, minify_js(output.getvalue())) |
+ output.close() |
+ |
+ def _concatenate_worker(self, module_name): |
+ descriptor = self.descriptors.modules[module_name] |
+ scripts = descriptor.get('scripts') |
+ if not scripts: |
+ return |
+ |
+ output = StringIO() |
+ output.write('/* Worker %s */\n' % module_name) |
+ dep_descriptors = [] |
+ for dep_name in self.descriptors.sorted_dependencies_closure(module_name): |
+ dep_descriptor = self.descriptors.modules[dep_name] |
+ dep_descriptors.append(dep_descriptor) |
+ scripts = dep_descriptor.get('scripts') |
+ if scripts: |
+ output.write('\n/* Module %s */\n' % dep_name) |
+ modular_build.concatenate_scripts(scripts, path.join(self.application_dir, dep_name), self.output_dir, output) |
+ |
+ output_file_path = concatenated_module_filename(module_name, self.output_dir) |
+ write_file(output_file_path, minify_js(output.getvalue())) |
+ output.close() |
+ |
+ |
+# Outputs: |
+# app_name.html as-is |
dgozman
2014/10/13 13:01:52
<app_name>.html ?
apavlov
2014/10/13 15:02:21
Done.
|
+# <module_name>/<all_files> |
+class DebugBuilder(AppBuilder): |
+ def __init__(self, application_name, descriptors, application_dir, output_dir): |
+ AppBuilder.__init__(self, application_name, descriptors, application_dir, output_dir) |
+ |
+ def build_app(self): |
+ self._build_html() |
+ for module_name in self.descriptors.modules: |
+ module = self.descriptors.modules[module_name] |
+ input_module_dir = path.join(self.application_dir, module_name) |
+ output_module_dir = path.join(self.output_dir, module_name) |
+ hardlink_or_copy_dir(input_module_dir, output_module_dir) |
+ |
+ def _build_html(self): |
+ html_name = self.application_name + '.html' |
+ output = StringIO() |
+ with open(path.join(self.application_dir, html_name), 'r') as app_input_html: |
+ for line in app_input_html: |
+ output.write(line) |
+ |
+ write_file(path.join(self.output_dir, html_name), output.getvalue()) |
dgozman
2014/10/13 13:01:52
Why not shutil.copy?
apavlov
2014/10/13 15:02:21
I will add something else into here in a subsequen
dgozman
2014/10/14 09:21:08
Maybe change shutil.copy to this processing in the
apavlov
2014/10/14 10:02:58
Done, even though exactly this code used to run wh
|
+ output.close() |
+ |
+ |
+def build_application(application_name, loader, application_dir, output_dir, release_mode): |
descriptors = loader.load_application(application_name + '.json') |
- concatenate_application_script(application_name, descriptors, application_dir, output_dir, minify) |
- for module in filter(lambda desc: not desc.get('type'), descriptors.application.values()): |
- concatenate_dynamic_module(module['name'], descriptors, application_dir, output_dir, minify) |
- for module in filter(lambda desc: desc.get('type') == 'worker', descriptors.application.values()): |
- concatenate_worker(module['name'], descriptors, application_dir, output_dir, minify) |
+ if release_mode: |
+ builder = ReleaseBuilder(application_name, descriptors, application_dir, output_dir) |
+ else: |
+ builder = DebugBuilder(application_name, descriptors, application_dir, output_dir) |
+ builder.build_app() |