Mercurial > piecrust2
comparison piecrust/app.py @ 3:f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
- Serving works, with debug window.
- Baking works, multi-threading, with dependency handling.
- Various things not implemented yet.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 10 Aug 2014 23:43:16 -0700 |
parents | aaa8fb7c8918 |
children | 474c9882decf |
comparison
equal
deleted
inserted
replaced
2:40fa08b261b9 | 3:f485ba500df3 |
---|---|
1 import re | |
1 import json | 2 import json |
2 import os.path | 3 import os.path |
3 import types | 4 import types |
4 import codecs | 5 import codecs |
5 import hashlib | 6 import hashlib |
6 import logging | 7 import logging |
7 import yaml | 8 import yaml |
8 from cache import SimpleCache | 9 from werkzeug.utils import cached_property |
9 from decorators import lazy_property | 10 from piecrust import (APP_VERSION, |
10 from plugins.base import PluginLoader | 11 CACHE_DIR, TEMPLATES_DIR, |
11 from environment import StandardEnvironment | 12 PLUGINS_DIR, THEME_DIR, |
12 from configuration import Configuration, merge_dicts | 13 CONFIG_PATH, THEME_CONFIG_PATH, |
13 | 14 DEFAULT_FORMAT, DEFAULT_TEMPLATE_ENGINE, DEFAULT_POSTS_FS, |
14 | 15 DEFAULT_DATE_FORMAT, DEFAULT_PLUGIN_SOURCE, DEFAULT_THEME_SOURCE) |
15 APP_VERSION = '2.0.0alpha' | 16 from piecrust.cache import ExtensibleCache, NullCache, NullExtensibleCache |
16 CACHE_VERSION = '2.0' | 17 from piecrust.plugins.base import PluginLoader |
17 | 18 from piecrust.environment import StandardEnvironment |
18 CACHE_DIR = '_cache' | 19 from piecrust.configuration import Configuration, ConfigurationError, merge_dicts |
19 TEMPLATES_DIR = '_content/templates' | 20 from piecrust.routing import Route |
20 PAGES_DIR = '_content/pages' | 21 from piecrust.sources.base import REALM_USER, REALM_THEME |
21 POSTS_DIR = '_content/posts' | 22 from piecrust.taxonomies import Taxonomy |
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 | 23 |
28 | 24 |
29 logger = logging.getLogger(__name__) | 25 logger = logging.getLogger(__name__) |
26 | |
27 | |
28 CACHE_VERSION = 10 | |
30 | 29 |
31 | 30 |
32 class VariantNotFoundError(Exception): | 31 class VariantNotFoundError(Exception): |
33 def __init__(self, variant_path, message=None): | 32 def __init__(self, variant_path, message=None): |
34 super(VariantNotFoundError, self).__init__( | 33 super(VariantNotFoundError, self).__init__( |
35 message or ("No such configuration variant: %s" % variant_path)) | 34 message or ("No such configuration variant: %s" % variant_path)) |
36 | 35 |
37 | 36 |
38 class PieCrustConfiguration(Configuration): | 37 class PieCrustConfiguration(Configuration): |
39 def __init__(self, paths=None, cache_dir=False): | 38 def __init__(self, paths=None, cache=None, values=None, validate=True): |
40 super(PieCrustConfiguration, self).__init__() | 39 super(PieCrustConfiguration, self).__init__(values, validate) |
41 self.paths = paths | 40 self.paths = paths |
42 self.cache_dir = cache_dir | 41 self.cache = cache or NullCache() |
43 self.fixups = [] | 42 self.fixups = [] |
44 | 43 |
45 def applyVariant(self, variant_path, raise_if_not_found=True): | 44 def applyVariant(self, variant_path, raise_if_not_found=True): |
46 variant = self.get(variant_path) | 45 variant = self.get(variant_path) |
47 if variant is None: | 46 if variant is None: |
56 | 55 |
57 def _load(self): | 56 def _load(self): |
58 if self.paths is None: | 57 if self.paths is None: |
59 self._values = self._validateAll({}) | 58 self._values = self._validateAll({}) |
60 return | 59 return |
61 | 60 |
62 path_times = filter(self.paths, | 61 path_times = map(lambda p: os.path.getmtime(p), self.paths) |
63 lambda p: os.path.getmtime(p)) | 62 cache_key = hashlib.md5("version=%s&cache=%d" % ( |
64 cache_key = hashlib.md5("version=%s&cache=%s" % ( | 63 APP_VERSION, CACHE_VERSION)).hexdigest() |
65 APP_VERSION, CACHE_VERSION)) | 64 |
66 | 65 if self.cache.isValid('config.json', path_times): |
67 cache = None | 66 logger.debug("Loading configuration from cache...") |
68 if self.cache_dir: | 67 config_text = self.cache.read('config.json') |
69 cache = SimpleCache(self.cache_dir) | 68 self._values = json.loads(config_text) |
70 | 69 |
71 if cache is not None: | 70 actual_cache_key = self._values.get('__cache_key') |
72 if cache.isValid('config.json', path_times): | 71 if actual_cache_key == cache_key: |
73 config_text = cache.read('config.json') | 72 return |
74 self._values = json.loads(config_text) | 73 logger.debug("Outdated cache key '%s' (expected '%s')." % ( |
75 | 74 actual_cache_key, cache_key)) |
76 actual_cache_key = self._values.get('__cache_key') | |
77 if actual_cache_key == cache_key: | |
78 return | |
79 | 75 |
80 values = {} | 76 values = {} |
77 logger.debug("Loading configuration from: %s" % self.paths) | |
81 for i, p in enumerate(self.paths): | 78 for i, p in enumerate(self.paths): |
82 with codecs.open(p, 'r', 'utf-8') as fp: | 79 with codecs.open(p, 'r', 'utf-8') as fp: |
83 loaded_values = yaml.load(fp.read()) | 80 loaded_values = yaml.load(fp.read()) |
81 if loaded_values is None: | |
82 loaded_values = {} | |
84 for fixup in self.fixups: | 83 for fixup in self.fixups: |
85 fixup(i, loaded_values) | 84 fixup(i, loaded_values) |
86 merge_dicts(values, loaded_values) | 85 merge_dicts(values, loaded_values) |
87 | 86 |
88 for fixup in self.fixups: | 87 for fixup in self.fixups: |
89 fixup(len(self.paths), values) | 88 fixup(len(self.paths), values) |
90 | 89 |
91 self._values = self._validateAll(values) | 90 self._values = self._validateAll(values) |
92 | 91 |
93 if cache is not None: | 92 logger.debug("Caching configuration...") |
94 self._values['__cache_key'] = cache_key | 93 self._values['__cache_key'] = cache_key |
95 config_text = json.dumps(self._values) | 94 config_text = json.dumps(self._values) |
96 cache.write('config.json', config_text) | 95 self.cache.write('config.json', config_text) |
96 | |
97 def _validateAll(self, values): | |
98 # Put all the defaults in the `site` section. | |
99 default_sitec = { | |
100 'title': "Untitled PieCrust website", | |
101 'root': '/', | |
102 'default_format': DEFAULT_FORMAT, | |
103 'default_template_engine': DEFAULT_TEMPLATE_ENGINE, | |
104 'enable_gzip': True, | |
105 'pretty_urls': False, | |
106 'slugify': 'transliterate|lowercase', | |
107 'timezone': False, | |
108 'locale': False, | |
109 'date_format': DEFAULT_DATE_FORMAT, | |
110 'auto_formats': { | |
111 'html': '', | |
112 'md': 'markdown', | |
113 'textile': 'textile'}, | |
114 'default_auto_format': 'md', | |
115 'pagination_suffix': '/%num%', | |
116 'plugins_sources': [DEFAULT_PLUGIN_SOURCE], | |
117 'themes_sources': [DEFAULT_THEME_SOURCE], | |
118 'cache_time': 28800, | |
119 'display_errors': True, | |
120 'enable_debug_info': True | |
121 } | |
122 sitec = values.get('site') | |
123 if sitec is None: | |
124 sitec = {} | |
125 for key, val in default_sitec.iteritems(): | |
126 sitec.setdefault(key, val) | |
127 values['site'] = sitec | |
128 | |
129 # Add a section for our cached information. | |
130 cachec = {} | |
131 values['__cache'] = cachec | |
132 | |
133 # Cache auto-format regexes. | |
134 if not isinstance(sitec['auto_formats'], dict): | |
135 raise ConfigurationError("The 'site/auto_formats' setting must be a dictionary.") | |
136 cachec['auto_formats_re'] = r"\.(%s)$" % ( | |
137 '|'.join( | |
138 map(lambda i: re.escape(i), sitec['auto_formats'].keys()))) | |
139 if sitec['default_auto_format'] not in sitec['auto_formats']: | |
140 raise ConfigurationError("Default auto-format '%s' is not declared." % sitec['default_auto_format']) | |
141 | |
142 # Cache pagination suffix regex. | |
143 pgn_suffix = re.escape(sitec['pagination_suffix']) | |
144 pgn_suffix = pgn_suffix.replace("\\%num\\%", "(?P<num>\\d+)") + '$' | |
145 cachec['pagination_suffix_re'] = pgn_suffix | |
146 | |
147 # Make sure plugins and theme sources are lists. | |
148 if not isinstance(sitec['plugins_sources'], list): | |
149 sitec['plugins_sources'] = [sitec['plugins_sources']] | |
150 if not isinstance(sitec['themes_sources'], list): | |
151 sitec['themes_sources'] = [sitec['themes_sources']] | |
152 | |
153 # Setup values for posts/items. | |
154 ipp = sitec.get('posts_per_page') | |
155 if ipp is not None: | |
156 sitec.setdefault('items_per_page', ipp) | |
157 pf = sitec.get('posts_filters') | |
158 if pf is not None: | |
159 sitec.setdefault('items_filters', pf) | |
160 | |
161 # Figure out if we need to validate sources/routes, or auto-generate | |
162 # them from simple blog settings. | |
163 if 'sources' not in sitec: | |
164 posts_fs = sitec.setdefault('posts_fs', DEFAULT_POSTS_FS) | |
165 blogsc = sitec.setdefault('blogs', ['posts']) | |
166 | |
167 g_post_url = sitec.get('post_url', '%year%/%month%/%slug%') | |
168 g_tag_url = sitec.get('tag_url', 'tag/%tag%') | |
169 g_category_url = sitec.get('category_url', '%category%') | |
170 g_posts_per_page = sitec.get('items_per_page', 5) | |
171 g_posts_filters = sitec.get('items_filters') | |
172 g_date_format = sitec.get('date_format', DEFAULT_DATE_FORMAT) | |
173 | |
174 sourcesc = {} | |
175 sourcesc['pages'] = { | |
176 'type': 'default', | |
177 'data_endpoint': 'site/pages', | |
178 'item_name': 'page'} | |
179 sitec['sources'] = sourcesc | |
180 | |
181 routesc = [] | |
182 sitec['routes'] = routesc | |
183 | |
184 taxonomiesc = {} | |
185 taxonomiesc['tags'] = { | |
186 'multiple': True, | |
187 'term': 'tag'} | |
188 taxonomiesc['categories'] = { | |
189 'term': 'category'} | |
190 sitec['taxonomies'] = taxonomiesc | |
191 | |
192 for blog_name in blogsc: | |
193 blogc = values.get(blog_name, {}) | |
194 url_prefix = blog_name + '/' | |
195 endpoint = 'posts/%s' % blog_name | |
196 item_name = '%s-post' % blog_name | |
197 items_per_page = blogc.get('posts_per_page', g_posts_per_page) | |
198 items_filters = blogc.get('posts_filters', g_posts_filters) | |
199 date_format = blogc.get('date_format', g_date_format) | |
200 if len(blogsc) == 1: | |
201 url_prefix = '' | |
202 endpoint = 'posts' | |
203 item_name = 'post' | |
204 sourcesc[blog_name] = { | |
205 'type': 'posts/%s' % posts_fs, | |
206 'fs_endpoint': endpoint, | |
207 'data_type': 'blog', | |
208 'item_name': item_name, | |
209 'items_per_page': items_per_page, | |
210 'items_filters': items_filters, | |
211 'date_format': date_format, | |
212 'default_layout': 'post'} | |
213 tax_page_prefix = '' | |
214 if len(blogsc) > 1: | |
215 tax_page_prefix = blog_name + '/' | |
216 sourcesc[blog_name]['taxonomy_pages'] = { | |
217 'tags': ('pages:%s_tag.%%ext%%;' | |
218 'theme_pages:_tag.%%ext%%' % | |
219 tax_page_prefix), | |
220 'categories': ('pages:%s_category.%%ext%%;' | |
221 'theme_pages:_category.%%ext%%' % | |
222 tax_page_prefix)} | |
223 | |
224 post_url = blogc.get('post_url', url_prefix + g_post_url) | |
225 post_url = '/' + post_url.lstrip('/') | |
226 tag_url = blogc.get('tag_url', url_prefix + g_tag_url) | |
227 tag_url = '/' + tag_url.lstrip('/') | |
228 category_url = blogc.get('category_url', url_prefix + g_category_url) | |
229 category_url = '/' + category_url.lstrip('/') | |
230 routesc.append({'url': post_url, 'source': blog_name, | |
231 'func': 'pcposturl(year,month,day,slug)'}) | |
232 routesc.append({'url': tag_url, 'source': blog_name, | |
233 'taxonomy': 'tags', | |
234 'func': 'pctagurl(tag)'}) | |
235 routesc.append({'url': category_url, 'source': blog_name, | |
236 'taxonomy': 'categories', | |
237 'func': 'pccaturl(category)'}) | |
238 | |
239 routesc.append({'url': '/%path:path%', 'source': 'pages', | |
240 'func': 'pcurl(path)'}) | |
241 | |
242 # Validate sources/routes. | |
243 sourcesc = sitec.get('sources') | |
244 routesc = sitec.get('routes') | |
245 if not sourcesc: | |
246 raise ConfigurationError("There are no sources defined.") | |
247 if not routesc: | |
248 raise ConfigurationError("There are no routes defined.") | |
249 if not isinstance(sourcesc, dict): | |
250 raise ConfigurationError("The 'site/sources' setting must be a dictionary.") | |
251 if not isinstance(routesc, list): | |
252 raise ConfigurationError("The 'site/routes' setting must be a list.") | |
253 | |
254 # Add the theme page source if no sources were defined in the theme | |
255 # configuration itself. | |
256 has_any_theme_source = False | |
257 for sn, sc in sourcesc.iteritems(): | |
258 if sc.get('realm') == REALM_THEME: | |
259 has_any_theme_source = True | |
260 break | |
261 if not has_any_theme_source: | |
262 sitec['sources']['theme_pages'] = { | |
263 'theme_source': True, | |
264 'fs_endpoint': 'pages', | |
265 'data_endpoint': 'site/pages', | |
266 'item_name': 'page', | |
267 'realm': REALM_THEME} | |
268 sitec['routes'].append({ | |
269 'url': '/%path:path%', | |
270 'source': 'theme_pages', | |
271 'func': 'pcurl(path)'}) | |
272 | |
273 # Sources have the `default` scanner by default, duh. Also, a bunch | |
274 # of other default values for other configuration stuff. | |
275 for sn, sc in sourcesc.iteritems(): | |
276 if not isinstance(sc, dict): | |
277 raise ConfigurationError("All sources in 'site/sources' must be dictionaries.") | |
278 sc.setdefault('type', 'default') | |
279 sc.setdefault('fs_endpoint', sn) | |
280 sc.setdefault('data_endpoint', sn) | |
281 sc.setdefault('data_type', 'iterator') | |
282 sc.setdefault('item_name', sn) | |
283 sc.setdefault('items_per_page', 5) | |
284 sc.setdefault('date_format', DEFAULT_DATE_FORMAT) | |
285 sc.setdefault('realm', REALM_USER) | |
286 | |
287 # Check routes are referencing correct routes, have default | |
288 # values, etc. | |
289 for rc in routesc: | |
290 if not isinstance(rc, dict): | |
291 raise ConfigurationError("All routes in 'site/routes' must be dictionaries.") | |
292 rc_url = rc.get('url') | |
293 if not rc_url: | |
294 raise ConfigurationError("All routes in 'site/routes' must have an 'url'.") | |
295 if rc_url[0] != '/': | |
296 raise ConfigurationError("Route URLs must start with '/'.") | |
297 if rc.get('source') is None: | |
298 raise ConfigurationError("Routes must specify a source.") | |
299 if rc['source'] not in sourcesc.keys(): | |
300 raise ConfigurationError("Route is referencing unknown source: %s" % | |
301 rc['source']) | |
302 rc.setdefault('taxonomy', None) | |
303 rc.setdefault('page_suffix', '/%num%') | |
304 | |
305 # Validate taxonomies. | |
306 sitec.setdefault('taxonomies', {}) | |
307 taxonomiesc = sitec.get('taxonomies') | |
308 for tn, tc in taxonomiesc.iteritems(): | |
309 tc.setdefault('multiple', False) | |
310 tc.setdefault('term', tn) | |
311 tc.setdefault('page', '_%s.%%ext%%' % tc['term']) | |
312 | |
313 # Validate endpoints, and make sure the theme has a default source. | |
314 reserved_endpoints = set(['piecrust', 'site', 'page', 'route', | |
315 'assets', 'pagination', 'siblings', | |
316 'family']) | |
317 for name, src in sitec['sources'].iteritems(): | |
318 endpoint = src['data_endpoint'] | |
319 if endpoint in reserved_endpoints: | |
320 raise ConfigurationError( | |
321 "Source '%s' is using a reserved endpoint name: %s" % | |
322 (name, endpoint)) | |
323 | |
324 | |
325 # Done validating! | |
326 return values | |
97 | 327 |
98 | 328 |
99 class PieCrust(object): | 329 class PieCrust(object): |
100 def __init__(self, root, cache=True, debug=False, env=None): | 330 def __init__(self, root_dir, cache=True, debug=False, theme_site=False, |
101 self.root = root | 331 env=None): |
332 self.root_dir = root_dir | |
102 self.debug = debug | 333 self.debug = debug |
103 self.cache = cache | 334 self.theme_site = theme_site |
104 self.plugin_loader = PluginLoader(self) | 335 self.plugin_loader = PluginLoader(self) |
336 | |
337 if cache: | |
338 self.cache = ExtensibleCache(self.cache_dir) | |
339 else: | |
340 self.cache = NullExtensibleCache() | |
341 | |
105 self.env = env | 342 self.env = env |
106 if self.env is None: | 343 if self.env is None: |
107 self.env = StandardEnvironment() | 344 self.env = StandardEnvironment() |
108 self.env.initialize(self) | 345 self.env.initialize(self) |
109 | 346 |
110 @lazy_property | 347 @cached_property |
111 def config(self): | 348 def config(self): |
112 logger.debug("Loading site configuration...") | 349 logger.debug("Creating site configuration...") |
113 paths = [] | 350 paths = [] |
114 if self.theme_dir: | 351 if self.theme_dir: |
115 paths.append(os.path.join(self.theme_dir, THEME_CONFIG_PATH)) | 352 paths.append(os.path.join(self.theme_dir, THEME_CONFIG_PATH)) |
116 paths.append(os.path.join(self.root, CONFIG_PATH)) | 353 paths.append(os.path.join(self.root_dir, CONFIG_PATH)) |
117 | 354 |
118 config = PieCrustConfiguration(paths, self.cache_dir) | 355 config_cache = self.cache.getCache('app') |
356 config = PieCrustConfiguration(paths, config_cache) | |
119 if self.theme_dir: | 357 if self.theme_dir: |
120 # We'll need to patch the templates directories to be relative | 358 # We'll need to patch the templates directories to be relative |
121 # to the site's root, and not the theme root. | 359 # to the site's root, and not the theme root. |
122 def _fixupThemeTemplatesDir(index, config): | 360 def _fixupThemeTemplatesDir(index, config): |
123 if index == 0: | 361 if index != 0: |
124 sitec = config.get('site') | 362 return |
125 if sitec: | 363 sitec = config.get('site') |
126 tplc = sitec.get('templates_dirs') | 364 if sitec is None: |
127 if tplc: | 365 return |
128 if isinstance(tplc, types.StringTypes): | 366 tplc = sitec.get('templates_dirs') |
129 tplc = [tplc] | 367 if tplc is None: |
130 sitec['templates_dirs'] = filter(tplc, | 368 return |
131 lambda p: os.path.join(self.theme_dir, p)) | 369 if isinstance(tplc, types.StringTypes): |
132 | 370 tplc = [tplc] |
371 sitec['templates_dirs'] = filter(tplc, | |
372 lambda p: os.path.join(self.theme_dir, p)) | |
133 config.fixups.append(_fixupThemeTemplatesDir) | 373 config.fixups.append(_fixupThemeTemplatesDir) |
134 | 374 |
375 # We'll also need to flag all page sources as coming from | |
376 # the theme. | |
377 def _fixupThemeSources(index, config): | |
378 if index != 0: | |
379 return | |
380 sitec = config.get('site') | |
381 if sitec is None: | |
382 sitec = {} | |
383 config['site'] = sitec | |
384 srcc = sitec.get('sources') | |
385 if srcc is not None: | |
386 for sn, sc in srcc.iteritems(): | |
387 sc['realm'] = REALM_THEME | |
388 config.fixups.append(_fixupThemeSources) | |
389 | |
135 return config | 390 return config |
136 | 391 |
137 @lazy_property | 392 @cached_property |
138 def templates_dirs(self): | 393 def templates_dirs(self): |
139 templates_dirs = self._get_configurable_dirs(TEMPLATES_DIR, | 394 templates_dirs = self._get_configurable_dirs(TEMPLATES_DIR, |
140 'site/templates_dirs') | 395 'site/templates_dirs') |
141 | 396 |
142 # Also, add the theme directory, if nay. | 397 # Also, add the theme directory, if nay. |
145 if os.path.isdir(default_theme_dir): | 400 if os.path.isdir(default_theme_dir): |
146 templates_dirs.append(default_theme_dir) | 401 templates_dirs.append(default_theme_dir) |
147 | 402 |
148 return templates_dirs | 403 return templates_dirs |
149 | 404 |
150 @lazy_property | 405 @cached_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): | 406 def plugins_dirs(self): |
160 return self._get_configurable_dirs(PLUGINS_DIR, | 407 return self._get_configurable_dirs(PLUGINS_DIR, |
161 'site/plugins_dirs') | 408 'site/plugins_dirs') |
162 | 409 |
163 @lazy_property | 410 @cached_property |
164 def theme_dir(self): | 411 def theme_dir(self): |
165 return self._get_dir(THEME_DIR) | 412 td = self._get_dir(THEME_DIR) |
166 | 413 if td is not None: |
167 @lazy_property | 414 return td |
415 return os.path.join(os.path.dirname(__file__), 'resources', 'theme') | |
416 | |
417 @cached_property | |
168 def cache_dir(self): | 418 def cache_dir(self): |
169 if self.cache: | 419 return os.path.join(self.root_dir, CACHE_DIR) |
170 return os.path.join(self.root, CACHE_DIR) | 420 |
171 return False | 421 @cached_property |
422 def sources(self): | |
423 defs = {} | |
424 for cls in self.plugin_loader.getSources(): | |
425 defs[cls.SOURCE_NAME] = cls | |
426 | |
427 sources = [] | |
428 for n, s in self.config.get('site/sources').iteritems(): | |
429 cls = defs.get(s['type']) | |
430 if cls is None: | |
431 raise ConfigurationError("No such page source type: %s" % s['type']) | |
432 src = cls(self, n, s) | |
433 sources.append(src) | |
434 return sources | |
435 | |
436 @cached_property | |
437 def routes(self): | |
438 routes = [] | |
439 for r in self.config.get('site/routes'): | |
440 rte = Route(self, r) | |
441 routes.append(rte) | |
442 return routes | |
443 | |
444 @cached_property | |
445 def taxonomies(self): | |
446 taxonomies = [] | |
447 for tn, tc in self.config.get('site/taxonomies').iteritems(): | |
448 tax = Taxonomy(self, tn, tc) | |
449 taxonomies.append(tax) | |
450 return taxonomies | |
451 | |
452 def getSource(self, source_name): | |
453 for source in self.sources: | |
454 if source.name == source_name: | |
455 return source | |
456 return None | |
457 | |
458 def getRoutes(self, source_name, skip_taxonomies=False): | |
459 for route in self.routes: | |
460 if route.source_name == source_name: | |
461 if not skip_taxonomies or route.taxonomy is None: | |
462 yield route | |
463 | |
464 def getRoute(self, source_name, source_metadata): | |
465 for route in self.getRoutes(source_name, True): | |
466 if route.isMatch(source_metadata): | |
467 return route | |
468 return None | |
469 | |
470 def getTaxonomyRoute(self, tax_name, source_name): | |
471 for route in self.routes: | |
472 if route.taxonomy == tax_name and route.source_name == source_name: | |
473 return route | |
474 return None | |
475 | |
476 def getTaxonomy(self, tax_name): | |
477 for tax in self.taxonomies: | |
478 if tax.name == tax_name: | |
479 return tax | |
480 return None | |
172 | 481 |
173 def _get_dir(self, default_rel_dir): | 482 def _get_dir(self, default_rel_dir): |
174 abs_dir = os.path.join(self.root, default_rel_dir) | 483 abs_dir = os.path.join(self.root_dir, default_rel_dir) |
175 if os.path.isdir(abs_dir): | 484 if os.path.isdir(abs_dir): |
176 return abs_dir | 485 return abs_dir |
177 return False | 486 return None |
178 | 487 |
179 def _get_configurable_dirs(self, default_rel_dir, conf_name): | 488 def _get_configurable_dirs(self, default_rel_dir, conf_name): |
180 dirs = [] | 489 dirs = [] |
181 | 490 |
182 # Add custom directories from the configuration. | 491 # Add custom directories from the configuration. |
183 conf_dirs = self.config.get(conf_name) | 492 conf_dirs = self.config.get(conf_name) |
184 if conf_dirs is not None: | 493 if conf_dirs is not None: |
185 dirs += filter(conf_dirs, | 494 if isinstance(conf_dirs, types.StringTypes): |
186 lambda p: os.path.join(self.root, p)) | 495 dirs.append(os.path.join(self.root_dir, conf_dirs)) |
496 else: | |
497 dirs += filter(lambda p: os.path.join(self.root_dir, p), | |
498 conf_dirs) | |
187 | 499 |
188 # Add the default directory if it exists. | 500 # Add the default directory if it exists. |
189 default_dir = os.path.join(self.root, default_rel_dir) | 501 default_dir = os.path.join(self.root_dir, default_rel_dir) |
190 if os.path.isdir(default_dir): | 502 if os.path.isdir(default_dir): |
191 dirs.append(default_dir) | 503 dirs.append(default_dir) |
192 | 504 |
193 return dirs | 505 return dirs |
194 | 506 |