Skip to content

Commit c0147a6

Browse files
committed
allowed appending bugs to existing project and got rid of sqlite syntax
1 parent 426f5d5 commit c0147a6

File tree

1 file changed

+45
-29
lines changed

1 file changed

+45
-29
lines changed

mantis2trac.py

+45-29
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
Python 2.4 from http://www.python.org/
88
MySQL >= 3.23 from http://www.mysql.org/
99
10+
Example use:
11+
python mantis2trac.py --db mantis --tracenv /usr/local/trac-projects/myproj/ \
12+
--host localhost --user root --clean --append --products foo,bar
13+
14+
Version 1.6
15+
Author: Steffen Mecke ([email protected])
16+
Date: January 8, 2015
17+
1018
Version 1.5
1119
Author: Matthew Parmelee ([email protected])
1220
Date: July 16, 2013
@@ -30,9 +38,9 @@
3038
Mark Rowe <[email protected]> - original TracDatabase class
3139
Bill Soudan <[email protected]> - Many enhancements
3240
33-
Example use:
34-
python mantis2trac.py --db mantis --tracenv /usr/local/trac-projects/myproj/ \
35-
--host localhost --user root --clean --products foo,bar
41+
Changes in version 1.6:
42+
- allow to append to an existing project (with correct id mapping)
43+
- fixed to work with mysql by removing INSERT OR REPLACE syntax
3644
3745
Changes in version 1.5:
3846
- repaired queries to be consistent with Mantis updates
@@ -125,11 +133,13 @@
125133
MANTIS_PASSWORD = ''
126134

127135
# Path to the Trac environment.
128-
TRAC_ENV = ''
136+
TRAC_ENV = '/var/www/trac/projectname/'
129137

130138
# If true, all existing Trac tickets will be removed
131139
# prior to import.
132-
TRAC_CLEAN = True
140+
TRAC_CLEAN = False
141+
# If TRAC_CLEAN is true and this is true, tickets will be appended
142+
TRAC_APPEND = True
133143

134144
# Enclose imported ticket description and comments in a {{{ }}}
135145
# preformat block? This formats the text in a fixed-point font.
@@ -319,7 +329,8 @@ def __getitem__(self, item):
319329
statusXlator = FieldTranslator(STATUS_TRANSLATE)
320330

321331
class TracDatabase(object):
322-
def __init__(self, path):
332+
def __init__(self, path, append):
333+
self.append = _append
323334
self.env = Environment(path)
324335
self._db = self.env.get_db_cnx()
325336
self._db.autocommit = False
@@ -335,8 +346,9 @@ def hasTickets(self):
335346
return int(c.fetchall()[0][0]) > 0
336347

337348
def assertNoTickets(self):
338-
if self.hasTickets():
339-
raise Exception("Will not modify database with existing tickets!")
349+
if not self._append or self.hasTickets():
350+
raise Exception("Will not modify database with existing tickets!")
351+
return
340352

