| @@ -84,19 +84,34 @@ class MetaPlugin(Plugin): | |||||
| match = re.match(yaml_finder, text) | match = re.match(yaml_finder, text) | ||||
| if not match: | if not match: | ||||
| logger.info("No metadata found in resource [%s]" % resource) | logger.info("No metadata found in resource [%s]" % resource) | ||||
| return text | |||||
| text = text[match.end():] | |||||
| data = match.group(1) | |||||
| data = {} | |||||
| else: | |||||
| text = text[match.end():] | |||||
| data = match.group(1) | |||||
| if not hasattr(resource, 'meta') or not resource.meta: | if not hasattr(resource, 'meta') or not resource.meta: | ||||
| if not hasattr(resource.node, 'meta'): | if not hasattr(resource.node, 'meta'): | ||||
| resource.node.meta = Metadata({}) | resource.node.meta = Metadata({}) | ||||
| resource.meta = Metadata(data, resource.node.meta) | resource.meta = Metadata(data, resource.node.meta) | ||||
| else: | else: | ||||
| resource.meta.update(data) | resource.meta.update(data) | ||||
| self.__update_standard_attributes__(resource) | |||||
| logger.info("Successfully loaded metadata from resource [%s]" | logger.info("Successfully loaded metadata from resource [%s]" | ||||
| % resource) | % resource) | ||||
| return text | return text | ||||
| def __update_standard_attributes__(self, obj): | |||||
| """ | |||||
| Updates standard attributes on the resource and | |||||
| page based on the provided meta data. | |||||
| """ | |||||
| if not hasattr(obj, 'meta'): | |||||
| return | |||||
| standard_attributes = ['is_processable', 'uses_template'] | |||||
| for attr in standard_attributes: | |||||
| if hasattr(obj.meta, attr): | |||||
| setattr(obj, attr, getattr(obj.meta, attr)) | |||||
| def __read_node__(self, node): | def __read_node__(self, node): | ||||
| """ | """ | ||||
| Look for nodemeta.yaml. Load and assign it to the node. | Look for nodemeta.yaml. Load and assign it to the node. | ||||
| @@ -112,6 +127,7 @@ class MetaPlugin(Plugin): | |||||
| node.meta = Metadata(metadata, parent=parent_meta) | node.meta = Metadata(metadata, parent=parent_meta) | ||||
| else: | else: | ||||
| node.meta = Metadata({}, parent=parent_meta) | node.meta = Metadata({}, parent=parent_meta) | ||||
| self.__update_standard_attributes__(node) | |||||
| def begin_node(self, node): | def begin_node(self, node): | ||||
| """ | """ | ||||
| @@ -4,7 +4,8 @@ Jinja template utilties | |||||
| from hyde.fs import File, Folder | from hyde.fs import File, Folder | ||||
| from hyde.template import Template | from hyde.template import Template | ||||
| from jinja2 import contextfunction, Environment, FileSystemLoader, Undefined, nodes | |||||
| from jinja2 import contextfunction, Environment, FileSystemLoader | |||||
| from jinja2 import environmentfilter, Markup, Undefined, nodes | |||||
| from jinja2.ext import Extension | from jinja2.ext import Extension | ||||
| from jinja2.exceptions import TemplateError | from jinja2.exceptions import TemplateError | ||||
| @@ -30,6 +31,20 @@ def content_url(context, path): | |||||
| site = context['site'] | site = context['site'] | ||||
| return Folder(site.config.base_url).child(path) | return Folder(site.config.base_url).child(path) | ||||
| @environmentfilter | |||||
| def markdown(env, value): | |||||
| try: | |||||
| import markdown | |||||
| except ImportError: | |||||
| raise TemplateError("Cannot load the markdown library") | |||||
| output = value | |||||
| d = {} | |||||
| if hasattr(env.config, 'markdown'): | |||||
| d['extensions'] = getattr(env.config.markdown, 'extensions', []) | |||||
| d['extension_configs'] = getattr(env.config.markdown, 'extension_configs', {}) | |||||
| md = markdown.Markdown(**d) | |||||
| return md.convert(output) | |||||
| class Markdown(Extension): | class Markdown(Extension): | ||||
| tags = set(['markdown']) | tags = set(['markdown']) | ||||
| @@ -43,19 +58,10 @@ class Markdown(Extension): | |||||
| ).set_lineno(lineno) | ).set_lineno(lineno) | ||||
| def _render_markdown(self, caller=None): | def _render_markdown(self, caller=None): | ||||
| try: | |||||
| import markdown | |||||
| except ImportError: | |||||
| raise TemplateError("Cannot load the markdown library") | |||||
| if not caller: | if not caller: | ||||
| return '' | return '' | ||||
| output = caller().strip() | output = caller().strip() | ||||
| d = {} | |||||
| if hasattr(self.environment.config, 'markdown'): | |||||
| d['extensions'] = getattr(self.environment.config.markdown, 'extensions', []) | |||||
| d['extension_configs'] = getattr(self.environment.config.markdown, 'extension_configs', {}) | |||||
| md = markdown.Markdown(**d) | |||||
| return md.convert(output) | |||||
| return markdown(self.environment, output) | |||||
| # pylint: disable-msg=W0104,E0602,W0613,R0201 | # pylint: disable-msg=W0104,E0602,W0613,R0201 | ||||
| class Jinja2Template(Template): | class Jinja2Template(Template): | ||||
| @@ -80,13 +86,14 @@ class Jinja2Template(Template): | |||||
| self.env = Environment(loader=loader, | self.env = Environment(loader=loader, | ||||
| undefined=SilentUndefined, | undefined=SilentUndefined, | ||||
| trim_blocks=True, | trim_blocks=True, | ||||
| extensions=[Markdown, | |||||
| 'jinja2.ext.do', | |||||
| extensions=[Markdown, | |||||
| 'jinja2.ext.do', | |||||
| 'jinja2.ext.loopcontrols', | 'jinja2.ext.loopcontrols', | ||||
| 'jinja2.ext.with_']) | 'jinja2.ext.with_']) | ||||
| self.env.globals['media_url'] = media_url | self.env.globals['media_url'] = media_url | ||||
| self.env.globals['content_url'] = content_url | self.env.globals['content_url'] = content_url | ||||
| self.env.extend(config=config) | self.env.extend(config=config) | ||||
| self.env.filters['markdown'] = markdown | |||||
| try: | try: | ||||
| from typogrify.templatetags import jinja2_filters | from typogrify.templatetags import jinja2_filters | ||||
| @@ -212,8 +212,9 @@ class Generator(object): | |||||
| if resource.source_file.is_text: | if resource.source_file.is_text: | ||||
| text = resource.source_file.read_all() | text = resource.source_file.read_all() | ||||
| text = self.events.begin_text_resource(resource, text) or text | text = self.events.begin_text_resource(resource, text) or text | ||||
| logger.info("Rendering [%s]", resource) | |||||
| text = self.template.render(text, context) | |||||
| if resource.uses_template: | |||||
| logger.info("Rendering [%s]", resource) | |||||
| text = self.template.render(text, context) | |||||
| text = self.events.text_resource_complete( | text = self.events.text_resource_complete( | ||||
| resource, text) or text | resource, text) or text | ||||
| target = File(self.site.config.deploy_root_path.child( | target = File(self.site.config.deploy_root_path.child( | ||||
| @@ -120,10 +120,7 @@ class HydeWebServer(HTTPServer): | |||||
| self.exception_count += 1 | self.exception_count += 1 | ||||
| logger.error('Error occured when regenerating the site [%s]' | logger.error('Error occured when regenerating the site [%s]' | ||||
| % exception.message) | % exception.message) | ||||
| if self.exception_count > 1: | |||||
| self.shutdown() | |||||
| exit() | |||||
| else: | |||||
| if self.exception_count <= 1: | |||||
| self.__reinit__() | self.__reinit__() | ||||
| @@ -22,6 +22,7 @@ class Processable(object): | |||||
| super(Processable, self).__init__() | super(Processable, self).__init__() | ||||
| self.source = FS.file_or_folder(source) | self.source = FS.file_or_folder(source) | ||||
| self.is_processable = True | self.is_processable = True | ||||
| self.uses_template = True | |||||
| @property | @property | ||||
| def name(self): | def name(self): | ||||
| @@ -26,6 +26,26 @@ class TestMeta(object): | |||||
| def tearDown(self): | def tearDown(self): | ||||
| TEST_SITE.delete() | TEST_SITE.delete() | ||||
| def test_can_set_standard_attributes(self): | |||||
| text = """ | |||||
| --- | |||||
| is_processable: False | |||||
| --- | |||||
| {% extends "base.html" %} | |||||
| """ | |||||
| about2 = File(TEST_SITE.child('content/about2.html')) | |||||
| about2.write(text) | |||||
| s = Site(TEST_SITE) | |||||
| s.load() | |||||
| res = s.content.resource_from_path(about2.path) | |||||
| assert res.is_processable | |||||
| s.config.plugins = ['hyde.ext.plugins.meta.MetaPlugin'] | |||||
| gen = Generator(s) | |||||
| gen.generate_all() | |||||
| assert not res.meta.is_processable | |||||
| assert not res.is_processable | |||||
| def test_can_load_front_matter(self): | def test_can_load_front_matter(self): | ||||
| d = {'title': 'A nice title', | d = {'title': 'A nice title', | ||||
| 'author': 'Lakshmi Vyas', | 'author': 'Lakshmi Vyas', | ||||
| @@ -47,6 +47,20 @@ def test_generate_resource_from_path_with_is_processable_false(): | |||||
| about = File(Folder(site.config.deploy_root_path).child('about.html')) | about = File(Folder(site.config.deploy_root_path).child('about.html')) | ||||
| assert not about.exists | assert not about.exists | ||||
| @with_setup(create_test_site, delete_test_site) | |||||
| def test_generate_resource_from_path_with_uses_template_false(): | |||||
| site = Site(TEST_SITE) | |||||
| site.load() | |||||
| resource = site.content.resource_from_path(TEST_SITE.child('content/about.html')) | |||||
| resource.uses_template = False | |||||
| gen = Generator(site) | |||||
| gen.generate_resource_at_path(TEST_SITE.child('content/about.html')) | |||||
| about = File(Folder(site.config.deploy_root_path).child('about.html')) | |||||
| assert about.exists | |||||
| text = about.read_all() | |||||
| expected = resource.source_file.read_all() | |||||
| assert text == expected | |||||
| @with_setup(create_test_site, delete_test_site) | @with_setup(create_test_site, delete_test_site) | ||||
| def test_generate_resource_from_path_with_deploy_override(): | def test_generate_resource_from_path_with_deploy_override(): | ||||
| site = Site(TEST_SITE) | site = Site(TEST_SITE) | ||||