45b1587adc3336d8af8b408c5d805671a8ec722d
[zzz-spline-frontpage.git] / splinext / frontpage / __init__.py
1 from collections import namedtuple
2 import datetime
3 from pkg_resources import resource_filename
4 import subprocess
5
6 import feedparser
7
8 from spline.lib import helpers
9 from spline.lib.plugin import PluginBase, PluginLink, Priority
10
11 import splinext.frontpage.controllers.frontpage
12
13 class FrontPageUpdate(object):
14 """Base class ('interface') for an updated thing that may appear on the
15 front page.
16
17 Subclasses should implement the `time` and `template` properties.
18 """
19 pass
20
21
22 FrontPageRSS = namedtuple('FrontPageRSS',
23 ['time', 'entry', 'template', 'category', 'content', 'icon'])
24
25 def rss_hook(limit, url, title, icon=None):
26 """Front page handler for news feeds."""
27 feed = feedparser.parse(url)
28
29 updates = []
30 for entry in feed.entries:
31 # Try to find something to show! Default to the summary, if there is
32 # one, or try to generate one otherwise
33 content = u''
34 if 'summary' in entry:
35 content = entry.summary
36 elif 'content' in entry:
37 content = entry.content[0].value
38
39 content = helpers.literal(content)
40
41 update = FrontPageRSS(
42 time = datetime.datetime(*entry.published_parsed[:6]),
43 entry = entry,
44 template = '/front_page/rss.mako',
45 category = title,
46 content = content,
47 icon = icon,
48 )
49 updates.append(update)
50
51 return updates
52
53
54 FrontPageGit = namedtuple('FrontPageGit',
55 ['time', 'gitweb', 'log', 'tag', 'template', 'category', 'icon'])
56 FrontPageGitCommit = namedtuple('FrontPageGitCommit',
57 ['hash', 'author', 'time', 'subject', 'repo'])
58
59 def git_hook(limit, title, gitweb, repo_paths, repo_names,
60 tag_pattern=None, icon=None):
61
62 """Front page handler for repository history."""
63 # Repo stuff can be space-delimited lists...
64 repo_paths = repo_paths.split()
65 repo_names = repo_names.split()
66
67 # Fetch the main repo's git tags
68 args = [
69 'git',
70 '--git-dir=' + repo_paths[0],
71 'tag', '-l',
72 ]
73 if tag_pattern:
74 args.append(tag_pattern)
75
76 proc = subprocess.Popen(args, stdout=subprocess.PIPE)
77 git_output, _ = proc.communicate()
78 tags = git_output.strip().split('\n')
79
80 # Tags come out in alphabetical order, which means earliest first. Reverse
81 # it to make the slicing easier
82 tags.reverse()
83 # Only history from tag to tag is actually interesting, so get the most
84 # recent $limit tags but skip the earliest
85 interesting_tags = tags[:-1][:limit]
86
87 updates = []
88 for tag, since_tag in zip(interesting_tags, tags[1:]):
89 commits = []
90
91 for repo_path, repo_name in zip(repo_paths, repo_names):
92 # Grab an easily-parsed history: fields delimited by nulls.
93 # Hash, author's name, commit timestamp, subject.
94 git_log_args = [
95 'git',
96 '--git-dir=' + repo_path,
97 'log',
98 '--pretty=%h%x00%an%x00%at%x00%s',
99 "{0}..{1}".format(since_tag, tag),
100 ]
101 proc = subprocess.Popen(git_log_args, stdout=subprocess.PIPE)
102 for line in proc.stdout:
103 hash, author, time, subject = line.strip().split('\x00')
104 commits.append(
105 FrontPageGitCommit(
106 hash = hash,
107 author = author,
108 time = datetime.datetime.fromtimestamp(int(time)),
109 subject = subject,
110 repo = repo_name,
111 )
112 )
113
114 # LASTLY, get the date when this tag was actually created
115 args = [
116 'git',
117 'for-each-ref',
118 '--format=%(taggerdate:raw)',
119 'refs/tags/' + tag,
120 ]
121 tag_timestamp, _ = subprocess.Popen(args, stdout=subprocess.PIPE) \
122 .communicate()
123 tag_unixtime, tag_timezone = tag_timestamp.split(None, 1)
124
125 update = FrontPageGit(
126 time = datetime.datetime.fromtimestamp(int(tag_unixtime)),
127 gitweb = gitweb,
128 log = commits,
129 template = '/front_page/git.mako',
130 category = title,
131 tag = tag,
132 icon = icon,
133 )
134 updates.append(update)
135
136 return updates
137
138
139 def add_routes_hook(map, *args, **kwargs):
140 """Hook to inject some of our behavior into the routes configuration."""
141 map.connect('/', controller='frontpage', action='index')
142
143
144 class FrontPagePlugin(PluginBase):
145 def controllers(self):
146 return dict(
147 frontpage = splinext.frontpage.controllers.frontpage.FrontPageController,
148 )
149
150 def template_dirs(self):
151 return [
152 (resource_filename(__name__, 'templates'), Priority.FIRST)
153 ]
154
155 def hooks(self):
156 return [
157 ('routes_mapping', Priority.NORMAL, add_routes_hook),
158 ('frontpage_updates_rss', Priority.NORMAL, rss_hook),
159 ('frontpage_updates_git', Priority.NORMAL, git_hook),
160 ]