2154f6e4176b02e87b76bf1964c93a03755fe3e8
1 from collections
import namedtuple
3 from pkg_resources
import resource_filename
9 from spline
.lib
import helpers
10 from spline
.lib
.plugin
import PluginBase
, PluginLink
, Priority
12 import splinext
.frontpage
.controllers
.frontpage
14 class FrontPageUpdate(object):
15 """Base class ('interface') for an updated thing that may appear on the
18 Subclasses should implement the `time` and `template` properties.
23 RSS_SUMMARY_LENGTH
= 1000
25 FrontPageRSS
= namedtuple('FrontPageRSS',
26 ['time', 'entry', 'template', 'category', 'content', 'icon'])
28 def rss_hook(limit
, url
, title
=None, icon
=None):
29 """Front page handler for news feeds."""
30 feed
= feedparser
.parse(url
)
33 title
= feed
.feed
.title
36 for entry
in feed
.entries
[:limit
]:
37 # Grab a date -- Atom has published, RSS usually just has updated.
38 # Both come out as time tuples, which datetime.datetime() can read
40 timestamp_tuple
= entry
.published_parsed
41 except AttributeError:
42 timestamp_tuple
= entry
.updated_parsed
43 timestamp
= datetime
.datetime(*timestamp_tuple
[:6])
45 # Try to find something to show! Default to the summary, if there is
46 # one, or try to generate one otherwise
48 if 'summary' in entry
:
49 # If there be a summary, cheerfully trust that it's actually a
51 content
= entry
.summary
52 elif 'content' in entry
:
53 # Full content is way too much, especially for my giant blog posts.
54 # Cut this down to some arbitrary number of characters, then feed
55 # it to lxml.html to fix tag nesting
56 broken_html
= entry
.content
[0].value
[:RSS_SUMMARY_LENGTH
]
57 fragment
= lxml
.html
.fromstring(broken_html
)
59 # Insert an ellipsis at the end of the last node with text
62 # Need to find the last node with a tail, OR the last node with
64 for node
in fragment
.iter():
72 if last_text_node
is not None:
73 last_text_node
.text
+= '...'
74 if last_tail_node
is not None:
75 last_tail_node
.tail
+= '...'
78 content
= lxml
.html
.tostring(fragment
)
80 content
= helpers
.literal(content
)
82 update
= FrontPageRSS(
85 template
= '/front_page/rss.mako',
90 updates
.append(update
)
95 FrontPageGit
= namedtuple('FrontPageGit',
96 ['time', 'gitweb', 'log', 'tag', 'template', 'category', 'icon'])
97 FrontPageGitCommit
= namedtuple('FrontPageGitCommit',
98 ['hash', 'author', 'time', 'subject', 'repo'])
100 def git_hook(limit
, title
, gitweb
, repo_paths
, repo_names
,
101 tag_pattern
=None, icon
=None):
103 """Front page handler for repository history."""
104 # Repo stuff can be space-delimited lists...
105 repo_paths
= repo_paths
.split()
106 repo_names
= repo_names
.split()
108 # Fetch the main repo's git tags
111 '--git-dir=' + repo_paths
[0],
115 args
.append(tag_pattern
)
117 proc
= subprocess
.Popen(args
, stdout
=subprocess
.PIPE
)
118 git_output
, _
= proc
.communicate()
119 tags
= git_output
.strip().split('\n')
121 # Tags come out in alphabetical order, which means earliest first. Reverse
122 # it to make the slicing easier
124 # Only history from tag to tag is actually interesting, so get the most
125 # recent $limit tags but skip the earliest
126 interesting_tags
= tags
[:-1][:limit
]
129 for tag
, since_tag
in zip(interesting_tags
, tags
[1:]):
132 for repo_path
, repo_name
in zip(repo_paths
, repo_names
):
133 # Grab an easily-parsed history: fields delimited by nulls.
134 # Hash, author's name, commit timestamp, subject.
137 '--git-dir=' + repo_path
,
139 '--pretty=%h%x00%an%x00%at%x00%s',
140 "{0}..{1}".format(since_tag
, tag
),
142 proc
= subprocess
.Popen(git_log_args
, stdout
=subprocess
.PIPE
)
143 for line
in proc
.stdout
:
144 hash, author
, time
, subject
= line
.strip().split('\x00')
149 time
= datetime
.datetime
.fromtimestamp(int(time
)),
155 # LASTLY, get the date when this tag was actually created
159 '--format=%(taggerdate:raw)',
162 tag_timestamp
, _
= subprocess
.Popen(args
, stdout
=subprocess
.PIPE
) \
164 tag_unixtime
, tag_timezone
= tag_timestamp
.split(None, 1)
166 update
= FrontPageGit(
167 time
= datetime
.datetime
.fromtimestamp(int(tag_unixtime
)),
170 template
= '/front_page/git.mako',
175 updates
.append(update
)
180 def add_routes_hook(map, *args
, **kwargs
):
181 """Hook to inject some of our behavior into the routes configuration."""
182 map.connect('/', controller
='frontpage', action
='index')
185 class FrontPagePlugin(PluginBase
):
186 def controllers(self
):
188 frontpage
= splinext
.frontpage
.controllers
.frontpage
.FrontPageController
,
191 def template_dirs(self
):
193 (resource_filename(__name__
, 'templates'), Priority
.FIRST
)
198 ('routes_mapping', Priority
.NORMAL
, add_routes_hook
),
199 ('frontpage_updates_rss', Priority
.NORMAL
, rss_hook
),
200 ('frontpage_updates_git', Priority
.NORMAL
, git_hook
),