@@ -1,3 +1,10 @@ | |||
Version 0.8.3c11 | |||
================= | |||
* `hyde serve` now picks up changes in config data automatically. | |||
(Issue #24) | |||
Version 0.8.3c10 | |||
=============== | |||
@@ -27,15 +27,19 @@ class Generator(object): | |||
self.site = site | |||
self.generated_once = False | |||
self.deps = Dependents(site.sitepath) | |||
self.create_context() | |||
self.template = None | |||
Plugin.load_all(site) | |||
self.events = Plugin.get_proxy(self.site) | |||
def create_context(self): | |||
site = self.site | |||
self.__context__ = dict(site=site) | |||
if hasattr(site.config, 'context'): | |||
site.context = Context.load(site.sitepath, site.config.context) | |||
self.__context__.update(site.context) | |||
self.template = None | |||
Plugin.load_all(site) | |||
self.events = Plugin.get_proxy(self.site) | |||
@contextmanager | |||
def context_for_resource(self, resource): | |||
@@ -43,8 +47,6 @@ class Generator(object): | |||
Context manager that intializes the context for a given | |||
resource and rolls it back after the resource is processed. | |||
""" | |||
# TODO: update metadata and other resource | |||
# specific properties here. | |||
self.__context__.update( | |||
resource=resource, | |||
node=resource.node, | |||
@@ -103,10 +105,7 @@ class Generator(object): | |||
Checks if the site requries a reload and loads if | |||
necessary. | |||
""" | |||
#TODO: Perhaps this is better suited in Site | |||
if not len(self.site.content.child_nodes): | |||
logger.info("Reading site contents") | |||
self.site.load() | |||
self.site.reload_if_needed() | |||
def finalize(self): | |||
""" | |||
@@ -154,8 +153,9 @@ class Generator(object): | |||
last generation. | |||
""" | |||
logger.debug("Checking for changes in %s" % resource) | |||
self.load_site_if_needed() | |||
self.load_template_if_needed() | |||
self.load_site_if_needed() | |||
target = File(self.site.config.deploy_root_path.child( | |||
resource.relative_deploy_path)) | |||
if not target.exists or target.older_than(resource.source_file): | |||
@@ -164,6 +164,11 @@ class Generator(object): | |||
if resource.source_file.is_binary: | |||
logger.debug("No Changes found in %s" % resource) | |||
return False | |||
if self.site.config.needs_refresh() or \ | |||
not target.has_changed_since(self.site.config.last_modified): | |||
logger.debug("Site configuration changed") | |||
return True | |||
deps = self.get_dependencies(resource) | |||
if not deps or None in deps: | |||
logger.debug("No changes found in %s" % resource) | |||
@@ -282,8 +287,14 @@ class Generator(object): | |||
except HydeException: | |||
self.generate_all() | |||
def refresh_config(self): | |||
if self.site.config.needs_refresh(): | |||
logger.debug("Refreshing configuration and context") | |||
self.site.refresh_config() | |||
self.create_context() | |||
def __generate_node__(self, node, incremental=False): | |||
self.refresh_config() | |||
for node in node.walk(): | |||
logger.debug("Generating Node [%s]", node) | |||
self.events.begin_node(node) | |||
@@ -293,6 +304,7 @@ class Generator(object): | |||
def __generate_resource__(self, resource, incremental=False): | |||
self.refresh_config() | |||
if not resource.is_processable: | |||
logger.debug("Skipping [%s]", resource) | |||
return | |||
@@ -6,8 +6,9 @@ from hyde.fs import File, Folder | |||
import codecs | |||
import yaml | |||
from datetime import datetime | |||
from UserDict import IterableUserDict | |||
from hyde.util import getLoggerWithNullHandler | |||
logger = getLoggerWithNullHandler('hyde.engine') | |||
@@ -135,13 +136,27 @@ class Config(Expando): | |||
plugins = [], | |||
ignore = [ "*~", "*.bak" ] | |||
) | |||
conf = dict(**default_config) | |||
self.config_file = config_file | |||
self.config_dict = config_dict | |||
self.load_time = datetime.min | |||
self.config_files = [] | |||
self.sitepath = Folder(sitepath) | |||
conf = dict(**default_config) | |||
conf.update(self.read_config(config_file)) | |||
if config_dict: | |||
conf.update(config_dict) | |||
super(Config, self).__init__(conf) | |||
@property | |||
def last_modified(self): | |||
return max((conf.last_modified for conf in self.config_files)) | |||
def needs_refresh(self): | |||
if not self.config_files: | |||
return True | |||
return any((conf.has_changed_since(self.load_time) | |||
for conf in self.config_files)) | |||
def read_config(self, config_file): | |||
""" | |||
Reads the configuration file and updates this | |||
@@ -152,6 +167,7 @@ class Config(Expando): | |||
config_file else 'site.yaml') | |||
conf = {} | |||
if File(conf_file).exists: | |||
self.config_files.append(File(conf_file)) | |||
logger.info("Reading site configuration from [%s]", conf_file) | |||
with codecs.open(conf_file, 'r', 'utf-8') as stream: | |||
conf = yaml.load(stream) | |||
@@ -159,6 +175,7 @@ class Config(Expando): | |||
parent = self.read_config(conf['extends']) | |||
parent.update(conf) | |||
conf = parent | |||
self.load_time = datetime.now() | |||
return conf | |||
@@ -8,6 +8,7 @@ import select | |||
import threading | |||
import urlparse | |||
import urllib | |||
from datetime import datetime | |||
from SimpleHTTPServer import SimpleHTTPRequestHandler | |||
from BaseHTTPServer import HTTPServer | |||
from hyde.fs import File, Folder | |||
@@ -18,8 +19,6 @@ from hyde.exceptions import HydeException | |||
from hyde.util import getLoggerWithNullHandler | |||
logger = getLoggerWithNullHandler('hyde.server') | |||
from datetime import datetime | |||
class HydeRequestHandler(SimpleHTTPRequestHandler): | |||
""" | |||
Serves files by regenerating the resource (or) | |||
@@ -5,12 +5,13 @@ Parses & holds information about the site to be generated. | |||
import os | |||
import fnmatch | |||
import urlparse | |||
from functools import wraps | |||
from hyde.exceptions import HydeException | |||
from hyde.fs import FS, File, Folder | |||
from hyde.model import Config | |||
from hyde.util import getLoggerWithNullHandler | |||
from functools import wraps | |||
def path_normalized(f): | |||
@wraps(f) | |||
@@ -359,7 +360,6 @@ class RootNode(Node): | |||
return | |||
self.add_resource(afile) | |||
class Site(object): | |||
""" | |||
Represents the site to be generated. | |||
@@ -373,11 +373,29 @@ class Site(object): | |||
self.plugins = [] | |||
self.context = {} | |||
def refresh_config(self): | |||
""" | |||
Refreshes config data if one or more config files have | |||
changed. Note that this does not refresh the meta data. | |||
""" | |||
if self.config.needs_refresh(): | |||
logger.debug("Refreshing config data") | |||
self.config = Config(self.sitepath, | |||
self.config.config_file, | |||
self.config.config_dict) | |||
def reload_if_needed(self): | |||
""" | |||
Reloads if the site has not been loaded before or if the | |||
configuration has changed since the last load. | |||
""" | |||
if not len(self.content.child_nodes): | |||
self.load() | |||
def load(self): | |||
""" | |||
Walks the content and media folders to load up the sitemap. | |||
""" | |||
self.content.load() | |||
def content_url(self, path): | |||
@@ -303,7 +303,6 @@ class TestSorterMeta(object): | |||
"another-sad-post.html", | |||
"happy-post.html"] | |||
for r in s.content.walk_resources(): | |||
print r.meta.to_dict() | |||
expected = r.name in have_index | |||
assert attributes_checker(r, ['meta.index']) == expected | |||
@@ -77,9 +77,9 @@ class TestGenerator(object): | |||
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) | |||
assert not gen.has_resource_changed(resource) | |||
text = resource.source_file.read_all() | |||
resource.source_file.write(text) | |||
assert gen.has_resource_changed(resource) | |||
@@ -160,4 +160,4 @@ main: | |||
assert "abc = def" in out | |||
assert "home" in out | |||
assert "articles" in out | |||
assert "projects" in out | |||
assert "projects" in out |