--- a/hgext/bugzilla.py Wed Mar 30 09:49:45 2011 +0100
+++ b/hgext/bugzilla.py Wed Mar 30 09:49:45 2011 +0100
@@ -145,28 +145,77 @@
from mercurial import cmdutil, templater, util
import re, time
-MySQLdb = None
-
-def buglist(ids):
- return '(' + ','.join(map(str, ids)) + ')'
-
-class bugzilla_2_16(object):
- '''support for bugzilla version 2.16.'''
+class bzaccess(object):
+ '''Base class for access to Bugzilla.'''
def __init__(self, ui):
self.ui = ui
+ usermap = self.ui.config('bugzilla', 'usermap')
+ if usermap:
+ self.ui.readconfig(usermap, sections=['usermap'])
+
+ def map_committer(self, user):
+ '''map name of committer to Bugzilla user name.'''
+ for committer, bzuser in self.ui.configitems('usermap'):
+ if committer.lower() == user.lower():
+ return bzuser
+ return user
+
+ # Methods to be implemented by access classes.
+ def filter_real_bug_ids(self, ids):
+ '''remove bug IDs that do not exist in Bugzilla from set.'''
+ pass
+
+ def filter_cset_known_bug_ids(self, node, ids):
+ '''remove bug IDs where node occurs in comment text from set.'''
+ pass
+
+ def add_comment(self, bugid, text, committer):
+ '''add comment to bug.
+
+ If possible add the comment as being from the committer of
+ the changeset. Otherwise use the default Bugzilla user.
+ '''
+ pass
+
+ def notify(self, ids, committer):
+ '''Force sending of Bugzilla notification emails.'''
+ pass
+
+# Bugzilla via direct access to MySQL database.
+class bzmysql(bzaccess):
+ '''Support for direct MySQL access to Bugzilla.
+
+ The earliest Bugzilla version this is tested with is version 2.16.
+ '''
+
+ @staticmethod
+ def sql_buglist(ids):
+ '''return SQL-friendly list of bug ids'''
+ return '(' + ','.join(map(str, ids)) + ')'
+
+ _MySQLdb = None
+
+ def __init__(self, ui):
+ try:
+ import MySQLdb as mysql
+ bzmysql._MySQLdb = mysql
+ except ImportError, err:
+ raise util.Abort(_('python mysql support not available: %s') % err)
+
+ bzaccess.__init__(self, ui)
+
host = self.ui.config('bugzilla', 'host', 'localhost')
user = self.ui.config('bugzilla', 'user', 'bugs')
passwd = self.ui.config('bugzilla', 'password')
db = self.ui.config('bugzilla', 'db', 'bugs')
timeout = int(self.ui.config('bugzilla', 'timeout', 5))
- usermap = self.ui.config('bugzilla', 'usermap')
- if usermap:
- self.ui.readconfig(usermap, sections=['usermap'])
self.ui.note(_('connecting to %s:%s as %s, password %s\n') %
(host, db, user, '*' * len(passwd)))
- self.conn = MySQLdb.connect(host=host, user=user, passwd=passwd,
- db=db, connect_timeout=timeout)
+ self.conn = bzmysql._MySQLdb.connect(host=host,
+ user=user, passwd=passwd,
+ db=db,
+ connect_timeout=timeout)
self.cursor = self.conn.cursor()
self.longdesc_id = self.get_longdesc_id()
self.user_ids = {}
@@ -177,7 +226,7 @@
self.ui.note(_('query: %s %s\n') % (args, kwargs))
try:
self.cursor.execute(*args, **kwargs)
- except MySQLdb.MySQLError:
+ except bzmysql._MySQLdb.MySQLError:
self.ui.note(_('failed query: %s %s\n') % (args, kwargs))
raise
@@ -191,7 +240,8 @@
def filter_real_bug_ids(self, ids):
'''filter not-existing bug ids from set.'''
- self.run('select bug_id from bugs where bug_id in %s' % buglist(ids))
+ self.run('select bug_id from bugs where bug_id in %s' %
+ bzmysql.sql_buglist(ids))
return set([c[0] for c in self.cursor.fetchall()])
def filter_cset_known_bug_ids(self, node, ids):
@@ -199,7 +249,7 @@
self.run('''select bug_id from longdescs where
bug_id in %s and thetext like "%%%s%%"''' %
- (buglist(ids), short(node)))
+ (bzmysql.sql_buglist(ids), short(node)))
for (id,) in self.cursor.fetchall():
self.ui.status(_('bug %d already knows about changeset %s\n') %
(id, short(node)))
@@ -250,13 +300,6 @@
self.user_ids[user] = userid
return userid
- def map_committer(self, user):
- '''map name of committer to bugzilla user name.'''
- for committer, bzuser in self.ui.configitems('usermap'):
- if committer.lower() == user.lower():
- return bzuser
- return user
-
def get_bugzilla_user(self, committer):
'''see if committer is a registered bugzilla user. Return
bugzilla username and userid if so. If not, return default
@@ -291,19 +334,19 @@
(bugid, userid, now, self.longdesc_id))
self.conn.commit()
-class bugzilla_2_18(bugzilla_2_16):
+class bzmysql_2_18(bzmysql):
'''support for bugzilla 2.18 series.'''
def __init__(self, ui):
- bugzilla_2_16.__init__(self, ui)
+ bzmysql.__init__(self, ui)
self.default_notify = \
"cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s"
-class bugzilla_3_0(bugzilla_2_18):
+class bzmysql_3_0(bzmysql_2_18):
'''support for bugzilla 3.0 series.'''
def __init__(self, ui):
- bugzilla_2_18.__init__(self, ui)
+ bzmysql_2_18.__init__(self, ui)
def get_longdesc_id(self):
'''get identity of longdesc field'''
@@ -317,9 +360,9 @@
# supported versions of bugzilla. different versions have
# different schemas.
_versions = {
- '2.16': bugzilla_2_16,
- '2.18': bugzilla_2_18,
- '3.0': bugzilla_3_0
+ '2.16': bzmysql,
+ '2.18': bzmysql_2_18,
+ '3.0': bzmysql_3_0
}
_default_bug_re = (r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*'
@@ -419,13 +462,6 @@
'''add comment to bugzilla for each changeset that refers to a
bugzilla bug id. only add a comment once per bug, so same change
seen multiple times does not fill bug with duplicate data.'''
- try:
- import MySQLdb as mysql
- global MySQLdb
- MySQLdb = mysql
- except ImportError, err:
- raise util.Abort(_('python mysql support not available: %s') % err)
-
if node is None:
raise util.Abort(_('hook type %s does not pass a changeset id') %
hooktype)
@@ -437,6 +473,6 @@
for id in ids:
bz.update(id, ctx)
bz.notify(ids, util.email(ctx.user()))
- except MySQLdb.MySQLError, err:
- raise util.Abort(_('database error: %s') % err.args[1])
+ except Exception, e:
+ raise util.Abort(_('Bugzilla error: %s') % e)