Load the sources only on startup. Fix local limit/age behavior.
[zzz-spline-frontpage.git] / splinext / frontpage / __init__.py
1 from collections import defaultdict, namedtuple
2 from pkg_resources import resource_filename
3 import re
4 import subprocess
5
6 from pylons import config
7
8 from spline.lib import helpers
9 from spline.lib.plugin import PluginBase, PluginLink, Priority
10 from spline.lib.plugin.load import run_hooks
11
12 import splinext.frontpage.controllers.frontpage
13 from splinext.frontpage.sources import FeedSource, GitSource
14
15 def add_routes_hook(map, *args, **kwargs):
16 """Hook to inject some of our behavior into the routes configuration."""
17 map.connect('/', controller='frontpage', action='index')
18
19 def load_sources_hook(*args, **kwargs):
20 """Hook to load all the known sources and stuff them in config. Run once,
21 on server startup.
22 """
23 # Extract source definitions from config and store as source_name => config
24 update_config = defaultdict(dict)
25 key_rx = re.compile(
26 '(?x) ^ spline-frontpage [.] sources [.] (\w+) (?: [.] (\w+) )? $')
27 for key, val in config.iteritems():
28 # Match against spline-frontpage.source.(source).(key)
29 match = key_rx.match(key)
30 if not match:
31 continue
32
33 source_name, subkey = match.groups()
34 if not subkey:
35 # This is the type declaration; use a special key
36 subkey = '__type__'
37
38 update_config[source_name][subkey] = val
39
40 # Figure out the global limit and expiration time, with reasonable
41 # defaults. Make sure they're integers.
42 global_limit = int(config.get('spline-frontpage.limit', 10))
43 # max_age is optional and can be None
44 try:
45 global_max_age = int(config['spline-frontpage.max_age'])
46 except KeyError:
47 global_max_age = None
48
49 config['spline-frontpage.limit'] = global_limit
50 config['spline-frontpage.max_age'] = global_max_age
51
52 # Ask plugins to turn configuration into source objects
53 sources = []
54 for source, source_config in update_config.iteritems():
55 hook_name = 'frontpage_updates_' + source_config['__type__']
56 del source_config['__type__'] # don't feed this to constructor!
57
58 # Default to global limit and max age. Source takes care of making
59 # integers and whatnot
60 source_config.setdefault('limit', global_limit)
61 source_config.setdefault('max_age', global_max_age)
62
63 # Hooks return a list of sources; combine with running list
64 sources += run_hooks(hook_name, **source_config)
65
66 # Save the list of sources, and done
67 config['spline-frontpage.sources'] = sources
68
69
70 class FrontPagePlugin(PluginBase):
71 def controllers(self):
72 return dict(
73 frontpage = splinext.frontpage.controllers.frontpage.FrontPageController,
74 )
75
76 def template_dirs(self):
77 return [
78 (resource_filename(__name__, 'templates'), Priority.FIRST)
79 ]
80
81 def hooks(self):
82 return [
83 ('routes_mapping', Priority.NORMAL, add_routes_hook),
84 ('after_setup', Priority.NORMAL, load_sources_hook),
85 ('frontpage_updates_rss', Priority.NORMAL, FeedSource),
86 ('frontpage_updates_git', Priority.NORMAL, GitSource),
87 ]