+from collections import defaultdict, namedtuple
from pkg_resources import resource_filename
+import re
+import subprocess
-from spline.lib.plugin import PluginBase
+from pylons import config
+
+from spline.lib import helpers
from spline.lib.plugin import PluginBase, PluginLink, Priority
+from spline.lib.plugin.load import run_hooks
import splinext.frontpage.controllers.frontpage
+from splinext.frontpage.sources import FeedSource, GitSource
def add_routes_hook(map, *args, **kwargs):
"""Hook to inject some of our behavior into the routes configuration."""
map.connect('/', controller='frontpage', action='index')
+def load_sources_hook(config, *args, **kwargs):
+ """Hook to load all the known sources and stuff them in config. Run once,
+ on server startup.
+
+ Frontpage hooks are also passed the `config` hash, as it's not available
+ during setup.
+ """
+ # Extract source definitions from config and store as source_name => config
+ update_config = defaultdict(dict)
+ key_rx = re.compile(
+ '(?x) ^ spline-frontpage [.] sources [.] (\w+) (?: [.] (\w+) )? $')
+ for key, val in config.iteritems():
+ # Match against spline-frontpage.source.(source).(key)
+ match = key_rx.match(key)
+ if not match:
+ continue
+
+ source_name, subkey = match.groups()
+ if not subkey:
+ # This is the type declaration; use a special key
+ subkey = '__type__'
+
+ update_config[source_name][subkey] = val
+
+ # Figure out the global limit and expiration time, with reasonable
+ # defaults. Make sure they're integers.
+ global_limit = int(config.get('spline-frontpage.limit', 10))
+ # max_age is optional and can be None
+ try:
+ global_max_age = int(config['spline-frontpage.max_age'])
+ except KeyError:
+ global_max_age = None
+
+ config['spline-frontpage.limit'] = global_limit
+ config['spline-frontpage.max_age'] = global_max_age
+
+ # Ask plugins to turn configuration into source objects
+ sources = []
+ for source, source_config in update_config.iteritems():
+ hook_name = 'frontpage_updates_' + source_config['__type__']
+ del source_config['__type__'] # don't feed this to constructor!
+
+ # Default to global limit and max age. Source takes care of making
+ # integers and whatnot
+ source_config.setdefault('limit', global_limit)
+ source_config.setdefault('max_age', global_max_age)
+
+ # Hooks return a list of sources; combine with running list
+ sources += run_hooks(hook_name, config=config, **source_config)
+
+ # Save the list of sources, and done
+ config['spline-frontpage.sources'] = sources
+
+def source_cron_hook(*args, **kwargs):
+ """Hook to pass on cron tics to all sources, should they need it for e.g.
+ caching.
+ """
+ for source in config['spline-frontpage.sources']:
+ source.do_cron(*args, **kwargs)
class FrontPagePlugin(PluginBase):
def controllers(self):
def hooks(self):
return [
- ('routes_mapping', Priority.NORMAL, add_routes_hook),
+ ('routes_mapping', Priority.NORMAL, add_routes_hook),
+ ('after_setup', Priority.NORMAL, load_sources_hook),
+ ('cron', Priority.NORMAL, source_cron_hook),
+ ('frontpage_updates_rss', Priority.NORMAL, FeedSource),
+ ('frontpage_updates_git', Priority.NORMAL, GitSource),
]