Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2014 The Chromium Authors. All rights reserved. | 3 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """ | 7 """ |
| 8 Concatenates autostart modules, application modules' module.json descriptors, | 8 Release: |
| 9 and the application loader into a single script. | 9 - Concatenates autostart modules, application modules' module.json descriptors , |
| 10 Also concatenates all workers' dependencies into individual worker loader script s. | 10 and the application loader into a single script. |
| 11 - Concatenates all workers' dependencies into individual worker loader scripts . | |
| 12 - Builds app.html referencing the application script. | |
| 13 Debug: | |
| 14 - Copies the module directories into their destinations. | |
| 15 - Copies app.html as-is. | |
| 11 """ | 16 """ |
| 12 | 17 |
| 13 from cStringIO import StringIO | 18 from cStringIO import StringIO |
| 14 from os import path | 19 from os import path |
| 15 from modular_build import read_file, write_file, bail_error | 20 from modular_build import read_file, write_file, bail_error |
| 16 import copy | 21 import copy |
| 17 import modular_build | 22 import modular_build |
| 18 import os | 23 import os |
| 19 import re | 24 import re |
| 25 import shutil | |
| 20 import sys | 26 import sys |
| 21 | 27 |
| 22 try: | 28 try: |
| 23 import simplejson as json | 29 import simplejson as json |
| 24 except ImportError: | 30 except ImportError: |
| 25 import json | 31 import json |
| 26 | 32 |
| 27 rjsmin_path = os.path.abspath(os.path.join( | 33 rjsmin_path = os.path.abspath(os.path.join( |
| 28 os.path.dirname(__file__), | 34 os.path.dirname(__file__), |
| 29 "..", | 35 "..", |
| 30 "..", | 36 "..", |
| 31 "build", | 37 "build", |
| 32 "scripts")) | 38 "scripts")) |
| 33 sys.path.append(rjsmin_path) | 39 sys.path.append(rjsmin_path) |
| 34 import rjsmin | 40 import rjsmin |
| 35 | 41 |
| 36 | 42 |
| 37 def minify_if_needed(javascript, minify): | 43 def minify_js(javascript): |
| 38 return rjsmin.jsmin(javascript) if minify else javascript | 44 return rjsmin.jsmin(javascript) |
| 39 | 45 |
| 40 | 46 |
| 41 def concatenated_module_filename(module_name, output_dir): | 47 def concatenated_module_filename(module_name, output_dir): |
| 42 return path.join(output_dir, module_name + '_module.js') | 48 return path.join(output_dir, module_name + '_module.js') |
| 43 | 49 |
| 44 | 50 |
| 45 def concatenate_autostart_modules(descriptors, application_dir, output_dir, outp ut): | 51 def hardlink_or_copy_dir(src, dest): |
| 46 non_autostart = set() | 52 if path.exists(dest): |
| 47 sorted_module_names = descriptors.sorted_modules() | 53 shutil.rmtree(dest) |
| 48 for name in sorted_module_names: | 54 os.mkdir(dest) |
| 49 desc = descriptors.modules[name] | 55 for root, dirs, files in os.walk(src): |
| 50 name = desc['name'] | 56 for name in files: |
| 51 type = descriptors.application[name].get('type') | 57 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.
| |
| 52 if type == 'autostart': | 58 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
| |
| 53 deps = set(desc.get('dependencies', [])) | 59 if hasattr(os, 'link'): |
| 54 non_autostart_deps = deps & non_autostart | 60 os.link(src_name, dest_name) |
| 55 if len(non_autostart_deps): | 61 else: |
| 56 bail_error('Non-autostart dependencies specified for the autosta rted module "%s": %s' % (name, non_autostart_deps)) | 62 shutil.copy(src_name, dest_name) |
| 57 output.write('\n/* Module %s */\n' % name) | 63 for name in dirs: |
| 58 modular_build.concatenate_scripts(desc.get('scripts'), path.join(app lication_dir, name), output_dir, output) | 64 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.
| |
| 59 elif type != 'worker': | |
| 60 non_autostart.add(name) | |
| 61 | 65 |
| 62 | 66 |
| 63 def concatenate_application_script(application_name, descriptors, application_di r, output_dir, minify): | 67 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
| |
| 64 application_loader_name = application_name + '.js' | 68 def __init__(self, application_name, descriptors, application_dir, output_di r): |
| 65 output = StringIO() | 69 self.application_name = application_name |
| 66 runtime_contents = read_file(path.join(application_dir, 'Runtime.js')) | 70 self.descriptors = descriptors |
| 67 runtime_contents = re.sub('var allDescriptors = \[\];', 'var allDescriptors = %s;' % release_module_descriptors(descriptors.modules).replace("\\", "\\\\"), runtime_contents, 1) | 71 self.application_dir = application_dir |
| 68 output.write('/* Runtime.js */\n') | 72 self.output_dir = output_dir |
| 69 output.write(runtime_contents) | |
| 70 output.write('\n/* Autostart modules */\n') | |
| 71 concatenate_autostart_modules(descriptors, application_dir, output_dir, outp ut) | |
| 72 output.write('/* Application descriptor %s */\n' % (application_name + '.jso n')) | |
| 73 output.write('applicationDescriptor = ') | |
| 74 output.write(descriptors.application_json) | |
| 75 output.write(';\n/* Application loader */\n') | |
| 76 output.write(read_file(path.join(application_dir, application_loader_name))) | |
| 77 | |
| 78 write_file(path.join(output_dir, application_loader_name), minify_if_needed( output.getvalue(), minify)) | |
| 79 output.close() | |
| 80 | 73 |
| 81 | 74 |
| 82 def concatenate_dynamic_module(module_name, descriptors, application_dir, output _dir, minify): | 75 # Outputs: |
| 83 scripts = descriptors.modules[module_name].get('scripts') | 76 # 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
| |
| 84 if not scripts: | 77 # app_name.js |
| 85 return | 78 # <module_name>_module.js |
| 86 module_dir = path.join(application_dir, module_name) | 79 class ReleaseBuilder(AppBuilder): |
| 87 output = StringIO() | 80 def __init__(self, application_name, descriptors, application_dir, output_di r): |
| 88 modular_build.concatenate_scripts(scripts, module_dir, output_dir, output) | 81 AppBuilder.__init__(self, application_name, descriptors, application_dir , output_dir) |
| 89 output_file_path = concatenated_module_filename(module_name, output_dir) | 82 |
| 90 write_file(output_file_path, minify_if_needed(output.getvalue(), minify)) | 83 def build_app(self): |
| 91 output.close() | 84 self._build_html() |
| 85 self._build_app_script() | |
| 86 for module in filter(lambda desc: not desc.get('type'), self.descriptors .application.values()): | |
| 87 self._concatenate_dynamic_module(module['name']) | |
| 88 for module in filter(lambda desc: desc.get('type') == 'worker', self.des criptors.application.values()): | |
| 89 self._concatenate_worker(module['name']) | |
| 90 | |
| 91 def _build_html(self): | |
| 92 html_name = self.application_name + '.html' | |
| 93 output = StringIO() | |
| 94 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
| |
| 95 for line in app_input_html: | |
| 96 if '<script ' in line or '<link ' in line: | |
| 97 continue | |
| 98 if '</head>' in line: | |
| 99 output.write(self._generate_include_tag("%s.css" % self.appl ication_name)) | |
| 100 output.write(self._generate_include_tag("%s.js" % self.appli cation_name)) | |
| 101 output.write(line) | |
| 102 | |
| 103 write_file(path.join(self.output_dir, html_name), output.getvalue()) | |
| 104 output.close() | |
| 105 | |
| 106 def _build_app_script(self): | |
| 107 script_name = self.application_name + '.js' | |
| 108 output = StringIO() | |
| 109 self._concatenate_application_script(output) | |
| 110 write_file(path.join(self.output_dir, script_name), output.getvalue()) | |
| 111 output.close() | |
| 112 | |
| 113 def _generate_include_tag(self, resource_path): | |
| 114 if (resource_path.endswith('.js')): | |
| 115 return ' <script type="text/javascript" src="%s"></script>\n' % r esource_path | |
| 116 elif (resource_path.endswith('.css')): | |
| 117 return ' <link rel="stylesheet" type="text/css" href="%s">\n' % r esource_path | |
| 118 else: | |
| 119 assert resource_path | |
| 120 | |
| 121 def _release_module_descriptors(self): | |
| 122 module_descriptors = self.descriptors.modules | |
| 123 result = [] | |
| 124 for name in module_descriptors: | |
| 125 module = copy.copy(module_descriptors[name]) | |
| 126 # Clear scripts, as they are not used at runtime | |
| 127 # (only the fact of their presence is important). | |
| 128 if module.get('scripts'): | |
| 129 module['scripts'] = [] | |
| 130 result.append(module) | |
| 131 return json.dumps(result) | |
| 132 | |
| 133 def _concatenate_autostart_modules(self, output): | |
| 134 non_autostart = set() | |
| 135 sorted_module_names = self.descriptors.sorted_modules() | |
| 136 for name in sorted_module_names: | |
| 137 desc = self.descriptors.modules[name] | |
| 138 name = desc['name'] | |
| 139 type = self.descriptors.application[name].get('type') | |
| 140 if type == 'autostart': | |
| 141 deps = set(desc.get('dependencies', [])) | |
| 142 non_autostart_deps = deps & non_autostart | |
| 143 if len(non_autostart_deps): | |
| 144 bail_error('Non-autostart dependencies specified for the aut ostarted module "%s": %s' % (name, non_autostart_deps)) | |
| 145 output.write('\n/* Module %s */\n' % name) | |
| 146 modular_build.concatenate_scripts(desc.get('scripts'), path.join (self.application_dir, name), self.output_dir, output) | |
| 147 elif type != 'worker': | |
| 148 non_autostart.add(name) | |
| 149 | |
| 150 def _concatenate_application_script(self, output): | |
| 151 application_loader_name = self.application_name + '.js' | |
| 152 runtime_contents = read_file(path.join(self.application_dir, 'Runtime.js ')) | |
| 153 runtime_contents = re.sub('var allDescriptors = \[\];', 'var allDescript ors = %s;' % self._release_module_descriptors().replace("\\", "\\\\"), runtime_c ontents, 1) | |
| 154 output.write('/* Runtime.js */\n') | |
| 155 output.write(runtime_contents) | |
| 156 output.write('\n/* Autostart modules */\n') | |
| 157 self._concatenate_autostart_modules(output) | |
| 158 output.write('/* Application descriptor %s */\n' % (self.application_nam e + '.json')) | |
| 159 output.write('applicationDescriptor = ') | |
| 160 output.write(self.descriptors.application_json) | |
| 161 output.write('\n/* Application loader */\n') | |
| 162 output.write(read_file(path.join(self.application_dir, application_loade r_name))) | |
| 163 | |
| 164 def _concatenate_dynamic_module(self, module_name): | |
| 165 module = self.descriptors.modules[module_name] | |
| 166 scripts = module.get('scripts') | |
| 167 if not scripts: | |
| 168 return | |
| 169 module_dir = path.join(self.application_dir, module_name) | |
| 170 output = StringIO() | |
| 171 modular_build.concatenate_scripts(scripts, module_dir, self.output_dir, output) | |
| 172 output_file_path = concatenated_module_filename(module_name, self.output _dir) | |
| 173 write_file(output_file_path, minify_js(output.getvalue())) | |
| 174 output.close() | |
| 175 | |
| 176 def _concatenate_worker(self, module_name): | |
| 177 descriptor = self.descriptors.modules[module_name] | |
| 178 scripts = descriptor.get('scripts') | |
| 179 if not scripts: | |
| 180 return | |
| 181 | |
| 182 output = StringIO() | |
| 183 output.write('/* Worker %s */\n' % module_name) | |
| 184 dep_descriptors = [] | |
| 185 for dep_name in self.descriptors.sorted_dependencies_closure(module_name ): | |
| 186 dep_descriptor = self.descriptors.modules[dep_name] | |
| 187 dep_descriptors.append(dep_descriptor) | |
| 188 scripts = dep_descriptor.get('scripts') | |
| 189 if scripts: | |
| 190 output.write('\n/* Module %s */\n' % dep_name) | |
| 191 modular_build.concatenate_scripts(scripts, path.join(self.applic ation_dir, dep_name), self.output_dir, output) | |
| 192 | |
| 193 output_file_path = concatenated_module_filename(module_name, self.output _dir) | |
| 194 write_file(output_file_path, minify_js(output.getvalue())) | |
| 195 output.close() | |
| 92 | 196 |
| 93 | 197 |
| 94 def concatenate_worker(module_name, descriptors, application_dir, output_dir, mi nify): | 198 # Outputs: |
| 95 descriptor = descriptors.modules[module_name] | 199 # app_name.html as-is |
|
dgozman
2014/10/13 13:01:52
<app_name>.html ?
apavlov
2014/10/13 15:02:21
Done.
| |
| 96 scripts = descriptor.get('scripts') | 200 # <module_name>/<all_files> |
| 97 if not scripts: | 201 class DebugBuilder(AppBuilder): |
| 98 return | 202 def __init__(self, application_name, descriptors, application_dir, output_di r): |
| 99 worker_dir = path.join(application_dir, module_name) | 203 AppBuilder.__init__(self, application_name, descriptors, application_dir , output_dir) |
| 100 output_file_path = concatenated_module_filename(module_name, output_dir) | |
| 101 | 204 |
| 102 output = StringIO() | 205 def build_app(self): |
| 103 output.write('/* Worker %s */\n' % module_name) | 206 self._build_html() |
| 104 dependencies = descriptors.sorted_dependencies_closure(module_name) | 207 for module_name in self.descriptors.modules: |
| 105 dep_descriptors = [] | 208 module = self.descriptors.modules[module_name] |
| 106 for dep_name in dependencies: | 209 input_module_dir = path.join(self.application_dir, module_name) |
| 107 dep_descriptor = descriptors.modules[dep_name] | 210 output_module_dir = path.join(self.output_dir, module_name) |
| 108 dep_descriptors.append(dep_descriptor) | 211 hardlink_or_copy_dir(input_module_dir, output_module_dir) |
| 109 scripts = dep_descriptor.get('scripts') | |
| 110 if scripts: | |
| 111 output.write('\n/* Module %s */\n' % dep_name) | |
| 112 modular_build.concatenate_scripts(scripts, path.join(application_dir , dep_name), output_dir, output) | |
| 113 | 212 |
| 114 write_file(output_file_path, minify_if_needed(output.getvalue(), minify)) | 213 def _build_html(self): |
| 115 output.close() | 214 html_name = self.application_name + '.html' |
| 215 output = StringIO() | |
| 216 with open(path.join(self.application_dir, html_name), 'r') as app_input_ html: | |
| 217 for line in app_input_html: | |
| 218 output.write(line) | |
| 219 | |
| 220 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
| |
| 221 output.close() | |
| 116 | 222 |
| 117 | 223 |
| 118 def release_module_descriptors(module_descriptors): | 224 def build_application(application_name, loader, application_dir, output_dir, rel ease_mode): |
| 119 result = [] | |
| 120 for name in module_descriptors: | |
| 121 module = copy.copy(module_descriptors[name]) | |
| 122 # Clear scripts, as they are not used at runtime | |
| 123 # (only the fact of their presence is important). | |
| 124 if module.get('scripts'): | |
| 125 module['scripts'] = [] | |
| 126 result.append(module) | |
| 127 return json.dumps(result) | |
| 128 | |
| 129 | |
| 130 def build_application(application_name, loader, application_dir, output_dir, min ify): | |
| 131 descriptors = loader.load_application(application_name + '.json') | 225 descriptors = loader.load_application(application_name + '.json') |
| 132 concatenate_application_script(application_name, descriptors, application_di r, output_dir, minify) | 226 if release_mode: |
| 133 for module in filter(lambda desc: not desc.get('type'), descriptors.applicat ion.values()): | 227 builder = ReleaseBuilder(application_name, descriptors, application_dir, output_dir) |
| 134 concatenate_dynamic_module(module['name'], descriptors, application_dir, output_dir, minify) | 228 else: |
| 135 for module in filter(lambda desc: desc.get('type') == 'worker', descriptors. application.values()): | 229 builder = DebugBuilder(application_name, descriptors, application_dir, o utput_dir) |
| 136 concatenate_worker(module['name'], descriptors, application_dir, output_ dir, minify) | 230 builder.build_app() |
| OLD | NEW |