diff --git a/hyde/engine.py b/hyde/engine.py index 98005d1..45ab14a 100644 --- a/hyde/engine.py +++ b/hyde/engine.py @@ -16,7 +16,7 @@ import yaml HYDE_LAYOUTS = "HYDE_LAYOUTS" -logger = getLoggerWithConsoleHandler('hyde.engine') +logger = getLoggerWithConsoleHandler('hyde') class Engine(Application): """ diff --git a/hyde/ext/templates/jinja.py b/hyde/ext/templates/jinja.py index f33974c..a701b2f 100644 --- a/hyde/ext/templates/jinja.py +++ b/hyde/ext/templates/jinja.py @@ -104,6 +104,21 @@ class Jinja2Template(Template): jinja2_filters.register(self.env) + def get_dependencies(self, text): + """ + Finds dependencies hierarchically based on the included + files. + """ + from jinja2.meta import find_referenced_templates + ast = self.env.parse(text) + tpls = find_referenced_templates(ast) + deps = [] + for dep in tpls: + deps.append(dep) + source = self.env.loader.get_source(self.env, dep)[0] + deps.extend(self.get_dependencies(source)) + return list(set(deps)) + @property def exception_class(self): return TemplateError diff --git a/hyde/generator.py b/hyde/generator.py index b3bc144..31742da 100644 --- a/hyde/generator.py +++ b/hyde/generator.py @@ -2,7 +2,7 @@ The generator class and related utility functions. """ from hyde.exceptions import HydeException -from hyde.fs import File +from hyde.fs import File, Folder from hyde.plugin import Plugin from hyde.template import Template @@ -110,6 +110,29 @@ class Generator(object): logger.info("Generation Complete") self.events.generation_complete() + def has_resource_changed(self, resource): + target = File(self.site.config.deploy_root_path.child( + resource.relative_deploy_path)) + if not target.exists or target.older_than(resource.source_file): + return True + if resource.source_file.is_binary: + return False + deps = self.template.get_dependencies(resource.source_file.read_all()) + if not deps or None in deps: + return True + content = self.site.content.source_folder + layout = Folder(self.site.sitepath).child_folder('layout') + for dep in deps: + source = File(content.child(dep)) + if not source.exists: + source = File(layout.child(dep)) + if not source.exists: + return True + if target.older_than(source): + return True + + return False + def generate_all(self): """ Generates the entire website diff --git a/hyde/server.py b/hyde/server.py index 0ecbde0..396905a 100644 --- a/hyde/server.py +++ b/hyde/server.py @@ -10,9 +10,9 @@ from BaseHTTPServer import HTTPServer from hyde.fs import File, Folder from hyde.site import Site from hyde.generator import Generator -from hyde.util import getLoggerWithConsoleHandler -logger = getLoggerWithConsoleHandler('hyde.engine') +from hyde.util import getLoggerWithNullHandler +logger = getLoggerWithNullHandler('hyde.server') class HydeRequestHandler(SimpleHTTPRequestHandler): """ @@ -131,7 +131,7 @@ class HydeWebServer(HTTPServer): """ target = self.site.config.deploy_root_path.child( resource.relative_deploy_path) - if File(target).older_than(resource.source_file): + if self.generator.has_resource_changed(resource): try: logger.info('Generating resource [%s]' % resource) self.generator.generate_resource(resource) diff --git a/hyde/template.py b/hyde/template.py index 07eea67..3ca5321 100644 --- a/hyde/template.py +++ b/hyde/template.py @@ -25,6 +25,13 @@ class Template(object): """ abstract + + def get_dependencies(self, text): + """ + Finds the dependencies based on the included + files. + """ + return None def render(self, text, context): """ diff --git a/hyde/tests/test_generate.py b/hyde/tests/test_generate.py index 94c4ef2..fdd8fef 100644 --- a/hyde/tests/test_generate.py +++ b/hyde/tests/test_generate.py @@ -73,4 +73,24 @@ def test_generate_resource_from_path_with_deploy_override(): assert about.exists text = about.read_all() q = PyQuery(text) - assert resource.name in q("div#main").text() \ No newline at end of file + assert resource.name in q("div#main").text() + +@with_setup(create_test_site, delete_test_site) +def test_has_resource_changed(): + site = Site(TEST_SITE) + site.load() + resource = site.content.resource_from_path(TEST_SITE.child('content/about.html')) + gen = Generator(site) + gen.generate_all() + assert not gen.has_resource_changed(resource) + import time + time.sleep(1) + text = resource.source_file.read_all() + resource.source_file.write(text) + assert gen.has_resource_changed(resource) + gen.generate_all() + assert not gen.has_resource_changed(resource) + time.sleep(1) + l = File(TEST_SITE.child('layout/root.html')) + l.write(l.read_all()) + assert gen.has_resource_changed(resource) diff --git a/hyde/tests/test_jinja2template.py b/hyde/tests/test_jinja2template.py index d342c84..cbc58cf 100644 --- a/hyde/tests/test_jinja2template.py +++ b/hyde/tests/test_jinja2template.py @@ -73,6 +73,31 @@ def test_render(): assert actual("div.article p.meta").length == 20 assert actual("div.article div.text").length == 20 +def test_depends(): + t = Jinja2Template(JINJA2.path) + t.configure(None) + source = File(JINJA2.child('index.html')).read_all() + deps = list(t.get_dependencies(source)) + + assert len(deps) == 2 + + assert 'helpers.html' in deps + assert 'layout.html' in deps + +def test_depends_multi_level(): + t = Jinja2Template(JINJA2.path) + t.configure(None) + + source = "{% extends 'index.html' %}" + deps = list(t.get_dependencies(source)) + + assert len(deps) == 3 + + assert 'helpers.html' in deps + assert 'layout.html' in deps + assert 'index.html' in deps + + def test_typogrify(): source = """ {%filter typogrify%} @@ -94,12 +119,12 @@ def test_markdown(): t.configure(None) html = t.render(source, {}).strip() assert html == u'

Heading 3

' - + def test_markdown_with_extensions(): source = """ {%markdown%} ### Heading 3 - + {%endmarkdown%} """ t = Jinja2Template(JINJA2.path) diff --git a/hyde/util.py b/hyde/util.py index d9da797..d500768 100644 --- a/hyde/util.py +++ b/hyde/util.py @@ -18,7 +18,7 @@ except: pass def getLoggerWithConsoleHandler(logger_name): - logger = logging.getLogger('hyde.server') + logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) handler = logging.StreamHandler(sys.stdout) formatter = ColorFormatter(fmt="$COLOR%(levelname)s "