| @@ -116,12 +116,7 @@ class Engine(Application): | |||||
| Creates a site object from the given sitepath and the config file. | Creates a site object from the given sitepath and the config file. | ||||
| """ | """ | ||||
| sitepath = Folder(Folder(sitepath).fully_expanded_path) | sitepath = Folder(Folder(sitepath).fully_expanded_path) | ||||
| config_file = sitepath.child(config) | |||||
| logger.info("Reading site configuration from [%s]", config_file) | |||||
| conf = {} | |||||
| with codecs.open(config_file, 'r', 'utf-8') as stream: | |||||
| conf = yaml.load(stream) | |||||
| config = Config(sitepath, conf) | |||||
| config = Config(sitepath, config_file=config) | |||||
| if deploy: | if deploy: | ||||
| config.deploy_root = deploy | config.deploy_root = deploy | ||||
| return Site(sitepath, config) | return Site(sitepath, config) | ||||
| @@ -43,7 +43,7 @@ hyde [-s </site/path>] [-v] create [-l <layout>] [-f] [-h] | |||||
| While basic and test are really barebones, doc is the one that generates | While basic and test are really barebones, doc is the one that generates | ||||
| this documentation and is completely usable. Hyde will get more layouts | this documentation and is completely usable. Hyde will get more layouts | ||||
| as over time. | |||||
| over time. | |||||
| Hyde tries to locate the specified layout in the following folders: | Hyde tries to locate the specified layout in the following folders: | ||||
| @@ -62,7 +62,7 @@ | |||||
| <header class="banner clearfix"> | <header class="banner clearfix"> | ||||
| {% block header -%} | {% block header -%} | ||||
| <img src="{{ media_url('img/hyde-logo-128.png') }}"> | <img src="{{ media_url('img/hyde-logo-128.png') }}"> | ||||
| <h1>hyde 1.0</h1> | |||||
| <h1>hyde 0.6</h1> | |||||
| <h3>static hotness</h3> | <h3>static hotness</h3> | ||||
| {%- endblock %} | {%- endblock %} | ||||
| </header> | </header> | ||||
| @@ -0,0 +1,3 @@ | |||||
| extends: site.yaml | |||||
| mode: production | |||||
| deploy_root: ../../../../hydepy.github.com | |||||
| @@ -3,8 +3,12 @@ | |||||
| Contains data structures and utilities for hyde. | Contains data structures and utilities for hyde. | ||||
| """ | """ | ||||
| from hyde.fs import File, Folder | from hyde.fs import File, Folder | ||||
| import codecs | |||||
| import yaml | import yaml | ||||
| from hyde.util import getLoggerWithNullHandler | |||||
| logger = getLoggerWithNullHandler('hyde.engine') | |||||
| class Expando(object): | class Expando(object): | ||||
| """ | """ | ||||
| A generic expando class that creates attributes from | A generic expando class that creates attributes from | ||||
| @@ -69,7 +73,7 @@ class Config(Expando): | |||||
| Represents the hyde configuration file | Represents the hyde configuration file | ||||
| """ | """ | ||||
| def __init__(self, sitepath, config_dict=None): | |||||
| def __init__(self, sitepath, config_file=None, config_dict=None): | |||||
| default_config = dict( | default_config = dict( | ||||
| content_root='content', | content_root='content', | ||||
| deploy_root='deploy', | deploy_root='deploy', | ||||
| @@ -81,10 +85,31 @@ class Config(Expando): | |||||
| plugins = [] | plugins = [] | ||||
| ) | ) | ||||
| conf = dict(**default_config) | conf = dict(**default_config) | ||||
| self.sitepath = Folder(sitepath) | |||||
| conf.update(self.read_config(config_file)) | |||||
| if config_dict: | if config_dict: | ||||
| conf.update(config_dict) | conf.update(config_dict) | ||||
| super(Config, self).__init__(conf) | super(Config, self).__init__(conf) | ||||
| self.sitepath = Folder(sitepath) | |||||
| def read_config(self, config_file): | |||||
| """ | |||||
| Reads the configuration file and updates this | |||||
| object while allowing for inherited configurations. | |||||
| """ | |||||
| conf_file = self.sitepath.child( | |||||
| config_file if | |||||
| config_file else 'site.yaml') | |||||
| conf = {} | |||||
| if File(conf_file).exists: | |||||
| logger.info("Reading site configuration from [%s]", conf_file) | |||||
| with codecs.open(conf_file, 'r', 'utf-8') as stream: | |||||
| conf = yaml.load(stream) | |||||
| if 'extends' in conf: | |||||
| parent = self.read_config(conf['extends']) | |||||
| parent.update(conf) | |||||
| conf = parent | |||||
| return conf | |||||
| @property | @property | ||||
| def deploy_root_path(self): | def deploy_root_path(self): | ||||
| @@ -1,7 +1,4 @@ | |||||
| mode: development | mode: development | ||||
| media_root:: media # Relative path from site root (the directory where this file exists) | media_root:: media # Relative path from site root (the directory where this file exists) | ||||
| media_url: /media | media_url: /media | ||||
| template: hyde.ext.jinja2 | |||||
| widgets: | |||||
| plugins: | |||||
| aggregators: | |||||
| template: hyde.ext.jinja2 | |||||
| @@ -1,4 +1,4 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | """ | ||||
| Use nose | Use nose | ||||
| `$ pip install nose` | `$ pip install nose` | ||||
| @@ -108,7 +108,7 @@ def test_markdown_with_extensions(): | |||||
| """ | """ | ||||
| t = Jinja2Template(JINJA2.path) | t = Jinja2Template(JINJA2.path) | ||||
| s = Site(JINJA2.path) | s = Site(JINJA2.path) | ||||
| c = Config(JINJA2.path, dict(markdown=dict(extensions=['headerid']))) | |||||
| c = Config(JINJA2.path, config_dict=dict(markdown=dict(extensions=['headerid']))) | |||||
| s.config = c | s.config = c | ||||
| t.configure(s) | t.configure(s) | ||||
| html = t.render(source, {}).strip() | html = t.render(source, {}).strip() | ||||
| @@ -43,7 +43,8 @@ def test_expando_update(): | |||||
| assert x.a == 789 | assert x.a == 789 | ||||
| assert x.f == "opq" | assert x.f == "opq" | ||||
| TEST_SITE_ROOT = File(__file__).parent.child_folder('sites/test_jinja') | |||||
| TEST_SITE = File(__file__).parent.child_folder('_test') | |||||
| import yaml | import yaml | ||||
| class TestConfig(object): | class TestConfig(object): | ||||
| @@ -70,27 +71,65 @@ class TestConfig(object): | |||||
| aggregators: | aggregators: | ||||
| """ | """ | ||||
| def setUp(self): | |||||
| TEST_SITE.make() | |||||
| TEST_SITE.parent.child_folder('sites/test_jinja').copy_contents_to(TEST_SITE) | |||||
| def tearDown(self): | |||||
| TEST_SITE.delete() | |||||
| def test_default_configuration(self): | def test_default_configuration(self): | ||||
| c = Config(sitepath=TEST_SITE_ROOT) | |||||
| c = Config(sitepath=TEST_SITE, config_dict={}) | |||||
| for root in ['content', 'layout', 'media']: | for root in ['content', 'layout', 'media']: | ||||
| name = root + '_root' | name = root + '_root' | ||||
| path = name + '_path' | path = name + '_path' | ||||
| assert hasattr(c, name) | assert hasattr(c, name) | ||||
| assert getattr(c, name) == root | assert getattr(c, name) == root | ||||
| assert hasattr(c, path) | assert hasattr(c, path) | ||||
| assert getattr(c, path) == TEST_SITE_ROOT.child_folder(root) | |||||
| assert getattr(c, path) == TEST_SITE.child_folder(root) | |||||
| assert hasattr(c, 'plugins') | assert hasattr(c, 'plugins') | ||||
| assert len(c.plugins) == 0 | assert len(c.plugins) == 0 | ||||
| assert c.deploy_root_path == TEST_SITE_ROOT.child_folder('deploy') | |||||
| assert c.deploy_root_path == TEST_SITE.child_folder('deploy') | |||||
| assert c.not_found == '404.html' | assert c.not_found == '404.html' | ||||
| def test_conf1(self): | def test_conf1(self): | ||||
| c = Config(sitepath=TEST_SITE_ROOT, config_dict=yaml.load(self.conf1)) | |||||
| assert c.content_root_path == TEST_SITE_ROOT.child_folder('stuff') | |||||
| c = Config(sitepath=TEST_SITE, config_dict=yaml.load(self.conf1)) | |||||
| assert c.content_root_path == TEST_SITE.child_folder('stuff') | |||||
| def test_conf2(self): | def test_conf2(self): | ||||
| c = Config(sitepath=TEST_SITE_ROOT, config_dict=yaml.load(self.conf2)) | |||||
| assert c.content_root_path == TEST_SITE_ROOT.child_folder('site/stuff') | |||||
| assert c.media_root_path == TEST_SITE_ROOT.child_folder('mmm') | |||||
| assert c.media_url == TEST_SITE_ROOT.child_folder('/media') | |||||
| c = Config(sitepath=TEST_SITE, config_dict=yaml.load(self.conf2)) | |||||
| assert c.content_root_path == TEST_SITE.child_folder('site/stuff') | |||||
| assert c.media_root_path == TEST_SITE.child_folder('mmm') | |||||
| assert c.media_url == TEST_SITE.child_folder('/media') | |||||
| assert c.deploy_root_path == Folder('~/deploy_site') | |||||
| def test_read_from_file_by_default(self): | |||||
| File(TEST_SITE.child('site.yaml')).write(self.conf2) | |||||
| c = Config(sitepath=TEST_SITE) | |||||
| assert c.content_root_path == TEST_SITE.child_folder('site/stuff') | |||||
| assert c.media_root_path == TEST_SITE.child_folder('mmm') | |||||
| assert c.media_url == TEST_SITE.child_folder('/media') | |||||
| assert c.deploy_root_path == Folder('~/deploy_site') | |||||
| def test_read_from_specified_file(self): | |||||
| File(TEST_SITE.child('another.yaml')).write(self.conf2) | |||||
| c = Config(sitepath=TEST_SITE, config_file='another.yaml') | |||||
| assert c.content_root_path == TEST_SITE.child_folder('site/stuff') | |||||
| assert c.media_root_path == TEST_SITE.child_folder('mmm') | |||||
| assert c.media_url == TEST_SITE.child_folder('/media') | |||||
| assert c.deploy_root_path == Folder('~/deploy_site') | |||||
| def test_extends(self): | |||||
| another = """ | |||||
| extends: site.yaml | |||||
| mode: production | |||||
| media_root: xxx | |||||
| """ | |||||
| File(TEST_SITE.child('site.yaml')).write(self.conf2) | |||||
| File(TEST_SITE.child('another.yaml')).write(another) | |||||
| c = Config(sitepath=TEST_SITE, config_file='another.yaml') | |||||
| assert c.mode == 'production' | |||||
| assert c.content_root_path == TEST_SITE.child_folder('site/stuff') | |||||
| assert c.media_root_path == TEST_SITE.child_folder('xxx') | |||||
| assert c.media_url == TEST_SITE.child_folder('/media') | |||||
| assert c.deploy_root_path == Folder('~/deploy_site') | assert c.deploy_root_path == Folder('~/deploy_site') | ||||