Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Side by Side Diff: tools/cc-frame-viewer/build/parse_deps.py

Issue 15736032: Remove old cc-frame-viewer now that it is upstreamed into trace_viewer (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/cc-frame-viewer/build/calcdeps.py ('k') | tools/cc-frame-viewer/ccfv » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 import sys
5 import os
6 import re
7
8 class DepsException(Exception):
9 pass
10
11 """
12 The core of this script is the calc_load_sequence function. In total, this
13 walks over the provided javascript files and figures out their dependencies
14 using the module definitions provided in each file. This allows us to, for
15 example, have a trio of modules:
16
17 foo.js:
18 base.require('bar');
19 and bar.js:
20 base.require('baz');
21
22 calc_load_sequence(['foo'], '.') will yield:
23 [Module('baz'), Module('bar'), Module('foo')]
24
25 which is, based on the dependencies, the correct sequence in which to load
26 those modules.
27 """
28
29 class ResourceFinder(object):
30 """Helper code for finding a module given a name and current module.
31
32 The dependency resolution code in Module.resolve will find bits of code in the
33 actual javascript that says things require('bar'). This
34 code is responsible for figuring out what filename corresponds to 'bar' given
35 a Module('foo').
36 """
37 def __init__(self, root_dir):
38 self._root_dir = root_dir
39 pass
40
41 @property
42 def root_dir(self):
43 return self._root_dir
44
45 def _find_and_load_filename(self, absolute_path):
46 if not os.path.exists(absolute_path):
47 return None, None
48
49 f = open(absolute_path, 'r')
50 contents = f.read()
51 f.close()
52
53 return absolute_path, contents
54
55 def _find_and_load(self, current_module, requested_name, extension):
56 assert current_module.filename
57 pathy_name = requested_name.replace(".", os.sep)
58 filename = pathy_name + extension
59 absolute_path = os.path.join(self._root_dir, filename)
60 return self._find_and_load_filename(absolute_path)
61
62 def find_and_load_module(self, current_module, requested_module_name):
63 return self._find_and_load(current_module, requested_module_name, ".js")
64
65 def find_and_load_raw_script(self, current_module, filename):
66 absolute_path = os.path.join(self._root_dir, filename)
67 return self._find_and_load_filename(absolute_path)
68
69 def find_and_load_style_sheet(self,
70 current_module, requested_style_sheet_name):
71 return self._find_and_load(
72 current_module, requested_style_sheet_name, ".css")
73
74
75 class StyleSheet(object):
76 """Represents a stylesheet resource referenced by a module via the
77 base.requireStylesheet(xxx) directive."""
78 def __init__(self, name, filename, contents):
79 self.name = name
80 self.filename = filename
81 self.contents = contents
82
83 def __repr__(self):
84 return "StyleSheet(%s)" % self.name
85
86 class RawScript(object):
87 """Represents a raw script resource referenced by a module via the
88 base.requireRawScript(xxx) directive."""
89 def __init__(self, name, filename, contents):
90 self.name = name
91 self.filename = filename
92 self.contents = contents
93
94 def __repr__(self):
95 return "RawScript(%s)" % self.name
96
97 def _tokenize_js(text):
98 rest = text
99 tokens = ["//", "/*", "*/", "\n"]
100 while len(rest):
101 indices = [rest.find(token) for token in tokens]
102 found_indices = [index for index in indices if index >= 0]
103
104 if len(found_indices) == 0:
105 # end of string
106 yield rest
107 return
108
109 min_index = min(found_indices)
110 token_with_min = tokens[indices.index(min_index)]
111
112 if min_index > 0:
113 yield rest[:min_index]
114
115 yield rest[min_index:min_index + len(token_with_min)]
116 rest = rest[min_index + len(token_with_min):]
117
118 def _strip_js_comments(text):
119 result_tokens = []
120 token_stream = _tokenize_js(text).__iter__()
121 while True:
122 try:
123 t = token_stream.next()
124 except StopIteration:
125 break
126
127 if t == "//":
128 while True:
129 try:
130 t2 = token_stream.next()
131 if t2 == "\n":
132 break
133 except StopIteration:
134 break
135 elif t == '/*':
136 nesting = 1
137 while True:
138 try:
139 t2 = token_stream.next()
140 if t2 == "/*":
141 nesting += 1
142 elif t2 == "*/":
143 nesting -= 1
144 if nesting == 0:
145 break
146 except StopIteration:
147 break
148 else:
149 result_tokens.append(t)
150 return "".join(result_tokens)
151
152 def _MangleRawScriptFilenameToModuleName(filename):
153 name = filename
154 name = name.replace(os.sep, ':')
155 name = name.replace('..', '!!')
156 return name
157
158 class Module(object):
159 """Represents a javascript module. It can either be directly requested, e.g.
160 passed in by name to calc_load_sequence, or created by being referenced a
161 module via the base.require(xxx) directive.
162
163 Interesting properties on this object are:
164
165 - filename: the file of the actual module
166 - contents: the actual text contents of the module
167 - style_sheets: StyleSheet objects that this module relies on for styling
168 information.
169 - dependent_modules: other modules that this module needs in order to run
170 """
171 def __init__(self, name = None):
172 self.name = name
173 self.filename = None
174 self.contents = None
175
176 self.dependent_module_names = []
177 self.dependent_modules = []
178 self.dependent_raw_script_names = []
179 self.dependent_raw_scripts = []
180 self.style_sheet_names = []
181 self.style_sheets = []
182
183 def __repr__(self):
184 return "Module(%s)" % self.name
185
186 def load_and_parse(self, module_filename,
187 module_contents = None,
188 decl_required = True):
189 if not module_contents:
190 f = open(module_filename, 'r')
191 self.contents = f.read()
192 f.close()
193 else:
194 self.contents = module_contents
195 self.filename = module_filename
196 self.parse_definition_(self.contents, decl_required)
197
198 def resolve(self, all_resources, resource_finder):
199 if "scripts" not in all_resources:
200 all_resources["scripts"] = {}
201 if "style_sheets" not in all_resources:
202 all_resources["style_sheets"] = {}
203 if "raw_scripts" not in all_resources:
204 all_resources["raw_scripts"] = {}
205
206 assert self.filename
207
208 for name in self.dependent_module_names:
209 if name in all_resources["scripts"]:
210 assert all_resources["scripts"][name].contents
211 self.dependent_modules.append(all_resources["scripts"][name])
212 continue
213
214 filename, contents = resource_finder.find_and_load_module(self, name)
215 if not filename:
216 raise DepsException("Could not find a file for module %s" % name)
217
218 module = Module(name)
219 all_resources["scripts"][name] = module
220 self.dependent_modules.append(module)
221 module.load_and_parse(filename, contents)
222 module.resolve(all_resources, resource_finder)
223
224 for name in self.dependent_raw_script_names:
225 filename, contents = resource_finder.find_and_load_raw_script(self, name)
226 if not filename:
227 raise DepsException("Could not find a file for module %s" % name)
228
229 if name in all_resources["raw_scripts"]:
230 assert all_resources["raw_scripts"][name].contents
231 self.dependent_raw_scripts.append(all_resources["raw_scripts"][name])
232 continue
233
234 raw_script = RawScript(name, filename, contents)
235 all_resources["raw_scripts"][name] = raw_script
236 self.dependent_raw_scripts.append(raw_script)
237
238 for name in self.style_sheet_names:
239 if name in all_resources["style_sheets"]:
240 assert all_resources["style_sheets"][name].contents
241 self.style_sheets.append(all_resources["scripts"][name])
242 continue
243
244 filename, contents = resource_finder.find_and_load_style_sheet(self, name)
245 if not filename:
246 raise DepsException("Could not find a file for stylesheet %s" % name)
247
248 style_sheet = StyleSheet(name, filename, contents)
249 all_resources["style_sheets"][name] = style_sheet
250 self.style_sheets.append(style_sheet)
251
252 def compute_load_sequence_recursive(self, load_sequence, already_loaded_set):
253 for dependent_module in self.dependent_modules:
254 dependent_module.compute_load_sequence_recursive(load_sequence,
255 already_loaded_set)
256 if self.name not in already_loaded_set:
257 already_loaded_set.add(self.name)
258 load_sequence.append(self)
259
260 def parse_definition_(self, text, decl_required = True):
261 if not decl_required and not self.name:
262 raise Exception("Module.name must be set for decl_required to be false.")
263
264 stripped_text = _strip_js_comments(text)
265 rest = stripped_text
266 while True:
267 # Things to search for.
268 m_r = re.search("""base\s*\.\s*require\((["'])(.+?)\\1\)""",
269 rest, re.DOTALL)
270 m_s = re.search("""base\s*\.\s*requireStylesheet\((["'])(.+?)\\1\)""",
271 rest, re.DOTALL)
272 m_irs = re.search("""base\s*\.\s*requireRawScript\((["'])(.+?)\\1\)""",
273 rest, re.DOTALL)
274 matches = [m for m in [m_r, m_s, m_irs] if m]
275
276 # Figure out which was first.
277 matches.sort(key=lambda x: x.start())
278 if len(matches):
279 m = matches[0]
280 else:
281 break
282
283 if m == m_r:
284 dependent_module_name = m.group(2)
285 if '/' in dependent_module_name:
286 raise DepsException("Slashes are not allowed in module names. "
287 "Use '.' instead: %s" % dependent_module_name)
288 if dependent_module_name.endswith('js'):
289 raise DepsException("module names shouldn't end with .js"
290 "The module system will append that for you: %s" %
291 dependent_module_name)
292 self.dependent_module_names.append(dependent_module_name)
293 elif m == m_s:
294 style_sheet_name = m.group(2)
295 if '/' in style_sheet_name:
296 raise DepsException("Slashes are not allowed in style sheet names. "
297 "Use '.' instead: %s" % style_sheet_name)
298 if style_sheet_name.endswith('.css'):
299 raise DepsException("Style sheets should not end in .css. "
300 "The module system will append that for you" %
301 style_sheet_name)
302 self.style_sheet_names.append(style_sheet_name)
303 elif m == m_irs:
304 name = m.group(2)
305 self.dependent_raw_script_names.append(name)
306
307 rest = rest[m.end():]
308
309
310 def calc_load_sequence(filenames, toplevel_dir):
311 """Given a list of starting javascript files, figure out all the Module
312 objects that need to be loaded to satisfiy their dependencies.
313
314 The javascript files shoud specify their dependencies in a format that is
315 textually equivalent to base.js' require syntax, namely:
316
317 base.require(module1);
318 base.require(module2);
319 base.requireStylesheet(stylesheet);
320
321 The output of this function is an array of Module objects ordered by
322 dependency.
323 """
324 all_resources = {}
325 all_resources["scripts"] = {}
326 toplevel_modules = []
327 root_dir = ''
328 if filenames:
329 root_dir = os.path.abspath(os.path.dirname(filenames[0]))
330 resource_finder = ResourceFinder(root_dir)
331 for filename in filenames:
332 if not os.path.exists(filename):
333 raise Exception("Could not find %s" % filename)
334
335 rel_filename = os.path.relpath(filename, toplevel_dir)
336 dirname = os.path.dirname(rel_filename)
337 modname = os.path.splitext(os.path.basename(rel_filename))[0]
338 if len(dirname):
339 name = dirname.replace('/', '.') + '.' + modname
340 else:
341 name = modname
342
343 if name in all_resources["scripts"]:
344 continue
345
346 module = Module(name)
347 module.load_and_parse(filename, decl_required = False)
348 all_resources["scripts"][module.name] = module
349 module.resolve(all_resources, resource_finder)
350
351 # Find the root modules: ones who have no dependencies.
352 module_ref_counts = {}
353 for module in all_resources["scripts"].values():
354 module_ref_counts[module.name] = 0
355
356 def inc_ref_count(name):
357 module_ref_counts[name] = module_ref_counts[name] + 1
358 for module in all_resources["scripts"].values():
359 for dependent_module in module.dependent_modules:
360 inc_ref_count(dependent_module.name)
361
362 root_modules = [all_resources["scripts"][name]
363 for name, ref_count in module_ref_counts.items()
364 if ref_count == 0]
365
366 root_modules.sort(lambda x, y: cmp(x.name, y.name))
367
368 already_loaded_set = set()
369 load_sequence = []
370 for module in root_modules:
371 module.compute_load_sequence_recursive(load_sequence, already_loaded_set)
372 return load_sequence
OLDNEW
« no previous file with comments | « tools/cc-frame-viewer/build/calcdeps.py ('k') | tools/cc-frame-viewer/ccfv » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698