Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / third_party / tvcm / tvcm / module.py
1 # Copyright 2013 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 """This module contains the Module class and other classes for resources.
5
6 The Module class represents a module in the trace viewer system. A module has
7 a name, and may require a variety of other resources, such as stylesheets,
8 template objects, raw javascript, or other modules.
9
10 Other resources include HTML templates, raw javascript files, and stylesheets.
11 """
12
13 import os
14 import re
15 import inspect
16
17 from tvcm import resource as resource_module
18
19 class DepsException(Exception):
20   """Exceptions related to module dependency resolution."""
21   def __init__(self, fmt, *args):
22     import style_sheet as style_sheet_module
23     context = []
24     frame = inspect.currentframe()
25     while frame:
26       locals = frame.f_locals
27
28       module_name = None
29       if 'self' in locals:
30         s = locals['self']
31         if isinstance(s, Module):
32           module_name = s.name
33         if isinstance(s, style_sheet_module.StyleSheet):
34           module_name = s.name + '.css'
35       if not module_name:
36         if 'module' in locals:
37           module = locals['module']
38           if isinstance(s, Module):
39             module_name = module.name
40         elif 'm' in locals:
41           module = locals['m']
42           if isinstance(s, Module):
43             module_name = module.name
44
45       if module_name:
46         if len(context):
47           if context[-1] != module_name:
48             context.append(module_name)
49         else:
50           context.append(module_name)
51
52       frame = frame.f_back
53
54     context.reverse()
55     self.context = context
56     context_str = '\n'.join(['  %s' % x for x in context])
57     Exception.__init__(self, 'While loading:\n%s\nGot: %s' % (context_str, (fmt % args)))
58
59
60 class ModuleDependencyMetadata(object):
61   def __init__(self):
62     self.dependent_module_names = []
63     self.dependent_raw_script_relative_paths = []
64     self.style_sheet_names = []
65     self.html_template_names = []
66
67 class Module(object):
68   """Represents a javascript module.
69
70   It can either be directly requested, e.g. passed in by name to
71   calc_load_sequence, or created by being referenced a module via the
72   tvcm.require directive.
73
74   Interesting properties include:
75     name: Module name, may include a namespace, e.g. 'tvcm.foo'.
76     filename: The filename of the actual module.
77     contents: The text contents of the module
78     dependent_modules: Other modules that this module depends on.
79
80   In addition to these properties, a Module also contains lists of other
81   resources that it depends on.
82   """
83   def __init__(self, loader, name, resource):
84     assert isinstance(name, basestring), 'Got %s instead' % repr(name)
85     assert isinstance(resource, resource_module.Resource)
86     self.loader = loader
87     self.name = name
88     self.resource = resource
89
90     f = open(self.filename, 'r')
91     self.contents = f.read()
92     f.close()
93
94     # Dependency metadata, set up during Parse().
95     self.dependency_metadata = None
96
97     # Actual dependencies, set up during load().
98     self.dependent_modules = []
99     self.dependent_raw_scripts = []
100     self.style_sheets = []
101     self.html_templates = []
102
103   def __repr__(self):
104     return '%s(%s)' % (self.__class__.__name__, self.name)
105
106   @property
107   def filename(self):
108     return self.resource.absolute_path
109
110   @staticmethod
111   def html_contents_is_polymer_module(contents):
112     return '<polymer-component>' in contents
113
114   def Parse(self):
115     """Parses self.contents and fills in the module's dependency metadata."""
116     raise NotImplementedError()
117
118   def load(self):
119     """Loads the sub-resources that this module depends on from its dependency metadata.
120
121     Raises:
122       DepsException: There was a problem finding one of the dependencies.
123       Exception: There was a problem parsing a module that this one depends on.
124     """
125     assert self.name, 'Module name must be set before dep resolution.'
126     assert self.filename, 'Module filename must be set before dep resolution.'
127     assert self.name in self.loader.loaded_modules, 'Module must be registered in resource loader before loading.'
128
129     metadata = self.dependency_metadata
130     for name in metadata.dependent_module_names:
131       module = self.loader.load_module(module_name=name)
132       self.dependent_modules.append(module)
133
134     for relative_raw_script_path in metadata.dependent_raw_script_relative_paths:
135       raw_script = self.loader.load_raw_script(relative_raw_script_path)
136       self.dependent_raw_scripts.append(raw_script)
137
138     for name in metadata.style_sheet_names:
139       style_sheet = self.loader.load_style_sheet(name)
140       self.style_sheets.append(style_sheet)
141
142     for name in metadata.html_template_names:
143       html_template = self.loader.load_html_template(name)
144       self.html_templates.append(html_template)
145
146   def compute_load_sequence_recursive(self, load_sequence, already_loaded_set,
147                                       depth=0):
148     """Recursively builds up a load sequence list.
149
150     Args:
151       load_sequence: A list which will be incrementally built up.
152       already_loaded_set: A set of modules that has already been added to the
153           load sequence list.
154       depth: The depth of recursion. If it too deep, that indicates a loop.
155     """
156     if depth > 32:
157       raise Exception('Include loop detected on %s', self.name)
158     for dependent_module in self.dependent_modules:
159       dependent_module.compute_load_sequence_recursive(
160           load_sequence, already_loaded_set, depth+1)
161     if self.name not in already_loaded_set:
162       already_loaded_set.add(self.name)
163       load_sequence.append(self)
164
165
166 class HTMLTemplate(object):
167   """Represents an html template resource referenced by a module via the
168   tvcm.requireTemplate(xxx) directive."""
169   def __init__(self, name, filename, contents):
170     self.name = name
171     self.filename = filename
172     self.contents = contents
173
174   def __repr__(self):
175     return "HTMLTemplate(%s)" % self.name
176
177
178 class RawScript(object):
179   """Represents a raw script resource referenced by a module via the
180   tvcm.requireRawScript(xxx) directive."""
181   def __init__(self, resource):
182     self.resource = resource
183
184   @property
185   def filename(self):
186     return self.resource.absolute_path
187
188   @property
189   def contents(self):
190     return self.resource.contents
191
192   def __repr__(self):
193     return "RawScript(%s)" % self.filename