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.
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.
10 Other resources include HTML templates, raw javascript files, and stylesheets.
17 from tvcm import resource as resource_module
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
24 frame = inspect.currentframe()
26 locals = frame.f_locals
31 if isinstance(s, Module):
33 if isinstance(s, style_sheet_module.StyleSheet):
34 module_name = s.name + '.css'
36 if 'module' in locals:
37 module = locals['module']
38 if isinstance(s, Module):
39 module_name = module.name
42 if isinstance(s, Module):
43 module_name = module.name
47 if context[-1] != module_name:
48 context.append(module_name)
50 context.append(module_name)
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)))
60 class ModuleDependencyMetadata(object):
62 self.dependent_module_names = []
63 self.dependent_raw_script_relative_paths = []
64 self.style_sheet_names = []
65 self.html_template_names = []
68 """Represents a javascript module.
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.
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.
80 In addition to these properties, a Module also contains lists of other
81 resources that it depends on.
83 def __init__(self, loader, name, resource):
84 assert isinstance(name, basestring), 'Got %s instead' % repr(name)
85 assert isinstance(resource, resource_module.Resource)
88 self.resource = resource
90 f = open(self.filename, 'r')
91 self.contents = f.read()
94 # Dependency metadata, set up during Parse().
95 self.dependency_metadata = None
97 # Actual dependencies, set up during load().
98 self.dependent_modules = []
99 self.dependent_raw_scripts = []
100 self.style_sheets = []
101 self.html_templates = []
104 return '%s(%s)' % (self.__class__.__name__, self.name)
108 return self.resource.absolute_path
111 def html_contents_is_polymer_module(contents):
112 return '<polymer-component>' in contents
115 """Parses self.contents and fills in the module's dependency metadata."""
116 raise NotImplementedError()
119 """Loads the sub-resources that this module depends on from its dependency metadata.
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.
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.'
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)
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)
138 for name in metadata.style_sheet_names:
139 style_sheet = self.loader.load_style_sheet(name)
140 self.style_sheets.append(style_sheet)
142 for name in metadata.html_template_names:
143 html_template = self.loader.load_html_template(name)
144 self.html_templates.append(html_template)
146 def compute_load_sequence_recursive(self, load_sequence, already_loaded_set,
148 """Recursively builds up a load sequence list.
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
154 depth: The depth of recursion. If it too deep, that indicates a loop.
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)
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):
171 self.filename = filename
172 self.contents = contents
175 return "HTMLTemplate(%s)" % self.name
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
186 return self.resource.absolute_path
190 return self.resource.contents
193 return "RawScript(%s)" % self.filename