def filename_to_uri(self, filename): """ Given a filename, return a URI which can be used to access this template from the lookup. """ from_dir = self.find_dir_for_path(filename) base_uri = TemplateLookup.filename_to_uri(self, filename) ret = base_uri + self.super_delimiter + from_dir return ret
class Renderer(object): '''Manages rendering templates''' def __init__(self, template_dir, invoking_filenames, source_files): self.template_dir = template_dir self.invoking_filenames = invoking_filenames self.source_files = source_files self.tl = TemplateLookup(directories=[template_dir]) self.template_context = { 'camel': camel, # CamelCase function 'dromedary': dromedary, # dromeDary case function 'EmptyTemplate': EmptyTemplate, } self.mtime_cache = {} self.dependency_cache = {} def mtime(self, filename): try: return self.mtime_cache[filename] except KeyError: mtime = os.path.getmtime(filename) self.mtime_cache[filename] = mtime return mtime def render(self, template_name, output_dir, output_name=None, dependencies=None, **kwargs): if output_name is None: output_name = template_name tpl = self.tl.get_template(template_name) output_path = output_dir + '/' + output_name if self.already_rendered(tpl, output_path, dependencies): logger.debug(" Up to date: %s", output_path) return results = self.template_context.copy() results.update(kwargs) try: rendered = tpl.render(**results) except EmptyTemplate: logger.debug(" Empty template: %s", output_path) return with codecs.open(output_path, "w", "utf-8") as outfile: logger.info("Rendering %s", output_path) outfile.write( self.autogenerated_header( self.template_dir + '/' + template_name, output_path, self.invoking_filenames, )) outfile.write(rendered) def get_template_name(self, classname, directory, default): '''Returns the template for this class''' override_template = '{}/{}.java'.format(directory, classname) if self.tl.has_template(override_template): logger.debug("Found an override for %s at %s", classname, override_template) return override_template else: return default def dependent_templates(self, tpl): '''Returns filenames for all templates that are inherited from the given template''' if tpl.filename in self.dependency_cache: return self.dependency_cache[tpl.filename] inherit_files = re.findall(r'inherit file="(.*)"', tpl.source) op = os.path dependencies = set() tpl_dir = op.dirname(tpl.filename) for parent_relpath in inherit_files: parent_filename = op.normpath(op.join(tpl_dir, parent_relpath)) dependencies.add(parent_filename) dependencies.update( self.dependent_templates( self.tl.get_template( self.tl.filename_to_uri(parent_filename)))) dependencies.add(tpl.filename) self.dependency_cache[tpl.filename] = dependencies return dependencies def already_rendered(self, tpl, output_path, dependencies): '''Check if rendered file is already up to date''' if not os.path.exists(output_path): logger.debug(" Rendering since %s doesn't exist", output_path) return False output_mtime = self.mtime(output_path) # Check if this file or the invoking file have changed for filename in self.invoking_filenames + self.source_files: if self.mtime(filename) > output_mtime: logger.debug(" Rendering since %s has changed", filename) return False if self.mtime(__file__) > output_mtime: logger.debug(" Rendering since %s has changed", __file__) return False # Check if any dependent templates have changed for tpl in self.dependent_templates(tpl): if self.mtime(tpl) > output_mtime: logger.debug(" Rendering since %s is newer", tpl) return False # Check if any explicitly defined dependencies have changed dependencies = dependencies or [] for dep in dependencies: if self.mtime(dep) > output_mtime: logger.debug(" Rendering since %s is newer", dep) return False return True def autogenerated_header(self, template_path, output_path, filename): rel_tpl = os.path.relpath(template_path, start=output_path) filenames = ' and '.join( os.path.basename(f) for f in self.invoking_filenames) return ('// Autogenerated by {}.\n' '// Do not edit this file directly.\n' '// The template for this file is located at:\n' '// {}\n').format(filenames, rel_tpl)