Mercurial > piecrust2
comparison piecrust/app.py @ 0:a212a3f2e3ee
Initial commit.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 21 Dec 2013 14:44:02 -0800 |
parents | |
children | aaa8fb7c8918 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a212a3f2e3ee |
---|---|
1 import json | |
2 import os.path | |
3 import types | |
4 import codecs | |
5 import hashlib | |
6 import logging | |
7 import yaml | |
8 from cache import SimpleCache | |
9 from decorators import lazy_property | |
10 from plugins import PluginLoader | |
11 from environment import StandardEnvironment | |
12 from configuration import Configuration, merge_dicts | |
13 | |
14 | |
15 APP_VERSION = '2.0.0alpha' | |
16 CACHE_VERSION = '2.0' | |
17 | |
18 CACHE_DIR = '_cache' | |
19 TEMPLATES_DIR = '_content/templates' | |
20 PAGES_DIR = '_content/pages' | |
21 POSTS_DIR = '_content/posts' | |
22 PLUGINS_DIR = '_content/plugins' | |
23 THEME_DIR = '_content/theme' | |
24 | |
25 CONFIG_PATH = '_content/config.yml' | |
26 THEME_CONFIG_PATH = '_content/theme_config.yml' | |
27 | |
28 | |
29 logger = logging.getLogger(__name__) | |
30 | |
31 | |
32 class VariantNotFoundError(Exception): | |
33 def __init__(self, variant_path, message=None): | |
34 super(VariantNotFoundError, self).__init__( | |
35 message or ("No such configuration variant: %s" % variant_path)) | |
36 | |
37 | |
38 class PieCrustConfiguration(Configuration): | |
39 def __init__(self, paths=None, cache_dir=False): | |
40 super(PieCrustConfiguration, self).__init__() | |
41 self.paths = paths | |
42 self.cache_dir = cache_dir | |
43 self.fixups = [] | |
44 | |
45 def applyVariant(self, variant_path, raise_if_not_found=True): | |
46 variant = self.get(variant_path) | |
47 if variant is None: | |
48 if raise_if_not_found: | |
49 raise VariantNotFoundError(variant_path) | |
50 return | |
51 if not isinstance(variant, dict): | |
52 raise VariantNotFoundError(variant_path, | |
53 "Configuration variant '%s' is not an array. " | |
54 "Check your configuration file." % variant_path) | |
55 self.merge(variant) | |
56 | |
57 def _load(self): | |
58 if self.paths is None: | |
59 self._values = self._validateAll({}) | |
60 return | |
61 | |
62 path_times = filter(self.paths, | |
63 lambda p: os.path.getmtime(p)) | |
64 cache_key = hashlib.md5("version=%s&cache=%s" % ( | |
65 APP_VERSION, CACHE_VERSION)) | |
66 | |
67 cache = None | |
68 if self.cache_dir: | |
69 cache = SimpleCache(self.cache_dir) | |
70 | |
71 if cache is not None: | |
72 if cache.isValid('config.json', path_times): | |
73 config_text = cache.read('config.json') | |
74 self._values = json.loads(config_text) | |
75 | |
76 actual_cache_key = self._values.get('__cache_key') | |
77 if actual_cache_key == cache_key: | |
78 return | |
79 | |
80 values = {} | |
81 for i, p in enumerate(self.paths): | |
82 with codecs.open(p, 'r', 'utf-8') as fp: | |
83 loaded_values = yaml.load(fp.read()) | |
84 for fixup in self.fixups: | |
85 fixup(i, loaded_values) | |
86 merge_dicts(values, loaded_values) | |
87 | |
88 for fixup in self.fixups: | |
89 fixup(len(self.paths), values) | |
90 | |
91 self._values = self._validateAll(values) | |
92 | |
93 if cache is not None: | |
94 self._values['__cache_key'] = cache_key | |
95 config_text = json.dumps(self._values) | |
96 cache.write('config.json', config_text) | |
97 | |
98 | |
99 class PieCrust(object): | |
100 def __init__(self, root, cache=True, debug=False, env=None): | |
101 self.root = root | |
102 self.debug = debug | |
103 self.cache = cache | |
104 self.plugin_loader = PluginLoader(self) | |
105 self.env = env | |
106 if self.env is None: | |
107 self.env = StandardEnvironment() | |
108 self.env.initialize(self) | |
109 | |
110 @lazy_property | |
111 def config(self): | |
112 logger.debug("Loading site configuration...") | |
113 paths = [] | |
114 if self.theme_dir: | |
115 paths.append(os.path.join(self.theme_dir, THEME_CONFIG_PATH)) | |
116 paths.append(os.path.join(self.root, CONFIG_PATH)) | |
117 | |
118 config = PieCrustConfiguration(paths, self.cache_dir) | |
119 if self.theme_dir: | |
120 # We'll need to patch the templates directories to be relative | |
121 # to the site's root, and not the theme root. | |
122 def _fixupThemeTemplatesDir(index, config): | |
123 if index == 0: | |
124 sitec = config.get('site') | |
125 if sitec: | |
126 tplc = sitec.get('templates_dirs') | |
127 if tplc: | |
128 if isinstance(tplc, types.StringTypes): | |
129 tplc = [tplc] | |
130 sitec['templates_dirs'] = filter(tplc, | |
131 lambda p: os.path.join(self.theme_dir, p)) | |
132 | |
133 config.fixups.append(_fixupThemeTemplatesDir) | |
134 | |
135 return config | |
136 | |
137 @lazy_property | |
138 def templates_dirs(self): | |
139 templates_dirs = self._get_configurable_dirs(TEMPLATES_DIR, | |
140 'site/templates_dirs') | |
141 | |
142 # Also, add the theme directory, if nay. | |
143 if self.theme_dir: | |
144 default_theme_dir = os.path.join(self.theme_dir, TEMPLATES_DIR) | |
145 if os.path.isdir(default_theme_dir): | |
146 templates_dirs.append(default_theme_dir) | |
147 | |
148 return templates_dirs | |
149 | |
150 @lazy_property | |
151 def pages_dir(self): | |
152 return self._get_dir(PAGES_DIR) | |
153 | |
154 @lazy_property | |
155 def posts_dir(self): | |
156 return self._get_dir(POSTS_DIR) | |
157 | |
158 @lazy_property | |
159 def plugins_dirs(self): | |
160 return self._get_configurable_dirs(PLUGINS_DIR, | |
161 'site/plugins_dirs') | |
162 | |
163 @lazy_property | |
164 def theme_dir(self): | |
165 return self._get_dir(THEME_DIR) | |
166 | |
167 @lazy_property | |
168 def cache_dir(self): | |
169 if self.cache: | |
170 return os.path.join(self.root, CACHE_DIR) | |
171 return False | |
172 | |
173 def _get_dir(self, default_rel_dir): | |
174 abs_dir = os.path.join(self.root, default_rel_dir) | |
175 if os.path.isdir(abs_dir): | |
176 return abs_dir | |
177 return False | |
178 | |
179 def _get_configurable_dirs(self, default_rel_dir, conf_name): | |
180 dirs = [] | |
181 | |
182 # Add custom directories from the configuration. | |
183 conf_dirs = self.config.get(conf_name) | |
184 if conf_dirs is not None: | |
185 dirs += filter(conf_dirs, | |
186 lambda p: os.path.join(self.root, p)) | |
187 | |
188 # Add the default directory if it exists. | |
189 default_dir = os.path.join(self.root, default_rel_dir) | |
190 if os.path.isdir(default_dir): | |
191 dirs.append(default_dir) | |
192 | |
193 return dirs | |
194 |