##// END OF EJS Templates
bugzilla: localise all MySQL direct access inside access class....
Jim Hague -
r13800:c2ef8159 default
parent child Browse files
Show More
@@ -145,28 +145,77 b' from mercurial.node import short'
145 from mercurial import cmdutil, templater, util
145 from mercurial import cmdutil, templater, util
146 import re, time
146 import re, time
147
147
148 MySQLdb = None
148 class bzaccess(object):
149
149 '''Base class for access to Bugzilla.'''
150 def buglist(ids):
151 return '(' + ','.join(map(str, ids)) + ')'
152
153 class bugzilla_2_16(object):
154 '''support for bugzilla version 2.16.'''
155
150
156 def __init__(self, ui):
151 def __init__(self, ui):
157 self.ui = ui
152 self.ui = ui
153 usermap = self.ui.config('bugzilla', 'usermap')
154 if usermap:
155 self.ui.readconfig(usermap, sections=['usermap'])
156
157 def map_committer(self, user):
158 '''map name of committer to Bugzilla user name.'''
159 for committer, bzuser in self.ui.configitems('usermap'):
160 if committer.lower() == user.lower():
161 return bzuser
162 return user
163
164 # Methods to be implemented by access classes.
165 def filter_real_bug_ids(self, ids):
166 '''remove bug IDs that do not exist in Bugzilla from set.'''
167 pass
168
169 def filter_cset_known_bug_ids(self, node, ids):
170 '''remove bug IDs where node occurs in comment text from set.'''
171 pass
172
173 def add_comment(self, bugid, text, committer):
174 '''add comment to bug.
175
176 If possible add the comment as being from the committer of
177 the changeset. Otherwise use the default Bugzilla user.
178 '''
179 pass
180
181 def notify(self, ids, committer):
182 '''Force sending of Bugzilla notification emails.'''
183 pass
184
185 # Bugzilla via direct access to MySQL database.
186 class bzmysql(bzaccess):
187 '''Support for direct MySQL access to Bugzilla.
188
189 The earliest Bugzilla version this is tested with is version 2.16.
190 '''
191
192 @staticmethod
193 def sql_buglist(ids):
194 '''return SQL-friendly list of bug ids'''
195 return '(' + ','.join(map(str, ids)) + ')'
196
197 _MySQLdb = None
198
199 def __init__(self, ui):
200 try:
201 import MySQLdb as mysql
202 bzmysql._MySQLdb = mysql
203 except ImportError, err:
204 raise util.Abort(_('python mysql support not available: %s') % err)
205
206 bzaccess.__init__(self, ui)
207
158 host = self.ui.config('bugzilla', 'host', 'localhost')
208 host = self.ui.config('bugzilla', 'host', 'localhost')
159 user = self.ui.config('bugzilla', 'user', 'bugs')
209 user = self.ui.config('bugzilla', 'user', 'bugs')
160 passwd = self.ui.config('bugzilla', 'password')
210 passwd = self.ui.config('bugzilla', 'password')
161 db = self.ui.config('bugzilla', 'db', 'bugs')
211 db = self.ui.config('bugzilla', 'db', 'bugs')
162 timeout = int(self.ui.config('bugzilla', 'timeout', 5))
212 timeout = int(self.ui.config('bugzilla', 'timeout', 5))
163 usermap = self.ui.config('bugzilla', 'usermap')
164 if usermap:
165 self.ui.readconfig(usermap, sections=['usermap'])
166 self.ui.note(_('connecting to %s:%s as %s, password %s\n') %
213 self.ui.note(_('connecting to %s:%s as %s, password %s\n') %
167 (host, db, user, '*' * len(passwd)))
214 (host, db, user, '*' * len(passwd)))
168 self.conn = MySQLdb.connect(host=host, user=user, passwd=passwd,
215 self.conn = bzmysql._MySQLdb.connect(host=host,
169 db=db, connect_timeout=timeout)
216 user=user, passwd=passwd,
217 db=db,
218 connect_timeout=timeout)
170 self.cursor = self.conn.cursor()
219 self.cursor = self.conn.cursor()
171 self.longdesc_id = self.get_longdesc_id()
220 self.longdesc_id = self.get_longdesc_id()
172 self.user_ids = {}
221 self.user_ids = {}
@@ -177,7 +226,7 b' class bugzilla_2_16(object):'
177 self.ui.note(_('query: %s %s\n') % (args, kwargs))
226 self.ui.note(_('query: %s %s\n') % (args, kwargs))
178 try:
227 try:
179 self.cursor.execute(*args, **kwargs)
228 self.cursor.execute(*args, **kwargs)
180 except MySQLdb.MySQLError:
229 except bzmysql._MySQLdb.MySQLError:
181 self.ui.note(_('failed query: %s %s\n') % (args, kwargs))
230 self.ui.note(_('failed query: %s %s\n') % (args, kwargs))
182 raise
231 raise
183
232
@@ -191,7 +240,8 b' class bugzilla_2_16(object):'
191
240
192 def filter_real_bug_ids(self, ids):
241 def filter_real_bug_ids(self, ids):
193 '''filter not-existing bug ids from set.'''
242 '''filter not-existing bug ids from set.'''
194 self.run('select bug_id from bugs where bug_id in %s' % buglist(ids))
243 self.run('select bug_id from bugs where bug_id in %s' %
244 bzmysql.sql_buglist(ids))
195 return set([c[0] for c in self.cursor.fetchall()])
245 return set([c[0] for c in self.cursor.fetchall()])
196
246
197 def filter_cset_known_bug_ids(self, node, ids):
247 def filter_cset_known_bug_ids(self, node, ids):
@@ -199,7 +249,7 b' class bugzilla_2_16(object):'
199
249
200 self.run('''select bug_id from longdescs where
250 self.run('''select bug_id from longdescs where
201 bug_id in %s and thetext like "%%%s%%"''' %
251 bug_id in %s and thetext like "%%%s%%"''' %
202 (buglist(ids), short(node)))
252 (bzmysql.sql_buglist(ids), short(node)))
203 for (id,) in self.cursor.fetchall():
253 for (id,) in self.cursor.fetchall():
204 self.ui.status(_('bug %d already knows about changeset %s\n') %
254 self.ui.status(_('bug %d already knows about changeset %s\n') %
205 (id, short(node)))
255 (id, short(node)))
@@ -250,13 +300,6 b' class bugzilla_2_16(object):'
250 self.user_ids[user] = userid
300 self.user_ids[user] = userid
251 return userid
301 return userid
252
302
253 def map_committer(self, user):
254 '''map name of committer to bugzilla user name.'''
255 for committer, bzuser in self.ui.configitems('usermap'):
256 if committer.lower() == user.lower():
257 return bzuser
258 return user
259
260 def get_bugzilla_user(self, committer):
303 def get_bugzilla_user(self, committer):
261 '''see if committer is a registered bugzilla user. Return
304 '''see if committer is a registered bugzilla user. Return
262 bugzilla username and userid if so. If not, return default
305 bugzilla username and userid if so. If not, return default
@@ -291,19 +334,19 b' class bugzilla_2_16(object):'
291 (bugid, userid, now, self.longdesc_id))
334 (bugid, userid, now, self.longdesc_id))
292 self.conn.commit()
335 self.conn.commit()
293
336
294 class bugzilla_2_18(bugzilla_2_16):
337 class bzmysql_2_18(bzmysql):
295 '''support for bugzilla 2.18 series.'''
338 '''support for bugzilla 2.18 series.'''
296
339
297 def __init__(self, ui):
340 def __init__(self, ui):
298 bugzilla_2_16.__init__(self, ui)
341 bzmysql.__init__(self, ui)
299 self.default_notify = \
342 self.default_notify = \
300 "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s"
343 "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s"
301
344
302 class bugzilla_3_0(bugzilla_2_18):
345 class bzmysql_3_0(bzmysql_2_18):
303 '''support for bugzilla 3.0 series.'''
346 '''support for bugzilla 3.0 series.'''
304
347
305 def __init__(self, ui):
348 def __init__(self, ui):
306 bugzilla_2_18.__init__(self, ui)
349 bzmysql_2_18.__init__(self, ui)
307
350
308 def get_longdesc_id(self):
351 def get_longdesc_id(self):
309 '''get identity of longdesc field'''
352 '''get identity of longdesc field'''
@@ -317,9 +360,9 b' class bugzilla(object):'
317 # supported versions of bugzilla. different versions have
360 # supported versions of bugzilla. different versions have
318 # different schemas.
361 # different schemas.
319 _versions = {
362 _versions = {
320 '2.16': bugzilla_2_16,
363 '2.16': bzmysql,
321 '2.18': bugzilla_2_18,
364 '2.18': bzmysql_2_18,
322 '3.0': bugzilla_3_0
365 '3.0': bzmysql_3_0
323 }
366 }
324
367
325 _default_bug_re = (r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*'
368 _default_bug_re = (r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*'
@@ -419,13 +462,6 b' def hook(ui, repo, hooktype, node=None, '
419 '''add comment to bugzilla for each changeset that refers to a
462 '''add comment to bugzilla for each changeset that refers to a
420 bugzilla bug id. only add a comment once per bug, so same change
463 bugzilla bug id. only add a comment once per bug, so same change
421 seen multiple times does not fill bug with duplicate data.'''
464 seen multiple times does not fill bug with duplicate data.'''
422 try:
423 import MySQLdb as mysql
424 global MySQLdb
425 MySQLdb = mysql
426 except ImportError, err:
427 raise util.Abort(_('python mysql support not available: %s') % err)
428
429 if node is None:
465 if node is None:
430 raise util.Abort(_('hook type %s does not pass a changeset id') %
466 raise util.Abort(_('hook type %s does not pass a changeset id') %
431 hooktype)
467 hooktype)
@@ -437,6 +473,6 b' def hook(ui, repo, hooktype, node=None, '
437 for id in ids:
473 for id in ids:
438 bz.update(id, ctx)
474 bz.update(id, ctx)
439 bz.notify(ids, util.email(ctx.user()))
475 bz.notify(ids, util.email(ctx.user()))
440 except MySQLdb.MySQLError, err:
476 except Exception, e:
441 raise util.Abort(_('database error: %s') % err.args[1])
477 raise util.Abort(_('Bugzilla error: %s') % e)
442
478
General Comments 0
You need to be logged in to leave comments. Login now