]> andersk Git - jira-zephyrbot.git/blame_incremental - jirabot.py
Workaround for mechanize memory leaks.
[jira-zephyrbot.git] / jirabot.py
... / ...
CommitLineData
1#!/usr/bin/python
2import calendar
3import feedparser
4import formatter
5import htmlentitydefs
6import htmllib
7import mechanize
8import os
9import random
10import string
11import StringIO
12import time
13import traceback
14import urlparse
15import zephyr
16
17zephyr_sender = 'jira'
18zephyr_class = 'andersk-test'
19time_file = 'jirabot.time'
20
21class UnicodeHTMLParser(htmllib.HTMLParser):
22 entitydefs = dict((k, unichr(v)) for (k, v) in htmlentitydefs.name2codepoint.items())
23
24 def convert_charref(self, name):
25 try:
26 n = int(name)
27 except ValueError:
28 return
29 return self.convert_codepoint(n)
30
31 def convert_codepoint(self, codepoint):
32 return unichr(codepoint)
33
34def jira_init():
35 b = mechanize.Browser()
36 b.set_handle_robots(False)
37 b.add_client_certificate("https://idp.mit.edu:9443", "cert.pem", "cert.pem")
38 b.addheaders = [("Accept-Language", "en-us,en;q=0.5"),]
39 return b
40
41def jira_login(b):
42 b.open("https://jira.mit.edu/jira/secure/Dashboard.jspa")
43 try:
44 b.follow_link(text="MIT Touchstone")
45 except mechanize.LinkNotFoundError:
46 return
47 if (urlparse.urlparse(b.geturl())[1] == "jira.mit.edu"):
48 return
49 b.select_form("wayfForm1")
50 b.submit()
51 b.select_form(predicate=lambda f: any(c.name == 'login_certificate'
52 for c in f.controls))
53 b.submit()
54 b.select_form(nr=0)
55 b.submit()
56
57def feed_to_zephyrs(thing, rss, parse):
58 zephyrs = []
59 try:
60 feed = feedparser.parse(rss)
61 for e in feed.entries:
62 global old_time, new_time
63 t = int(calendar.timegm(e.date_parsed))
64 if t <= old_time:
65 continue
66 if t > new_time:
67 new_time = t
68 try:
69 z = parse(e)
70 except:
71 z = zerror("Error parsing " + thing + ":\n" + e.id + "\n" + traceback.format_exc())
72 zephyrs.append((t, z))
73 except:
74 zephyrs.append((0, zerror("Error parsing " + thing + "s feed:\n" + traceback.format_exc())))
75 return zephyrs
76
77def parse_issue(e):
78 issue = urlparse.urlparse(e.id)[2].rsplit('/', 1)[1]
79 url = e.id
80 msg = e.id + "\nThis issue was updated."
81
82 return zephyr.ZNotice(
83 sender=zephyr_sender,
84 auth=False,
85 opcode='auto',
86 cls=zephyr_class,
87 instance=issue,
88 fields=[e.title, msg],
89 )
90
91def parse_comment(e):
92 url = urlparse.urlunsplit(urlparse.urlparse(e.id)[0:3] + (None,None))
93 issue = url.rsplit('/', 1)[1]
94
95 s = StringIO.StringIO()
96 parser = UnicodeHTMLParser(formatter.AbstractFormatter(formatter.DumbWriter(s)))
97 parser.feed(e.summary.rsplit('<table>', 1)[0])
98 parser.close()
99 comment = s.getvalue()
100
101 msg = e.author + " added a comment:\n" + comment.rstrip()
102
103 return zephyr.ZNotice(
104 sender=zephyr_sender,
105 auth=False,
106 opcode='auto',
107 cls=zephyr_class,
108 instance=issue,
109 fields=[e.title, msg],
110 )
111
112def zerror(msg):
113 return zephyr.ZNotice(
114 sender=zephyr_sender,
115 auth=False,
116 opcode='auto',
117 cls=zephyr_class,
118 instance='jira-error',
119 fields=['Jira bot error', msg]
120 )
121
122b = jira_init()
123zephyr.init()
124
125count = 0
126
127while True:
128 time_file_new = time_file + '.' + ''.join(random.sample(string.letters, 8))
129
130 try:
131 os.rename(time_file, time_file_new)
132 except OSError:
133 print "warning: could not acquire timestamp lock"
134 time.sleep(17)
135 continue
136
137 if (count >= 200):
138 b = jira_init()
139 count = 0
140 count += 1
141
142 jira_login(b)
143 b.open("https://jira.mit.edu/jira/sr/jira.issueviews:searchrequest-rss/temp/SearchRequest.xml?&pid=10185&updated%3Aprevious=-1w&sorter/field=updated&sorter/order=DESC&tempMax=1000")
144 issues_rss = b.response().read()
145 b.open("https://jira.mit.edu/jira/sr/jira.issueviews:searchrequest-comments-rss/temp/SearchRequest.xml?&pid=10185&updated%3Aprevious=-1w&sorter/field=updated&sorter/order=DESC&tempMax=1000")
146 comments_rss = b.response().read()
147 b.clear_history()
148
149 old_time = int(open(time_file_new).read())
150 new_time = old_time
151
152 zephyrs = (feed_to_zephyrs('issue', issues_rss, parse_issue) +
153 feed_to_zephyrs('comment', comments_rss, parse_comment))
154 zephyrs.sort(key=lambda tz: tz[0])
155 for (t, z) in zephyrs:
156 z.send()
157
158 open(time_file_new, 'w').write(str(new_time))
159 os.rename(time_file_new, time_file)
160
161 time.sleep(60)
This page took 0.039984 seconds and 5 git commands to generate.