##// END OF EJS Templates
hgcia: fix diffstat support
Matt Mackall -
r15776:55a85a55 default
parent child Browse files
Show More
@@ -1,279 +1,279 b''
1 1 # Copyright (C) 2007-8 Brendan Cully <brendan@kublai.com>
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6 """hooks for integrating with the CIA.vc notification service
7 7
8 8 This is meant to be run as a changegroup or incoming hook. To
9 9 configure it, set the following options in your hgrc::
10 10
11 11 [cia]
12 12 # your registered CIA user name
13 13 user = foo
14 14 # the name of the project in CIA
15 15 project = foo
16 16 # the module (subproject) (optional)
17 17 #module = foo
18 18 # Append a diffstat to the log message (optional)
19 19 #diffstat = False
20 20 # Template to use for log messages (optional)
21 21 #template = {desc}\\n{baseurl}{webroot}/rev/{node}-- {diffstat}
22 22 # Style to use (optional)
23 23 #style = foo
24 24 # The URL of the CIA notification service (optional)
25 25 # You can use mailto: URLs to send by email, eg
26 26 # mailto:cia@cia.vc
27 27 # Make sure to set email.from if you do this.
28 28 #url = http://cia.vc/
29 29 # print message instead of sending it (optional)
30 30 #test = False
31 31 # number of slashes to strip for url paths
32 32 #strip = 0
33 33
34 34 [hooks]
35 35 # one of these:
36 36 changegroup.cia = python:hgcia.hook
37 37 #incoming.cia = python:hgcia.hook
38 38
39 39 [web]
40 40 # If you want hyperlinks (optional)
41 41 baseurl = http://server/path/to/repo
42 42 """
43 43
44 44 from mercurial.i18n import _
45 45 from mercurial.node import bin, short
46 46 from mercurial import cmdutil, patch, templater, util, mail
47 47 import email.Parser
48 48
49 49 import xmlrpclib
50 50 from xml.sax import saxutils
51 51
52 52 socket_timeout = 30 # seconds
53 53 try:
54 54 # set a timeout for the socket so you don't have to wait so looooong
55 55 # when cia.vc is having problems. requires python >= 2.3:
56 56 import socket
57 57 socket.setdefaulttimeout(socket_timeout)
58 58 except:
59 59 pass
60 60
61 61 HGCIA_VERSION = '0.1'
62 62 HGCIA_URL = 'http://hg.kublai.com/mercurial/hgcia'
63 63
64 64
65 65 class ciamsg(object):
66 66 """ A CIA message """
67 67 def __init__(self, cia, ctx):
68 68 self.cia = cia
69 69 self.ctx = ctx
70 70 self.url = self.cia.url
71 71 if self.url:
72 72 self.url += self.cia.root
73 73
74 74 def fileelem(self, path, uri, action):
75 75 if uri:
76 76 uri = ' uri=%s' % saxutils.quoteattr(uri)
77 77 return '<file%s action=%s>%s</file>' % (
78 78 uri, saxutils.quoteattr(action), saxutils.escape(path))
79 79
80 80 def fileelems(self):
81 81 n = self.ctx.node()
82 82 f = self.cia.repo.status(self.ctx.p1().node(), n)
83 83 url = self.url or ''
84 84 if url and url[-1] == '/':
85 85 url = url[:-1]
86 86 elems = []
87 87 for path in f[0]:
88 88 uri = '%s/diff/%s/%s' % (url, short(n), path)
89 89 elems.append(self.fileelem(path, url and uri, 'modify'))
90 90 for path in f[1]:
91 91 # TODO: copy/rename ?
92 92 uri = '%s/file/%s/%s' % (url, short(n), path)
93 93 elems.append(self.fileelem(path, url and uri, 'add'))
94 94 for path in f[2]:
95 95 elems.append(self.fileelem(path, '', 'remove'))
96 96
97 97 return '\n'.join(elems)
98 98
99 99 def sourceelem(self, project, module=None, branch=None):
100 100 msg = ['<source>', '<project>%s</project>' % saxutils.escape(project)]
101 101 if module:
102 102 msg.append('<module>%s</module>' % saxutils.escape(module))
103 103 if branch:
104 104 msg.append('<branch>%s</branch>' % saxutils.escape(branch))
105 105 msg.append('</source>')
106 106
107 107 return '\n'.join(msg)
108 108
109 109 def diffstat(self):
110 110 class patchbuf(object):
111 111 def __init__(self):
112 112 self.lines = []
113 113 # diffstat is stupid
114 114 self.name = 'cia'
115 115 def write(self, data):
116 self.lines.append(data)
116 self.lines += data.splitlines(True)
117 117 def close(self):
118 118 pass
119 119
120 120 n = self.ctx.node()
121 121 pbuf = patchbuf()
122 122 cmdutil.export(self.cia.repo, [n], fp=pbuf)
123 123 return patch.diffstat(pbuf.lines) or ''
124 124
125 125 def logmsg(self):
126 126 diffstat = self.cia.diffstat and self.diffstat() or ''
127 127 self.cia.ui.pushbuffer()
128 128 self.cia.templater.show(self.ctx, changes=self.ctx.changeset(),
129 129 baseurl=self.cia.ui.config('web', 'baseurl'),
130 130 url=self.url, diffstat=diffstat,
131 131 webroot=self.cia.root)
132 132 return self.cia.ui.popbuffer()
133 133
134 134 def xml(self):
135 135 n = short(self.ctx.node())
136 136 src = self.sourceelem(self.cia.project, module=self.cia.module,
137 137 branch=self.ctx.branch())
138 138 # unix timestamp
139 139 dt = self.ctx.date()
140 140 timestamp = dt[0]
141 141
142 142 author = saxutils.escape(self.ctx.user())
143 143 rev = '%d:%s' % (self.ctx.rev(), n)
144 144 log = saxutils.escape(self.logmsg())
145 145
146 146 url = self.url
147 147 if url and url[-1] == '/':
148 148 url = url[:-1]
149 149 url = url and '<url>%s/rev/%s</url>' % (saxutils.escape(url), n) or ''
150 150
151 151 msg = """
152 152 <message>
153 153 <generator>
154 154 <name>Mercurial (hgcia)</name>
155 155 <version>%s</version>
156 156 <url>%s</url>
157 157 <user>%s</user>
158 158 </generator>
159 159 %s
160 160 <body>
161 161 <commit>
162 162 <author>%s</author>
163 163 <version>%s</version>
164 164 <log>%s</log>
165 165 %s
166 166 <files>%s</files>
167 167 </commit>
168 168 </body>
169 169 <timestamp>%d</timestamp>
170 170 </message>
171 171 """ % \
172 172 (HGCIA_VERSION, saxutils.escape(HGCIA_URL),
173 173 saxutils.escape(self.cia.user), src, author, rev, log, url,
174 174 self.fileelems(), timestamp)
175 175
176 176 return msg
177 177
178 178
179 179 class hgcia(object):
180 180 """ CIA notification class """
181 181
182 182 deftemplate = '{desc}'
183 183 dstemplate = '{desc}\n-- \n{diffstat}'
184 184
185 185 def __init__(self, ui, repo):
186 186 self.ui = ui
187 187 self.repo = repo
188 188
189 189 self.ciaurl = self.ui.config('cia', 'url', 'http://cia.vc')
190 190 self.user = self.ui.config('cia', 'user')
191 191 self.project = self.ui.config('cia', 'project')
192 192 self.module = self.ui.config('cia', 'module')
193 193 self.diffstat = self.ui.configbool('cia', 'diffstat')
194 194 self.emailfrom = self.ui.config('email', 'from')
195 195 self.dryrun = self.ui.configbool('cia', 'test')
196 196 self.url = self.ui.config('web', 'baseurl')
197 197 # Default to -1 for backward compatibility
198 198 self.stripcount = int(self.ui.config('cia', 'strip', -1))
199 199 self.root = self.strip(self.repo.root)
200 200
201 201 style = self.ui.config('cia', 'style')
202 202 template = self.ui.config('cia', 'template')
203 203 if not template:
204 204 template = self.diffstat and self.dstemplate or self.deftemplate
205 205 template = templater.parsestring(template, quoted=False)
206 206 t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
207 207 style, False)
208 208 t.use_template(template)
209 209 self.templater = t
210 210
211 211 def strip(self, path):
212 212 '''strip leading slashes from local path, turn into web-safe path.'''
213 213
214 214 path = util.pconvert(path)
215 215 count = self.stripcount
216 216 if count < 0:
217 217 return ''
218 218 while count > 0:
219 219 c = path.find('/')
220 220 if c == -1:
221 221 break
222 222 path = path[c + 1:]
223 223 count -= 1
224 224 return path
225 225
226 226 def sendrpc(self, msg):
227 227 srv = xmlrpclib.Server(self.ciaurl)
228 228 res = srv.hub.deliver(msg)
229 229 if res is not True and res != 'queued.':
230 230 raise util.Abort(_('%s returned an error: %s') %
231 231 (self.ciaurl, res))
232 232
233 233 def sendemail(self, address, data):
234 234 p = email.Parser.Parser()
235 235 msg = p.parsestr(data)
236 236 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
237 237 msg['To'] = address
238 238 msg['From'] = self.emailfrom
239 239 msg['Subject'] = 'DeliverXML'
240 240 msg['Content-type'] = 'text/xml'
241 241 msgtext = msg.as_string()
242 242
243 243 self.ui.status(_('hgcia: sending update to %s\n') % address)
244 244 mail.sendmail(self.ui, util.email(self.emailfrom),
245 245 [address], msgtext)
246 246
247 247
248 248 def hook(ui, repo, hooktype, node=None, url=None, **kwargs):
249 249 """ send CIA notification """
250 250 def sendmsg(cia, ctx):
251 251 msg = ciamsg(cia, ctx).xml()
252 252 if cia.dryrun:
253 253 ui.write(msg)
254 254 elif cia.ciaurl.startswith('mailto:'):
255 255 if not cia.emailfrom:
256 256 raise util.Abort(_('email.from must be defined when '
257 257 'sending by email'))
258 258 cia.sendemail(cia.ciaurl[7:], msg)
259 259 else:
260 260 cia.sendrpc(msg)
261 261
262 262 n = bin(node)
263 263 cia = hgcia(ui, repo)
264 264 if not cia.user:
265 265 ui.debug('cia: no user specified')
266 266 return
267 267 if not cia.project:
268 268 ui.debug('cia: no project specified')
269 269 return
270 270 if hooktype == 'changegroup':
271 271 start = repo.changelog.rev(n)
272 272 end = len(repo.changelog)
273 273 for rev in xrange(start, end):
274 274 n = repo.changelog.node(rev)
275 275 ctx = repo.changectx(n)
276 276 sendmsg(cia, ctx)
277 277 else:
278 278 ctx = repo.changectx(n)
279 279 sendmsg(cia, ctx)
General Comments 0
You need to be logged in to leave comments. Login now