341353
def setSeverityList(self, s):
342354
"""Remove all severities, set them to `s`"""
@@ -413,15 +425,15 @@ def addTicket(self, id, time, changetime, component,
413425
if PREFORMAT_COMMENTS:
414426
desc = '{{{\n%s\n}}}' % desc
415427
print "inserting ticket %s -- \"%s\"" % (id, summary[0:40].replace("\n", " "))
416-
c.execute("""INSERT OR REPLACE INTO ticket (id, type, time, changetime, component,
428+
c.execute("""INSERT INTO ticket (type, time, changetime, component,
417429
severity, priority, owner, reporter, cc,
418430
version, milestone, status, resolution,
419431
summary, description, keywords)
420-
VALUES (%s, %s, %s, %s, %s,
432+
VALUES (%s, %s, %s, %s,
421433
%s, %s, %s, %s, %s,
422434
%s, %s, %s, %s,
423435
%s, %s, %s)""",
424-
(id, type, self.convertTime(time), self.convertTime(changetime), component.encode('utf-8'),
436+
(type, self.convertTime(time), self.convertTime(changetime), component.encode('utf-8'),
425437
severity.encode('utf-8'), priority.encode('utf-8'), owner, reporter, cc,
426438
version, milestone.encode('utf-8'), status.lower(), resolution,
427439
summary.decode('utf-8'), desc, keywords.encode('utf-8')))
@@ -450,7 +462,7 @@ def addTicketComment(self, ticket, time, author, value):
450462
comment = '{{{\n%s\n}}}' % comment
451463

452464
c = self.db().cursor()
453-
c.execute("""INSERT OR IGNORE INTO ticket_change (ticket, time, author, field, oldvalue, newvalue)
465+
c.execute("""INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue)
454466
VALUES (%s, %s, %s, %s, %s, %s)""",
455467
(ticket, self.convertTime(time), author, 'comment', '', comment))
456468
self.db().commit()
@@ -471,7 +483,7 @@ def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue):
471483
fixtime = c.fetchall()
472484
if fixtime:
473485
time = time + 1
474-
c.execute("""INSERT OR IGNORE INTO ticket_change (ticket, time, author, field, oldvalue, newvalue)
486+
c.execute("""INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue)
475487
VALUES (%s, %s, %s, %s, %s, %s)""",
476488
(ticket, self.convertTime(time), author, field, oldvalue.encode('utf-8'), newvalue.encode('utf-8')))
477489
self.db().commit()
@@ -513,7 +525,7 @@ def getLoginName(self, cursor, userid):
513525
if not r:
514526
sessionSql = """INSERT INTO session
515527
(sid, authenticated, last_visit)
516-
VALUES (%s, %s, %s)""", (result[0]['username'].encode('utf-8'), '1', self.convertTime(result[0]['last_visit']))
528+
VALUES (%s, %s, %d)""", (result[0]['username'].encode('utf-8'), '1', self.convertTime(result[0]['last_visit']))
517529
# pre-populate the session table and the realname/email table with user data
518530
try:
519531
c.execute(sessionSql)
@@ -588,7 +600,7 @@ def productFilter(fieldName, products):
588600
result += "%s = '%s'" % (fieldName, product)
589601
return result
590602

591-
def convert(_db, _host, _user, _password, _env, _force):
603+
def convert(_db, _host, _user, _password, _env, _force, _append):
592604
activityFields = FieldTranslator()
593605

594606
# account for older versions of mantis
@@ -606,7 +618,7 @@ def convert(_db, _host, _user, _password, _env, _force):
606618

607619
# init Trac environment
608620
print "Trac database('%s'): connecting..." % (_env)
609-
trac = TracDatabase(_env)
621+
trac = TracDatabase(_env, _append)
610622

611623
# force mode...
612624
if _force == 1:
@@ -748,8 +760,9 @@ def convert(_db, _host, _user, _password, _env, _force):
748760
del longdescs[0]
749761

750762
# Add the ticket to the Trac database
751-
trac.addTicket(**ticket)
752-
763+
new_id = trac.addTicket(**ticket)
764+
print "ticket %s has id %s" % (bugid, new_id)
765+
753766
#
754767
# Add ticket comments
755768
#
@@ -764,7 +777,7 @@ def convert(_db, _host, _user, _password, _env, _force):
764777
project, branch, commit = activity[0]['new_value'].split()
765778
wikivalue = '%s [/browser/?rev=%s %s] [%s]' % (project, commit, branch, commit)
766779
note['note'] = note['note'] + "\n\n" + wikivalue
767-
trac.addTicketComment(bugid, note['date_submitted'], trac.getLoginName(mysql_cur, note['reporter_id']), note['note'])
780+
trac.addTicketComment(new_id, note['date_submitted'], trac.getLoginName(mysql_cur, note['reporter_id']), note['note'])
768781

769782
#
770783
# Convert ticket changes
@@ -800,7 +813,7 @@ def convert(_db, _host, _user, _password, _env, _force):
800813
# - 'version' -> 'milestone'
801814

802815
ticketChange = {}
803-
ticketChange['ticket'] = bugid
816+
ticketChange['ticket'] = new_id
804817
ticketChange['oldvalue'] = activity['old_value']
805818
ticketChange['newvalue'] = activity['new_value']
806819
ticketChange['time'] = activity['date_modified']
@@ -929,24 +942,24 @@ def convert(_db, _host, _user, _password, _env, _force):
929942

930943
try:
931944
try:
932-
if(os.path.isdir(trac.get_attachments_dir(bugid)) == False):
945+
if(os.path.isdir(trac.get_attachments_dir(new_id)) == False):
933946
try:
934-
os.mkdir(trac.get_attachments_dir(bugid))
947+
os.mkdir(trac.get_attachments_dir(new_id))
935948
except:
936-
errorStr = " * ERROR: couldnt create attachment directory in filesystem at %s" % trac.get_attachments_dir(bugid)
949+
errorStr = " * ERROR: couldnt create attachment directory in filesystem at %s" % trac.get_attachments_dir(new_id)
937950
errors.append(errorStr)
938951
print errorStr
939952
# trac stores the files with the special characters like spaces in the filename encoded to the url
940953
# equivalents, so we have to urllib.quote() the filename we're saving.
941-
attachmentFile = open(trac.get_attachments_dir(bugid) + quote(attachment['filename']),'wb')
954+
attachmentFile = open(trac.get_attachments_dir(new_id) + quote(attachment['filename']),'wb')
942955
attachmentFile.write(attachment['content'])
943956
attachmentFile.close()
944957
except:
945-
errorStr = " * ERROR: couldnt dump attachment data into filesystem at %s" % trac.get_attachments_dir(bugid) + attachment['filename']
958+
errorStr = " * ERROR: couldnt dump attachment data into filesystem at %s" % trac.get_attachments_dir(new_id) + attachment['filename']
946959
errors.append(errorStr)
947960
print errorStr
948961
else:
949-
attach_sql = """INSERT INTO attachment (type,id,filename,size,time,description,author,ipnr) VALUES ('ticket',%s,'%s',%i,%i,'%s','%s','127.0.0.1')""" % (bugid,attachment['filename'].encode('utf-8'),attachment['filesize'],trac.convertTime(attachment['date_added']),attachment['description'].encode('utf-8'),author)
962+
attach_sql = """INSERT INTO attachment (type,id,filename,size,time,description,author,ipnr) VALUES ('ticket',%s,'%s',%i,%i,'%s','%s','127.0.0.1')""" % (new_id,attachment['filename'].encode('utf-8'),attachment['filesize'],trac.convertTime(attachment['date_added']),attachment['description'].encode('utf-8'),author)
950963
try:
951964
c = trac.db().cursor()
952965
c.execute(attach_sql)
@@ -960,12 +973,12 @@ def convert(_db, _host, _user, _password, _env, _force):
960973

961974
totalAttachments += 1
962975
hash = hashlib.sha1()
963-
hash.update(str(bugid).encode('utf-8'))
976+
hash.update(str(new_id).encode('utf-8'))
964977
path_hash = hash.hexdigest()
965978
hash = hashlib.sha1()
966979
hash.update(attachment['filename'].encode('utf-8'))
967980
file_hash = hash.hexdigest()
968-
old_path = 'importfiles/%s/%s' % (bugid, quote(attachment['filename']))
981+
old_path = 'importfiles/%s/%s' % (new_id, quote(attachment['filename']))
969982
new_path = TRAC_ENV + '/files/attachments/ticket/'
970983
new_path += '%s/%s/' % (path_hash[0:3], path_hash)
971984
try:
@@ -1009,6 +1022,7 @@ def usage():
10091022
print " -u | --user <MySQL username> - Effective Mantis database user"
10101023
print " -p | --passwd <MySQL password> - Mantis database user password"
10111024
print " -c | --clean - Remove current Trac tickets before importing"
1025+
print " -a | --append - Append bugs to existing project"
10121026
print " --products <product1,product2> - List of products to import from mantis"
10131027
print " --help | help - This help info"
10141028
print
@@ -1045,6 +1059,8 @@ def main():
10451059
iter = iter + 1
10461060
elif sys.argv[iter] in ['-c', '--clean']:
10471061
TRAC_CLEAN = 1
1062+
elif sys.argv[iter] in ['-a', '--append']:
1063+
TRAC_APPEND = 1
10481064
elif sys.argv[iter] in ['--products'] and iter+1 < len(sys.argv):
10491065
PRODUCTS = sys.argv[iter+1].split(',')
10501066
iter = iter + 1
@@ -1055,7 +1071,7 @@ def main():
10551071
else:
10561072
usage()
10571073

1058-
convert(MANTIS_DB, MANTIS_HOST, MANTIS_USER, MANTIS_PASSWORD, TRAC_ENV, TRAC_CLEAN)
1074+
convert(MANTIS_DB, MANTIS_HOST, MANTIS_USER, MANTIS_PASSWORD, TRAC_ENV, TRAC_CLEAN, TRAC_APPEND)
10591075

10601076
if __name__ == '__main__':
10611077
main()

0 commit comments

Comments
 (0)