Mercurial > hg
annotate hgext/hgcia.py @ 9471:bccf780f78ed
Merge with crew-stable
author | Martin Geisler <mg@lazybytes.net> |
---|---|
date | Sat, 19 Sep 2009 13:55:18 +0200 |
parents | 4c041f1ee1b4 |
children | 25e572394f5c |
rev | line source |
---|---|
7438 | 1 # Copyright (C) 2007-8 Brendan Cully <brendan@kublai.com> |
2 # Published under the GNU GPL | |
3 | |
8935
f4f0e902b750
extensions: change descriptions for hook-providing extensions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
8894
diff
changeset
|
4 """hooks for integrating with the CIA.vc notification service |
7438 | 5 |
9260
b2f37dbc5952
hgcia: wrap docstrings at 70 characters
Martin Geisler <mg@lazybytes.net>
parents:
9208
diff
changeset
|
6 This is meant to be run as a changegroup or incoming hook. To |
b2f37dbc5952
hgcia: wrap docstrings at 70 characters
Martin Geisler <mg@lazybytes.net>
parents:
9208
diff
changeset
|
7 configure it, set the following options in your hgrc:: |
7438 | 8 |
9208
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
9 [cia] |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
10 # your registered CIA user name |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
11 user = foo |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
12 # the name of the project in CIA |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
13 project = foo |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
14 # the module (subproject) (optional) |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
15 #module = foo |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
16 # Append a diffstat to the log message (optional) |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
17 #diffstat = False |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
18 # Template to use for log messages (optional) |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
19 #template = {desc}\\n{baseurl}/rev/{node}-- {diffstat} |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
20 # Style to use (optional) |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
21 #style = foo |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
22 # The URL of the CIA notification service (optional) |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
23 # You can use mailto: URLs to send by email, eg |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
24 # mailto:cia@cia.vc |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
25 # Make sure to set email.from if you do this. |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
26 #url = http://cia.vc/ |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
27 # print message instead of sending it (optional) |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
28 #test = False |
7438 | 29 |
9208
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
30 [hooks] |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
31 # one of these: |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
32 changegroup.cia = python:hgcia.hook |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
33 #incoming.cia = python:hgcia.hook |
7438 | 34 |
9208
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
35 [web] |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
36 # If you want hyperlinks (optional) |
12d119ae39bc
hgcia: use reST syntax for literal block
Martin Geisler <mg@lazybytes.net>
parents:
9136
diff
changeset
|
37 baseurl = http://server/path/to/repo |
7438 | 38 """ |
39 | |
40 from mercurial.i18n import _ | |
41 from mercurial.node import * | |
42 from mercurial import cmdutil, patch, templater, util, mail | |
43 import email.Parser | |
44 | |
45 import xmlrpclib | |
46 from xml.sax import saxutils | |
47 | |
48 socket_timeout = 30 # seconds | |
49 try: | |
50 # set a timeout for the socket so you don't have to wait so looooong | |
51 # when cia.vc is having problems. requires python >= 2.3: | |
52 import socket | |
53 socket.setdefaulttimeout(socket_timeout) | |
54 except: | |
55 pass | |
56 | |
57 HGCIA_VERSION = '0.1' | |
58 HGCIA_URL = 'http://hg.kublai.com/mercurial/hgcia' | |
59 | |
60 | |
61 class ciamsg(object): | |
62 """ A CIA message """ | |
63 def __init__(self, cia, ctx): | |
64 self.cia = cia | |
65 self.ctx = ctx | |
66 self.url = self.cia.url | |
67 | |
68 def fileelem(self, path, uri, action): | |
69 if uri: | |
70 uri = ' uri=%s' % saxutils.quoteattr(uri) | |
71 return '<file%s action=%s>%s</file>' % ( | |
72 uri, saxutils.quoteattr(action), saxutils.escape(path)) | |
73 | |
74 def fileelems(self): | |
75 n = self.ctx.node() | |
76 f = self.cia.repo.status(self.ctx.parents()[0].node(), n) | |
77 url = self.url or '' | |
78 elems = [] | |
79 for path in f[0]: | |
80 uri = '%s/diff/%s/%s' % (url, short(n), path) | |
81 elems.append(self.fileelem(path, url and uri, 'modify')) | |
82 for path in f[1]: | |
83 # TODO: copy/rename ? | |
84 uri = '%s/file/%s/%s' % (url, short(n), path) | |
85 elems.append(self.fileelem(path, url and uri, 'add')) | |
86 for path in f[2]: | |
87 elems.append(self.fileelem(path, '', 'remove')) | |
88 | |
89 return '\n'.join(elems) | |
90 | |
91 def sourceelem(self, project, module=None, branch=None): | |
92 msg = ['<source>', '<project>%s</project>' % saxutils.escape(project)] | |
93 if module: | |
94 msg.append('<module>%s</module>' % saxutils.escape(module)) | |
95 if branch: | |
96 msg.append('<branch>%s</branch>' % saxutils.escape(branch)) | |
97 msg.append('</source>') | |
98 | |
99 return '\n'.join(msg) | |
100 | |
101 def diffstat(self): | |
8778
c5f36402daad
use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
8541
diff
changeset
|
102 class patchbuf(object): |
7438 | 103 def __init__(self): |
104 self.lines = [] | |
105 # diffstat is stupid | |
106 self.name = 'cia' | |
107 def write(self, data): | |
108 self.lines.append(data) | |
109 def close(self): | |
110 pass | |
111 | |
112 n = self.ctx.node() | |
113 pbuf = patchbuf() | |
114 patch.export(self.cia.repo, [n], fp=pbuf) | |
115 return patch.diffstat(pbuf.lines) or '' | |
116 | |
117 def logmsg(self): | |
118 diffstat = self.cia.diffstat and self.diffstat() or '' | |
119 self.cia.ui.pushbuffer() | |
120 self.cia.templater.show(self.ctx, changes=self.ctx.changeset(), | |
121 url=self.cia.url, diffstat=diffstat) | |
122 return self.cia.ui.popbuffer() | |
123 | |
124 def xml(self): | |
125 n = short(self.ctx.node()) | |
126 src = self.sourceelem(self.cia.project, module=self.cia.module, | |
127 branch=self.ctx.branch()) | |
128 # unix timestamp | |
129 dt = self.ctx.date() | |
130 timestamp = dt[0] | |
131 | |
132 author = saxutils.escape(self.ctx.user()) | |
133 rev = '%d:%s' % (self.ctx.rev(), n) | |
134 log = saxutils.escape(self.logmsg()) | |
135 | |
136 url = self.url and '<url>%s/rev/%s</url>' % (saxutils.escape(self.url), | |
137 n) or '' | |
138 | |
139 msg = """ | |
140 <message> | |
141 <generator> | |
142 <name>Mercurial (hgcia)</name> | |
143 <version>%s</version> | |
144 <url>%s</url> | |
145 <user>%s</user> | |
146 </generator> | |
147 %s | |
148 <body> | |
149 <commit> | |
150 <author>%s</author> | |
151 <version>%s</version> | |
152 <log>%s</log> | |
153 %s | |
154 <files>%s</files> | |
155 </commit> | |
156 </body> | |
157 <timestamp>%d</timestamp> | |
158 </message> | |
159 """ % \ | |
160 (HGCIA_VERSION, saxutils.escape(HGCIA_URL), | |
161 saxutils.escape(self.cia.user), src, author, rev, log, url, | |
162 self.fileelems(), timestamp) | |
163 | |
164 return msg | |
165 | |
166 | |
167 class hgcia(object): | |
168 """ CIA notification class """ | |
169 | |
170 deftemplate = '{desc}' | |
171 dstemplate = '{desc}\n-- \n{diffstat}' | |
172 | |
173 def __init__(self, ui, repo): | |
174 self.ui = ui | |
175 self.repo = repo | |
176 | |
177 self.ciaurl = self.ui.config('cia', 'url', 'http://cia.vc') | |
178 self.user = self.ui.config('cia', 'user') | |
179 self.project = self.ui.config('cia', 'project') | |
180 self.module = self.ui.config('cia', 'module') | |
181 self.diffstat = self.ui.configbool('cia', 'diffstat') | |
182 self.emailfrom = self.ui.config('email', 'from') | |
183 self.dryrun = self.ui.configbool('cia', 'test') | |
184 self.url = self.ui.config('web', 'baseurl') | |
185 | |
186 style = self.ui.config('cia', 'style') | |
187 template = self.ui.config('cia', 'template') | |
188 if not template: | |
189 template = self.diffstat and self.dstemplate or self.deftemplate | |
190 template = templater.parsestring(template, quoted=False) | |
7762
fece056bf240
add --git option to commands supporting --patch (log, incoming, history, tip)
Jim Correia <jim.correia@pobox.com>
parents:
7438
diff
changeset
|
191 t = cmdutil.changeset_templater(self.ui, self.repo, False, None, |
fece056bf240
add --git option to commands supporting --patch (log, incoming, history, tip)
Jim Correia <jim.correia@pobox.com>
parents:
7438
diff
changeset
|
192 style, False) |
7438 | 193 t.use_template(template) |
194 self.templater = t | |
195 | |
196 def sendrpc(self, msg): | |
197 srv = xmlrpclib.Server(self.ciaurl) | |
198 srv.hub.deliver(msg) | |
199 | |
200 def sendemail(self, address, data): | |
201 p = email.Parser.Parser() | |
202 msg = p.parsestr(data) | |
203 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2") | |
204 msg['To'] = address | |
205 msg['From'] = self.emailfrom | |
206 msg['Subject'] = 'DeliverXML' | |
207 msg['Content-type'] = 'text/xml' | |
9136
31177742f54a
for calls expecting bool args, pass bool instead of int
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
9062
diff
changeset
|
208 msgtext = msg.as_string() |
7438 | 209 |
210 self.ui.status(_('hgcia: sending update to %s\n') % address) | |
211 mail.sendmail(self.ui, util.email(self.emailfrom), | |
212 [address], msgtext) | |
213 | |
214 | |
215 def hook(ui, repo, hooktype, node=None, url=None, **kwargs): | |
216 """ send CIA notification """ | |
217 def sendmsg(cia, ctx): | |
218 msg = ciamsg(cia, ctx).xml() | |
219 if cia.dryrun: | |
220 ui.write(msg) | |
221 elif cia.ciaurl.startswith('mailto:'): | |
222 if not cia.emailfrom: | |
223 raise util.Abort(_('email.from must be defined when ' | |
224 'sending by email')) | |
225 cia.sendemail(cia.ciaurl[7:], msg) | |
226 else: | |
227 cia.sendrpc(msg) | |
228 | |
229 n = bin(node) | |
230 cia = hgcia(ui, repo) | |
231 if not cia.user: | |
9467
4c041f1ee1b4
do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents:
9260
diff
changeset
|
232 ui.debug('cia: no user specified') |
7438 | 233 return |
234 if not cia.project: | |
9467
4c041f1ee1b4
do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents:
9260
diff
changeset
|
235 ui.debug('cia: no project specified') |
7438 | 236 return |
237 if hooktype == 'changegroup': | |
238 start = repo.changelog.rev(n) | |
239 end = len(repo.changelog) | |
240 for rev in xrange(start, end): | |
241 n = repo.changelog.node(rev) | |
242 ctx = repo.changectx(n) | |
243 sendmsg(cia, ctx) | |
244 else: | |
245 ctx = repo.changectx(n) | |
246 sendmsg(cia, ctx) |