Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / scripts / concatenate_application_code.py
blob47bacfd16452595081a940ab6b4bb5110c1bcc58
1 #!/usr/bin/env python
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
5 # found in the LICENSE file.
7 """
8 Release:
9 - Concatenates autostart modules, application modules' module.json descriptors,
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.
16 """
18 from cStringIO import StringIO
19 from os import path
20 from os.path import join
21 from modular_build import read_file, write_file, bail_error
22 import copy
23 import modular_build
24 import os
25 import re
26 import shutil
27 import sys
29 try:
30 import simplejson as json
31 except ImportError:
32 import json
34 rjsmin_path = path.abspath(join(
35 path.dirname(__file__),
36 '..',
37 '..',
38 'build',
39 'scripts'))
40 sys.path.append(rjsmin_path)
41 import rjsmin
44 def resource_source_url(url):
45 return '\n/*# sourceURL=' + url + ' */'
48 def minify_js(javascript):
49 return rjsmin.jsmin(javascript)
52 def concatenated_module_filename(module_name, output_dir):
53 return join(output_dir, module_name + '_module.js')
56 def symlink_or_copy_file(src, dest, safe=False):
57 if safe and path.exists(dest):
58 os.remove(dest)
59 if hasattr(os, 'symlink'):
60 os.symlink(src, dest)
61 else:
62 shutil.copy(src, dest)
65 def symlink_or_copy_dir(src, dest):
66 if path.exists(dest):
67 shutil.rmtree(dest)
68 for src_dir, dirs, files in os.walk(src):
69 subpath = path.relpath(src_dir, src)
70 dest_dir = path.normpath(join(dest, subpath))
71 os.mkdir(dest_dir)
72 for name in files:
73 src_name = join(os.getcwd(), src_dir, name)
74 dest_name = join(dest_dir, name)
75 symlink_or_copy_file(src_name, dest_name)
78 class AppBuilder:
79 def __init__(self, application_name, descriptors, application_dir, output_dir):
80 self.application_name = application_name
81 self.descriptors = descriptors
82 self.application_dir = application_dir
83 self.output_dir = output_dir
85 def app_file(self, extension):
86 return self.application_name + '.' + extension
88 def core_resource_names(self):
89 result = []
90 for module in self.descriptors.sorted_modules():
91 if self.descriptors.application[module].get('type') != 'autostart':
92 continue
94 resources = self.descriptors.modules[module].get('resources')
95 if not resources:
96 continue
97 for resource_name in resources:
98 result.append(path.join(module, resource_name))
99 return result
102 # Outputs:
103 # <app_name>.html
104 # <app_name>.js
105 # <module_name>_module.js
106 class ReleaseBuilder(AppBuilder):
107 def __init__(self, application_name, descriptors, application_dir, output_dir):
108 AppBuilder.__init__(self, application_name, descriptors, application_dir, output_dir)
110 def build_app(self):
111 self._build_html()
112 self._build_app_script()
113 for module in filter(lambda desc: (not desc.get('type') or desc.get('type') == 'remote'), self.descriptors.application.values()):
114 self._concatenate_dynamic_module(module['name'])
115 for module in filter(lambda desc: desc.get('type') == 'worker', self.descriptors.application.values()):
116 self._concatenate_worker(module['name'])
118 def _build_html(self):
119 html_name = self.app_file('html')
120 output = StringIO()
121 with open(join(self.application_dir, html_name), 'r') as app_input_html:
122 for line in app_input_html:
123 if '<script ' in line or '<link ' in line:
124 continue
125 if '</head>' in line:
126 output.write(self._generate_include_tag(self.app_file('css')))
127 output.write(self._generate_include_tag(self.app_file('js')))
128 output.write(line)
130 write_file(join(self.output_dir, html_name), output.getvalue())
131 output.close()
133 def _build_app_script(self):
134 script_name = self.app_file('js')
135 output = StringIO()
136 self._concatenate_application_script(output)
137 write_file(join(self.output_dir, script_name), minify_js(output.getvalue()))
138 output.close()
140 def _generate_include_tag(self, resource_path):
141 if (resource_path.endswith('.js')):
142 return ' <script type="text/javascript" src="%s"></script>\n' % resource_path
143 elif (resource_path.endswith('.css')):
144 return ' <link rel="stylesheet" type="text/css" href="%s">\n' % resource_path
145 else:
146 assert resource_path
148 def _release_module_descriptors(self):
149 module_descriptors = self.descriptors.modules
150 result = []
151 for name in module_descriptors:
152 module = copy.copy(module_descriptors[name])
153 # Clear scripts, as they are not used at runtime
154 # (only the fact of their presence is important).
155 resources = module.get('resources', None)
156 if module.get('scripts') or resources:
157 module['scripts'] = []
158 # Resources list is not used at runtime.
159 if resources is not None:
160 del module['resources']
161 condition = self.descriptors.application[name].get('condition')
162 if condition:
163 module['condition'] = condition
164 type = self.descriptors.application[name].get('type')
165 if type == 'remote':
166 module['remote'] = True
167 result.append(module)
168 return json.dumps(result)
170 def _write_module_resources(self, resource_names, output):
171 for resource_name in resource_names:
172 resource_name = path.normpath(resource_name).replace('\\', '/')
173 output.write('Runtime.cachedResources["%s"] = "' % resource_name)
174 resource_content = read_file(path.join(self.application_dir, resource_name)) + resource_source_url(resource_name)
175 resource_content = resource_content.replace('\\', '\\\\')
176 resource_content = resource_content.replace('\n', '\\n')
177 resource_content = resource_content.replace('"', '\\"')
178 output.write(resource_content)
179 output.write('";\n')
181 def _concatenate_autostart_modules(self, output):
182 non_autostart = set()
183 sorted_module_names = self.descriptors.sorted_modules()
184 for name in sorted_module_names:
185 desc = self.descriptors.modules[name]
186 name = desc['name']
187 type = self.descriptors.application[name].get('type')
188 if type == 'autostart':
189 deps = set(desc.get('dependencies', []))
190 non_autostart_deps = deps & non_autostart
191 if len(non_autostart_deps):
192 bail_error('Non-autostart dependencies specified for the autostarted module "%s": %s' % (name, non_autostart_deps))
193 output.write('\n/* Module %s */\n' % name)
194 modular_build.concatenate_scripts(desc.get('scripts'), join(self.application_dir, name), self.output_dir, output)
195 elif type != 'worker':
196 non_autostart.add(name)
198 def _concatenate_application_script(self, output):
199 runtime_contents = read_file(join(self.application_dir, 'Runtime.js'))
200 runtime_contents = re.sub('var allDescriptors = \[\];', 'var allDescriptors = %s;' % self._release_module_descriptors().replace('\\', '\\\\'), runtime_contents, 1)
201 output.write('/* Runtime.js */\n')
202 output.write(runtime_contents)
203 output.write('\n/* Autostart modules */\n')
204 self._concatenate_autostart_modules(output)
205 output.write('/* Application descriptor %s */\n' % self.app_file('json'))
206 output.write('applicationDescriptor = ')
207 output.write(self.descriptors.application_json())
208 output.write(';\n/* Core resources */\n')
209 self._write_module_resources(self.core_resource_names(), output)
210 output.write('\n/* Application loader */\n')
211 output.write(read_file(join(self.application_dir, self.app_file('js'))))
213 def _concatenate_dynamic_module(self, module_name):
214 module = self.descriptors.modules[module_name]
215 scripts = module.get('scripts')
216 resources = self.descriptors.module_resources(module_name)
217 module_dir = join(self.application_dir, module_name)
218 output = StringIO()
219 if scripts:
220 modular_build.concatenate_scripts(scripts, module_dir, self.output_dir, output)
221 if resources:
222 self._write_module_resources(resources, output)
223 output_file_path = concatenated_module_filename(module_name, self.output_dir)
224 write_file(output_file_path, minify_js(output.getvalue()))
225 output.close()
227 def _concatenate_worker(self, module_name):
228 descriptor = self.descriptors.modules[module_name]
229 scripts = descriptor.get('scripts')
230 if not scripts:
231 return
233 output = StringIO()
234 output.write('/* Worker %s */\n' % module_name)
235 dep_descriptors = []
236 for dep_name in self.descriptors.sorted_dependencies_closure(module_name):
237 dep_descriptor = self.descriptors.modules[dep_name]
238 dep_descriptors.append(dep_descriptor)
239 scripts = dep_descriptor.get('scripts')
240 if scripts:
241 output.write('\n/* Module %s */\n' % dep_name)
242 modular_build.concatenate_scripts(scripts, join(self.application_dir, dep_name), self.output_dir, output)
244 output_file_path = concatenated_module_filename(module_name, self.output_dir)
245 write_file(output_file_path, minify_js(output.getvalue()))
246 output.close()
249 # Outputs:
250 # <app_name>.html as-is
251 # <app_name>.js as-is
252 # <module_name>/<all_files>
253 class DebugBuilder(AppBuilder):
254 def __init__(self, application_name, descriptors, application_dir, output_dir):
255 AppBuilder.__init__(self, application_name, descriptors, application_dir, output_dir)
257 def build_app(self):
258 self._build_html()
259 js_name = self.app_file('js')
260 src_name = join(os.getcwd(), self.application_dir, js_name)
261 symlink_or_copy_file(src_name, join(self.output_dir, js_name), True)
262 for module_name in self.descriptors.modules:
263 module = self.descriptors.modules[module_name]
264 input_module_dir = join(self.application_dir, module_name)
265 output_module_dir = join(self.output_dir, module_name)
266 symlink_or_copy_dir(input_module_dir, output_module_dir)
268 def _build_html(self):
269 html_name = self.app_file('html')
270 symlink_or_copy_file(join(os.getcwd(), self.application_dir, html_name), join(self.output_dir, html_name), True)
273 def build_application(application_name, loader, application_dir, output_dir, release_mode):
274 descriptors = loader.load_application(application_name + '.json')
275 if release_mode:
276 builder = ReleaseBuilder(application_name, descriptors, application_dir, output_dir)
277 else:
278 builder = DebugBuilder(application_name, descriptors, application_dir, output_dir)
279 builder.build_app()