Edgewall Software

Ticket #1462: bugzilla2trac.py.4.diff

File bugzilla2trac.py.4.diff, 22.2 KB (added by charlie.clark@…, 3 years ago)

This should be applied directly to trunk, not on top off the existing diffs

  • bugzilla2trac.py

     
    1313Copyright 2004, Dmitry Yusupov <dmitry_yus@yahoo.com> 
    1414 
    1515Many enhancements, Bill Soudan <bill@soudan.net> 
     16Other enhancements, Florent Guillaume <fg@nuxeo.com> 
    1617""" 
    1718 
     19import re 
     20 
    1821### 
    1922### Conversion Settings -- edit these before running if desired 
    2023### 
     
    2225# Bugzilla version.  You can find this in Bugzilla's globals.pl file. 
    2326# 
    2427# Currently, the following bugzilla versions are known to work: 
    25 #   2.11 
     28#   2.11, 2.16.5 
    2629# 
    2730# If you run this script on a version not listed here and it is successful, 
    2831# please report it to the Trac mailing list so we can update the list. 
     
    3134# MySQL connection parameters for the Bugzilla database.  These can also  
    3235# be specified on the command line. 
    3336BZ_DB = '' 
    34 BZ_HOST = 'localhost' 
     37BZ_HOST = '' 
    3538BZ_USER = '' 
    3639BZ_PASSWORD = '' 
    3740 
     
    4043 
    4144# If true, all existing Trac tickets and attachments will be removed  
    4245# prior to import. 
    43 TRAC_CLEAN = False 
     46TRAC_CLEAN = FALSE 
    4447 
    4548# Enclose imported ticket description and comments in a {{{ }}}  
    4649# preformat block?  This formats the text in a fixed-point font. 
    4750PREFORMAT_COMMENTS = False 
    4851 
     52# Replace bug numbers in comments with #xyz 
     53REPLACE_BUG_NO = False 
     54 
     55# Severities 
     56SEVERITIES = [ 
     57    ('blocker',     '1'), 
     58    ('critical',    '2'), 
     59    ('major',       '3'), 
     60    ('normal',      '4'), 
     61    ('minor',       '5'), 
     62    ('trivial',     '6'), 
     63    ('enhancement', '7'), 
     64    ] 
     65 
     66# Priorities 
     67PRIORITIES = [ 
     68    ('P1', '1'), 
     69    ('P2', '2'), 
     70    ('P3', '3'), 
     71    ('P4', '4'), 
     72    ('P5', '5'), 
     73    ] 
     74 
    4975# By default, all bugs are imported from Bugzilla.  If you add a list 
    5076# of products here, only bugs from those products will be imported. 
    5177PRODUCTS = [] 
     78# These Bugzilla products will be ignored during import. 
     79IGNORE_PRODUCTS = [] 
    5280 
    53 # Trac doesn't have the concept of a product.  Instead, this script can 
    54 # assign keywords in the ticket entry to represent products. 
    55 # 
    56 # ex. PRODUCT_KEYWORDS = { 'product1' : 'PRODUCT1_KEYWORD' } 
    57 PRODUCT_KEYWORDS = {} 
     81# These milestones are ignored 
     82IGNORE_MILESTONES = ['---'] 
    5883 
     84# These logins are converted to these user ids 
     85LOGIN_MAP = { 
     86    #'some.user@example.com': 'someuser', 
     87   } 
     88 
     89# These emails are removed from CC list 
     90IGNORE_CC = [ 
     91    #'loser@example.com', 
     92    ] 
     93 
     94# The 'component' field in Trac can come either from the Product or 
     95# or from the Component field of Bugzilla. COMPONENTS_FROM_PRODUCTS 
     96# switches the behavior. 
     97# If COMPONENTS_FROM_PRODUCTS is True: 
     98# - Bugzilla Product -> Trac Component 
     99# - Bugzilla Component -> Trac Keyword 
     100# IF COMPONENTS_FROM_PRODUCTS is False: 
     101# - Bugzilla Product -> Trac Keyword 
     102# - Bugzilla Component -> Trac Component 
     103COMPONENTS_FROM_PRODUCTS = False 
     104 
     105# If COMPONENTS_FROM_PRODUCTS is True, the default owner for each 
     106# Trac component is inferred from a default Bugzilla component. 
     107DEFAULT_COMPONENTS = ['default', 'misc', 'main'] 
     108 
     109# This mapping can assign keywords in the ticket entry to represent 
     110# products or components (depending on COMPONENTS_FROM_PRODUCTS). 
     111# The keyword will be ignored if empty. 
     112KEYWORDS_MAPPING = { 
     113    #'Bugzilla_product_or_component': 'Keyword', 
     114    'default': '', 
     115    'misc': '', 
     116    } 
     117 
     118# If this is True, products or components are all set as keywords 
     119# even if not mentionned in KEYWORDS_MAPPING. 
     120MAP_ALL_KEYWORDS = True 
     121 
     122 
    59123# Bug comments that should not be imported.  Each entry in list should 
    60124# be a regular expression. 
    61125IGNORE_COMMENTS = [ 
     
    96160# otherwise you'd see changes for fields that don't exist in Trac. 
    97161IGNORED_ACTIVITY_FIELDS = ['everconfirmed'] 
    98162 
     163# Regular expression and its replacement 
     164BUG_NO_RE = re.compile(r'\b(bug #?)([0-9])') 
     165BUG_NO_REPL = r'#\2' 
     166 
    99167### 
    100168### Script begins here 
    101169### 
    102170 
    103171import os 
    104 import re 
    105172import sys 
    106173import string 
    107174import StringIO 
    108175 
    109176import MySQLdb 
    110177import MySQLdb.cursors 
    111 import trac.env 
     178try: 
     179    from trac.env import Environment 
     180except: 
     181    from trac.Environment import Environment 
    112182 
     183from trac import attachment 
     184 
    113185if not hasattr(sys, 'setdefaultencoding'): 
    114186    reload(sys) 
    115187 
    116188sys.setdefaultencoding('latin1') 
    117189 
    118 # simulated Attachment class for trac.add 
    119 class Attachment: 
    120     def __init__(self, name, data): 
    121         self.filename = name 
    122         self.file = StringIO.StringIO(data.tostring()) 
     190     
    123191   
    124192# simple field translation mapping.  if string not in 
    125193# mapping, just return string, otherwise return value 
     
    134202 
    135203class TracDatabase(object): 
    136204    def __init__(self, path): 
    137         self.env = trac.env.Environment(path) 
     205        self.env = Environment(path) 
    138206        self._db = self.env.get_db_cnx() 
    139207        self._db.autocommit = False 
    140208        self.loginNameCache = {} 
     
    210278        c = self.db().cursor() 
    211279        c.execute("""DELETE FROM milestone""") 
    212280        for ms in m: 
    213             print "inserting milestone ", ms[key] 
     281            milestone = ms[key] 
     282            print "inserting milestone ", milestone 
    214283            c.execute("""INSERT INTO milestone (name) VALUES (%s)""", 
    215                       ms[key].encode('utf-8')) 
     284                      milestone.encode('utf-8')) 
    216285        self.db().commit() 
    217286     
    218287    def addTicket(self, id, time, changetime, component, 
     
    226295        if PREFORMAT_COMMENTS: 
    227296          desc = '{{{\n%s\n}}}' % desc 
    228297 
     298        if REPLACE_BUG_NO: 
     299            if BUG_NO_RE.search(desc): 
     300                desc = re.sub(BUG_NO_RE, BUG_NO_REPL, desc) 
     301 
    229302        print "inserting ticket %s -- %s" % (id, summary) 
    230303        c.execute("""INSERT INTO ticket (id, time, changetime, component, 
    231304                                         severity, priority, owner, reporter, cc, 
     
    249322        if PREFORMAT_COMMENTS: 
    250323          comment = '{{{\n%s\n}}}' % comment 
    251324 
     325        if REPLACE_BUG_NO: 
     326            if BUG_NO_RE.search(comment): 
     327                comment = re.sub(BUG_NO_RE, BUG_NO_REPL, comment) 
     328 
    252329        c = self.db().cursor() 
    253330        c.execute("""INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) 
    254331                                 VALUES        (%s, %s, %s, %s, %s, %s)""", 
     
    261338                                 VALUES        (%s, %s, %s, %s, %s, %s)""", 
    262339                  ticket, time.strftime('%s'), author, field, oldvalue.encode('utf-8'), newvalue.encode('utf-8')) 
    263340        self.db().commit() 
     341        
    264342         
    265     def addAttachment(self, id, attachment, description, author): 
    266         print 'inserting attachment for ticket %s -- %s' % (id, description) 
    267         attachment.filename = attachment.filename.encode('utf-8') 
    268         self.env.create_attachment(self.db(), 'ticket', str(id), attachment, description.encode('utf-8'), 
    269             author, 'unknown') 
    270          
    271343    def getLoginName(self, cursor, userid): 
    272344        if userid not in self.loginNameCache: 
    273345            cursor.execute("SELECT * FROM profiles WHERE userid = %s" % userid) 
     
    279351                print 'warning: unknown bugzilla userid %d, recording as anonymous' % userid 
    280352                loginName = 'anonymous' 
    281353 
     354            loginName = LOGIN_MAP.get(loginName, loginName) 
     355 
    282356            self.loginNameCache[userid] = loginName 
    283357 
    284358        return self.loginNameCache[userid] 
     
    298372 
    299373        return self.fieldNameCache[fieldid] 
    300374 
    301 def productFilter(fieldName, products): 
    302     first = True 
    303     result = '' 
    304     for product in products: 
    305         if not first:  
    306             result += " or " 
    307         first = False 
    308         result += "%s = '%s'" % (fieldName, product) 
    309     return result 
     375def makeWhereClause(fieldName, values, negative=False): 
     376    if not values: 
     377        return '' 
     378    if negative: 
     379        connector, op = ' AND ', '!=' 
     380    else: 
     381        connector, op = ' OR ', '=' 
     382    clause = connector.join(["%s %s '%s'" % (fieldName, op, value) 
     383                             for value in values]) 
     384    return ' WHERE '+clause 
    310385 
    311386def convert(_db, _host, _user, _password, _env, _force): 
    312387    activityFields = FieldTranslator() 
    313388 
    314389    # account for older versions of bugzilla 
    315390    if BZ_VERSION == '2.11': 
    316         print 'Using Buzvilla v%s schema.' % BZ_VERSION 
     391        print 'Using Bugzilla v%s schema.' % BZ_VERSION 
    317392        activityFields['removed'] = 'oldvalue' 
    318393        activityFields['added'] = 'newvalue' 
    319394 
     
    337412        c.execute("""DELETE FROM ticket""") 
    338413        trac.db().commit() 
    339414        c.execute("""DELETE FROM attachment""") 
    340         os.system('rm -rf %s' % trac.env.get_attachments_dir()) 
    341         os.mkdir(trac.env.get_attachments_dir()) 
     415        attachments_dir = os.path.join(os.path.normpath(trac.env.path), 'attachments') 
     416        os.system('rm -rf %s' % attachments_dir) 
     417        os.mkdir(attachments_dir) 
    342418        trac.db().commit() 
    343419 
    344420 
    345421    print 
     422    print "0. filtering products..." 
     423    sql = "SELECT product FROM products" 
     424    mysql_cur.execute(sql) 
     425    products = [] 
     426    for line in mysql_cur.fetchall(): 
     427        product = line['product'] 
     428        if PRODUCTS and product not in PRODUCTS: 
     429            continue 
     430        if product in IGNORE_PRODUCTS: 
     431            continue 
     432        products.append(product) 
     433    PRODUCTS[:] = products 
     434    print "using products", ' '.join(PRODUCTS) 
     435 
     436    print 
    346437    print "1. import severities..." 
    347     severities = (('blocker', '1'), ('critical', '2'), ('major', '3'), ('normal', '4'), 
    348         ('minor', '5'), ('trivial', '6'), ('enhancement', '7')) 
    349     trac.setSeverityList(severities) 
     438    trac.setSeverityList(SEVERITIES) 
    350439 
    351440    print 
    352441    print "2. import components..." 
    353     sql = "SELECT value, initialowner AS owner FROM components" 
    354     if PRODUCTS: 
    355        sql += " WHERE %s" % productFilter('program', PRODUCTS) 
    356     mysql_cur.execute(sql) 
    357     components = mysql_cur.fetchall() 
    358     for component in components: 
    359                 component['owner'] = trac.getLoginName(mysql_cur, component['owner']) 
    360     trac.setComponentList(components, 'value') 
     442    if not COMPONENTS_FROM_PRODUCTS: 
     443        sql = "SELECT value, initialowner AS owner FROM components" 
     444        sql += makeWhereClause('program', PRODUCTS) 
     445        mysql_cur.execute(sql) 
     446        components = mysql_cur.fetchall() 
     447        for component in components: 
     448            component['owner'] = trac.getLoginName(mysql_cur, component['owner']) 
     449        trac.setComponentList(components, 'value') 
     450    else: 
     451        sql = "SELECT program AS product, value AS comp, initialowner AS owner FROM components" 
     452        sql += makeWhereClause('program', PRODUCTS) 
     453        mysql_cur.execute(sql) 
     454        lines = mysql_cur.fetchall() 
     455        all_components = {} # product -> components 
     456        all_owners = {} # product, component -> owner 
     457        for line in lines: 
     458            product = line['product'] 
     459            comp = line['comp'] 
     460            owner = line['owner'] 
     461            all_components.setdefault(product, []).append(comp) 
     462            all_owners[(product, comp)] = owner 
     463        component_list = [] 
     464        for product, components in all_components.items(): 
     465            # find best default owner 
     466            default = None 
     467            for comp in DEFAULT_COMPONENTS: 
     468                if comp in components: 
     469                    default = comp 
     470                    break 
     471            if default is None: 
     472                default = components[0] 
     473            owner = all_owners[(product, default)] 
     474            owner_name = trac.getLoginName(mysql_cur, owner) 
     475            component_list.append({'product': product, 'owner': owner_name}) 
     476        trac.setComponentList(component_list, 'product') 
    361477 
    362478    print 
    363479    print "3. import priorities..." 
    364     priorities = (('P1', '1'), ('P2', '2'), ('P3', '3'), ('P4', '4'), ('P5', '5')) 
    365     trac.setPriorityList(priorities) 
     480    trac.setPriorityList(PRIORITIES) 
    366481 
    367482    print 
    368483    print "4. import versions..." 
    369484    sql = "SELECT DISTINCTROW value FROM versions" 
    370     if PRODUCTS: 
    371        sql += " WHERE %s" % productFilter('program', PRODUCTS) 
     485    sql += makeWhereClause('program', PRODUCTS) 
    372486    mysql_cur.execute(sql) 
    373487    versions = mysql_cur.fetchall() 
    374488    trac.setVersionList(versions, 'value') 
    375489 
    376490    print 
    377491    print "5. import milestones..." 
    378     mysql_cur.execute("SELECT value FROM milestones") 
     492    sql = "SELECT DISTINCT value FROM milestones" 
     493    sql += makeWhereClause('value', IGNORE_MILESTONES, negative=True) 
     494    mysql_cur.execute(sql) 
    379495    milestones = mysql_cur.fetchall() 
    380     if milestones[0] == '---': 
    381         trac.setMilestoneList(milestones, 'value') 
    382     else: 
    383         trac.setMilestoneList([], '') 
     496    trac.setMilestoneList(milestones, 'value') 
    384497 
    385498    print 
    386499    print '6. retrieving bugs...' 
    387500    sql = "SELECT * FROM bugs " 
    388     if PRODUCTS: 
    389        sql += " WHERE %s" % productFilter('product', PRODUCTS) 
     501    sql += makeWhereClause('product', PRODUCTS) 
    390502    sql += " ORDER BY bug_id" 
    391503    mysql_cur.execute(sql) 
    392504    bugs = mysql_cur.fetchall() 
     
    401513        ticket['id'] = bugid 
    402514        ticket['time'] = bug['creation_ts'] 
    403515        ticket['changetime'] = bug['delta_ts'] 
    404         ticket['component'] = bug['component'] 
     516        if COMPONENTS_FROM_PRODUCTS: 
     517            ticket['component'] = bug['product'] 
     518        else: 
     519            ticket['component'] = bug['component'] 
    405520        ticket['severity'] = bug['bug_severity'] 
    406521        ticket['priority'] = bug['priority'] 
    407522 
     
    413528        cc_list = [] 
    414529        for cc in cc_records: 
    415530            cc_list.append(trac.getLoginName(mysql_cur, cc['who'])) 
     531        cc_list = [cc for cc in cc_list if '@' in cc and cc not in IGNORE_CC] 
    416532        ticket['cc'] = string.join(cc_list, ', ') 
    417533 
    418534        ticket['version'] = bug['version'] 
    419535 
    420         if bug['target_milestone'] == '---': 
    421             ticket['milestone'] = '' 
    422         else: 
    423             ticket['milestone'] = bug['target_milestone'] 
     536        target_milestone = bug['target_milestone'] 
     537        if target_milestone in IGNORE_MILESTONES: 
     538            target_milestone = '' 
     539        ticket['milestone'] = target_milestone 
    424540 
    425541        bug_status = bug['bug_status'].lower() 
    426542        ticket['status'] = statusXlator[bug_status] 
     
    435551 
    436552        ticket['summary'] = bug['short_desc'] 
    437553 
    438         keywords = string.split(bug['keywords'], ' ') 
    439  
    440554        mysql_cur.execute("SELECT * FROM longdescs WHERE bug_id = %s" % bugid)  
    441555        longdescs = list(mysql_cur.fetchall()) 
    442556 
     
    464578        bugs_activity = mysql_cur.fetchall() 
    465579        resolution = '' 
    466580        ticketChanges = [] 
     581        keywords = [] 
    467582        for activity in bugs_activity: 
    468583            field_name = trac.getFieldName(mysql_cur, activity['fieldid']).lower() 
    469584             
     
    479594            if field_name == 'resolution': 
    480595                resolution = added.lower() 
    481596 
    482             keywordChange = False 
    483             oldKeywords = string.join(keywords, " ") 
     597            add_keywords = [] 
     598            remove_keywords = [] 
    484599 
    485600            # convert bugzilla field names... 
    486601            if field_name == 'bug_severity': 
     
    490605            elif field_name == 'bug_status': 
    491606                field_name = 'status' 
    492607                if removed in STATUS_KEYWORDS: 
    493                     kw = STATUS_KEYWORDS[removed] 
    494                     if kw in keywords: 
    495                         keywords.remove(kw) 
    496                     else: 
    497                         oldKeywords = string.join(keywords + [ kw ], " ") 
    498                     keywordChange = True 
     608                    remove_keywords.append(STATUS_KEYWORDS[removed]) 
    499609                if added in STATUS_KEYWORDS: 
    500                     kw = STATUS_KEYWORDS[added] 
    501                     keywords.append(kw) 
    502                     keywordChange = True 
     610                    add_keywords.append(STATUS_KEYWORDS[added]) 
    503611                added = statusXlator[added] 
    504612                removed = statusXlator[removed] 
    505613            elif field_name == 'short_desc': 
    506614                field_name = 'summary' 
    507             elif field_name == 'product': 
    508                 if removed in PRODUCT_KEYWORDS: 
    509                     kw = PRODUCT_KEYWORDS[removed] 
    510                     if kw in keywords: 
    511                         keywords.remove(kw) 
    512                     else: 
    513                         oldKeywords = string.join(keywords + [ kw ], " ") 
    514                     keywordChange = True 
    515                 if added in PRODUCT_KEYWORDS: 
    516                     kw = PRODUCT_KEYWORDS[added] 
    517                     keywords.append(kw) 
    518                     keywordChange = True 
     615            elif field_name == 'product' and COMPONENTS_FROM_PRODUCTS: 
     616                field_name = 'component' 
     617            elif ((field_name == 'product' and not COMPONENTS_FROM_PRODUCTS) or 
     618                  (field_name == 'component' and COMPONENTS_FROM_PRODUCTS)): 
     619                if MAP_ALL_KEYWORDS or removed in KEYWORDS_MAPPING: 
     620                    kw = KEYWORDS_MAPPING.get(removed, removed) 
     621                    if kw: 
     622                        remove_keywords.append(kw) 
     623                if MAP_ALL_KEYWORDS or added in KEYWORDS_MAPPING: 
     624                    kw = KEYWORDS_MAPPING.get(added, added) 
     625                    if kw: 
     626                        add_keywords.append(kw) 
     627                if field_name == 'component': 
     628                    # just keep the keyword change 
     629                    added = removed = '' 
     630            elif field_name == 'target_milestone': 
     631                field_name = 'milestone' 
     632                if added in IGNORE_MILESTONES: 
     633                    added = '' 
     634                if removed in IGNORE_MILESTONES: 
     635                    removed = '' 
    519636 
    520637            ticketChange = {} 
    521638            ticketChange['ticket'] = bugid 
     
    525642            ticketChange['oldvalue'] = removed 
    526643            ticketChange['newvalue'] = added 
    527644 
    528             if keywordChange: 
    529                 newKeywords = string.join(keywords, " ") 
    530                 ticketChangeKw = ticketChange 
    531                 ticketChangeKw['field'] = 'keywords' 
    532                 ticketChangeKw['oldvalue'] = oldKeywords 
    533                 ticketChangeKw['newvalue'] = newKeywords 
    534                 #trac.addTicketChange(ticket=bugid, time=activity['bug_when'], 
    535                 #    author=trac.getLoginName(mysql_cur, activity['who']), 
    536                 #    field='keywords', oldvalue=oldKeywords, newvalue=newKeywords) 
    537                 ticketChanges.append(ticketChangeKw) 
     645            if add_keywords or remove_keywords: 
     646                # ensure removed ones are in old 
     647                old_keywords = keywords + [kw for kw in remove_keywords if kw not in keywords] 
     648                # remove from new 
     649                keywords = [kw for kw in keywords if kw not in remove_keywords] 
     650                # add to new 
     651                keywords += [kw for kw in add_keywords if kw not in keywords] 
     652                if old_keywords != keywords: 
     653                    ticketChangeKw = ticketChange.copy() 
     654                    ticketChangeKw['field'] = 'keywords' 
     655                    ticketChangeKw['oldvalue'] = ' '.join(old_keywords) 
     656                    ticketChangeKw['newvalue'] = ' '.join(keywords) 
     657                    ticketChanges.append(ticketChangeKw) 
    538658 
    539659            if field_name in IGNORED_ACTIVITY_FIELDS: 
    540660                continue 
     
    552672                  oldChange['oldvalue'] += " " + ticketChange['oldvalue']  
    553673                  oldChange['newvalue'] += " " + ticketChange['newvalue'] 
    554674                  break 
     675              # cc sometime appear in different activities with same time 
     676              if (field_name == 'cc' 
     677                  and oldChange['time'] == ticketChange['time']): 
     678                  oldChange['newvalue'] += ", " + ticketChange['newvalue'] 
     679                  break 
    555680            else: 
    556                 #trac.addTicketChange(ticket=bugid, time=activity['bug_when'], 
    557                 #    author=trac.getLoginName(mysql_cur, activity['who']), 
    558                 #    field=field_name, oldvalue=removed, newvalue=added) 
    559681                ticketChanges.append (ticketChange) 
    560682 
    561683        for ticketChange in ticketChanges: 
     
    568690        if not ticket['resolution'] and ticket['status'] == 'closed': 
    569691            ticket['resolution'] = resolution 
    570692 
    571         if bug['bug_status'] in STATUS_KEYWORDS: 
    572             kw = STATUS_KEYWORDS[bug['bug_status']] 
    573             # may have already been added during activity import 
     693        bug_status = bug['bug_status'] 
     694        if bug_status in STATUS_KEYWORDS: 
     695            kw = STATUS_KEYWORDS[bug_status] 
    574696            if kw not in keywords: 
    575697                keywords.append(kw) 
    576698 
    577         if bug['product'] in PRODUCT_KEYWORDS: 
    578             kw = PRODUCT_KEYWORDS[bug['product']] 
    579             # may have already been added during activity import 
    580             if kw not in keywords: 
     699        product = bug['product'] 
     700        if product in KEYWORDS_MAPPING and not COMPONENTS_FROM_PRODUCTS: 
     701            kw = KEYWORDS_MAPPING.get(product, product) 
     702            if kw and kw not in keywords: 
    581703                keywords.append(kw) 
    582704 
     705        component = bug['component'] 
     706        if (COMPONENTS_FROM_PRODUCTS and 
     707            (MAP_ALL_KEYWORDS or component in KEYWORDS_MAPPING)): 
     708            kw = KEYWORDS_MAPPING.get(component, component) 
     709            if kw and kw not in keywords: 
     710                keywords.append(kw) 
     711 
    583712        mysql_cur.execute("SELECT * FROM attachments WHERE bug_id = %s" % bugid) 
    584713        attachments = mysql_cur.fetchall() 
    585714        for a in attachments: 
    586715            author = trac.getLoginName(mysql_cur, a['submitter_id']) 
    587716             
    588             tracAttachment = Attachment(a['filename'], a['thedata']) 
    589             trac.addAttachment(bugid, tracAttachment, a['description'], author) 
     717            #tracAttachment = Attachment(a['filename'], a['thedata']) 
     718            #trac.addAttachment(bugid, tracAttachment, a['description'], author) 
     719            #self.env.create_attachment(self.db(), 'ticket', str(id), attachment, description.encode('utf-8'), 
     720 
     721            tracAttachment = attachment.Attachment(trac.env, 'ticket', str(a['bug_id']), None, trac.db()) 
     722            tracAttachment.insert(a['filename'], StringIO.StringIO(a['thedata'].tostring()), len(a['thedata'])) 
    590723             
    591724        ticket['keywords'] = string.join(keywords)                 
    592725        ticketid = trac.addTicket(**ticket) 
     
    639772                print "Error: unknown parameter: " + sys.argv[iter] 
    640773                sys.exit(0) 
    641774            iter = iter + 1 
    642     else: 
    643         usage() 
    644775         
    645776    convert(BZ_DB, BZ_HOST, BZ_USER, BZ_PASSWORD, TRAC_ENV, TRAC_CLEAN) 
    646777