Mercurial > hg
annotate hgext/hgcia.py @ 9410:1c83938b6a8e
extensions: load and configure extensions in well-defined phases
Extensions are now loaded with a call-graph like this:
dispatch._dispatch
extensions.loadall
extensions.load
# add foo module to extensions._extensions
extensions.load
# add bar module to extensions._extensions
foo.uisetup(ui)
bar.uisetup(ui)
foo.extsetup()
bar.extsetup()
commands.table.update(foo.cmdtable)
commands.table.update(bar.cmdtable)
hg.repository
foo.reposetup(ui, repo)
bar.reposetup(ui, repo)
The uisetup calls could easily be moved out to dispatch._dispatch, but
have been kept in extensions.loadall since at least TortoiseHg calls
extensions.loadall and expects it to call uisetup.
The extensions.load function called uisetup. It now has an unused ui
argument which has been kept for backwards compatibility.
author | Martin Geisler <mg@lazybytes.net> |
---|---|
date | Sat, 29 Aug 2009 00:29:16 +0200 |
parents | b2f37dbc5952 |
children | 4c041f1ee1b4 |
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: | |
232 ui.debug(_('cia: no user specified')) | |
233 return | |
234 if not cia.project: | |
235 ui.debug(_('cia: no project specified')) | |
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) |