123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808 |
- try:
- # Using Psyco makes it about 25% faster, but there's a bug in psyco in
- # handling of eval causing it to use unlimited memory with the magic
- # file enabled.
- # import psyco
- # psyco.full()
- # from psyco.classes import *
- pass
- except:
- pass
- import re
- import base64
- import cStringIO
- import specialuu
- import array
- import email.Utils
- import zlib
- import magic
- # Comment out if you don't want magic detection
- magicf = magic.MagicFile()
- # Open our output file
- outfile = open("gnats2bz_data.sql", "w")
- # List of GNATS fields
- fieldnames = ("Number", "Category", "Synopsis", "Confidential", "Severity",
- "Priority", "Responsible", "State", "Quarter", "Keywords",
- "Date-Required", "Class", "Submitter-Id", "Arrival-Date",
- "Closed-Date", "Last-Modified", "Originator", "Release",
- "Organization", "Environment", "Description", "How-To-Repeat",
- "Fix", "Release-Note", "Audit-Trail", "Unformatted")
- # Dictionary telling us which GNATS fields are multiline
- multilinefields = {"Organization":1, "Environment":1, "Description":1,
- "How-To-Repeat":1, "Fix":1, "Release-Note":1,
- "Audit-Trail":1, "Unformatted":1}
- # Mapping of GCC release to version. Our version string is updated every
- # so we need to funnel all release's with 3.4 in the string to be version
- # 3.4 for bug tracking purposes
- # The key is a regex to match, the value is the version it corresponds
- # with
- releasetovermap = {r"3\.4":"3.4", r"3\.3":"3.3", r"3\.2\.2":"3.2.2",
- r"3\.2\.1":"3.2.1", r"3\.2":"3.2", r"3\.1\.2":"3.1.2",
- r"3\.1\.1":"3.1.1", r"3\.1":"3.1", r"3\.0\.4":"3.0.4",
- r"3\.0\.3":"3.0.3", r"3\.0\.2":"3.0.2", r"3\.0\.1":"3.0.1",
- r"3\.0":"3.0", r"2\.95\.4":"2.95.4", r"2\.95\.3":"2.95.3",
- r"2\.95\.2":"2.95.2", r"2\.95\.1":"2.95.1",
- r"2\.95":"2.95", r"2\.97":"2.97",
- r"2\.96.*[rR][eE][dD].*[hH][aA][tT]":"2.96 (redhat)",
- r"2\.96":"2.96"}
- # These map the field name to the field id bugzilla assigns. We need
- # the id when doing bug activity.
- fieldids = {"State":8, "Responsible":15}
- # These are the keywords we use in gcc bug tracking. They are transformed
- # into bugzilla keywords. The format here is <keyword>-><bugzilla keyword id>
- keywordids = {"wrong-code":1, "ice-on-legal-code":2, "ice-on-illegal-code":3,
- "rejects-legal":4, "accepts-illegal":5, "pessimizes-code":6}
- # Map from GNATS states to Bugzilla states. Duplicates and reopened bugs
- # are handled when parsing the audit trail, so no need for them here.
- state_lookup = {"":"NEW", "open":"ASSIGNED", "analyzed":"ASSIGNED",
- "feedback":"WAITING", "closed":"CLOSED",
- "suspended":"SUSPENDED"}
- # Table of versions that exist in the bugs, built up as we go along
- versions_table = {}
- # Delimiter gnatsweb uses for attachments
- attachment_delimiter = "----gnatsweb-attachment----\n"
- # Here starts the various regular expressions we use
- # Matches an entire GNATS single line field
- gnatfieldre = re.compile(r"""^([>\w\-]+)\s*:\s*(.*)\s*$""")
- # Matches the name of a GNATS field
- fieldnamere = re.compile(r"""^>(.*)$""")
- # Matches the useless part of an envelope
- uselessre = re.compile(r"""^(\S*?):\s*""", re.MULTILINE)
- # Matches the filename in a content disposition
- dispositionre = re.compile("(\\S+);\\s*filename=\"([^\"]+)\"")
- # Matches the last changed date in the entire text of a bug
- # If you have other editable fields that get audit trail entries, modify this
- # The field names are explicitly listed in order to speed up matching
- lastdatere = re.compile(r"""^(?:(?:State|Responsible|Priority|Severity)-Changed-When: )(.+?)$""", re.MULTILINE)
- # Matches the From line of an email or the first line of an audit trail entry
- # We use this re to find the begin lines of all the audit trail entries
- # The field names are explicitly listed in order to speed up matching
- fromtore=re.compile(r"""^(?:(?:State|Responsible|Priority|Severity)-Changed-From-To: |From: )""", re.MULTILINE)
- # These re's match the various parts of an audit trail entry
- changedfromtore=re.compile(r"""^(\w+?)-Changed-From-To: (.+?)$""", re.MULTILINE)
- changedbyre=re.compile(r"""^\w+?-Changed-By: (.+?)$""", re.MULTILINE)
- changedwhenre=re.compile(r"""^\w+?-Changed-When: (.+?)$""", re.MULTILINE)
- changedwhyre=re.compile(r"""^\w+?-Changed-Why:\s*(.*?)$""", re.MULTILINE)
- # This re matches audit trail text saying that the current bug is a duplicate of another
- duplicatere=re.compile(r"""(?:")?Dup(?:licate)?(?:d)?(?:")? of .*?(\d+)""", re.IGNORECASE | re.MULTILINE)
- # Get the text of a From: line
- fromre=re.compile(r"""^From: (.*?)$""", re.MULTILINE)
- # Get the text of a Date: Line
- datere=re.compile(r"""^Date: (.*?)$""", re.MULTILINE)
- # Map of the responsible file to email addresses
- responsible_map = {}
- # List of records in the responsible file
- responsible_list = []
- # List of records in the categories file
- categories_list = []
- # List of pr's in the index
- pr_list = []
- # Map usernames to user ids
- usermapping = {}
- # Start with this user id
- userid_base = 2
- # Name of gnats user
- gnats_username = "gnats@gcc.gnu.org"
- # Name of unassigned user
- unassigned_username = "unassigned@gcc.gnu.org"
- gnats_db_dir = "."
- product = "gcc"
- productdesc = "GNU Compiler Connection"
- milestoneurl = "http://gcc/gnu.org"
- defaultmilestone = "3.4"
- def write_non_bug_tables():
- """ Write out the non-bug related tables, such as products, profiles, etc."""
- # Set all non-unconfirmed bugs's everconfirmed flag
- print >>outfile, "update bugs set everconfirmed=1 where bug_status != 'UNCONFIRMED';"
- # Set all bugs assigned to the unassigned user to NEW
- print >>outfile, "update bugs set bug_status='NEW',assigned_to='NULL' where bug_status='ASSIGNED' AND assigned_to=3;"
-
- # Insert the products
- print >>outfile, "\ninsert into products ("
- print >>outfile, " product, description, milestoneurl, disallownew,"
- print >>outfile, " defaultmilestone, votestoconfirm) values ("
- print >>outfile, " '%s', '%s', '%s', 0, '%s', 1);" % (product,
- productdesc,
- milestoneurl,
- defaultmilestone)
- # Insert the components
- for category in categories_list:
- component = SqlQuote(category[0])
- productstr = SqlQuote(product)
- description = SqlQuote(category[1])
- initialowner = SqlQuote("3")
- print >>outfile, "\ninsert into components (";
- print >>outfile, " value, program, initialowner, initialqacontact,"
- print >>outfile, " description) values ("
- print >>outfile, " %s, %s, %s, '', %s);" % (component, productstr,
- initialowner, description)
-
- # Insert the versions
- for productstr, version_list in versions_table.items():
- productstr = SqlQuote(productstr)
- for version in version_list:
- version = SqlQuote(version)
- print >>outfile, "\ninsert into versions (value, program) "
- print >>outfile, " values (%s, %s);" % (version, productstr)
-
- # Insert the users
- for username, userid in usermapping.items():
- realname = map_username_to_realname(username)
- username = SqlQuote(username)
- realname = SqlQuote(realname)
- print >>outfile, "\ninsert into profiles ("
- print >>outfile, " userid, login_name, password, cryptpassword, realname, groupset"
- print >>outfile, ") values ("
- print >>outfile, "%s,%s,'password',encrypt('password'), %s, 0);" % (userid, username, realname)
- print >>outfile, "update profiles set groupset=1 << 32 where login_name like '%\@gcc.gnu.org';"
-
- def unixdate2datetime(unixdate):
- """ Convert a unix date to a datetime value """
- year, month, day, hour, min, sec, x, x, x, x = email.Utils.parsedate_tz(unixdate)
- return "%d-%02d-%02d %02d:%02d:%02d" % (year,month,day,hour,min,sec)
- def unixdate2timestamp(unixdate):
- """ Convert a unix date to a timestamp value """
- year, month, day, hour, min, sec, x, x, x, x = email.Utils.parsedate_tz(unixdate)
- return "%d%02d%02d%02d%02d%02d" % (year,month,day,hour,min,sec)
- def SqlQuote(str):
- """ Perform SQL quoting on a string """
- return "'%s'" % str.replace("'", """''""").replace("\\", "\\\\").replace("\0","\\0")
- def convert_gccver_to_ver(gccver):
- """ Given a gcc version, convert it to a Bugzilla version. """
- for k in releasetovermap.keys():
- if re.search(".*%s.*" % k, gccver) is not None:
- return releasetovermap[k]
- result = re.search(r""".*(\d\.\d) \d+ \(experimental\).*""", gccver)
- if result is not None:
- return result.group(1)
- return "unknown"
- def load_index(fname):
- """ Load in the GNATS index file """
- global pr_list
- ifp = open(fname)
- for record in ifp.xreadlines():
- fields = record.split("|")
- pr_list.append(fields[0])
- ifp.close()
-
- def load_categories(fname):
- """ Load in the GNATS categories file """
- global categories_list
- cfp = open(fname)
- for record in cfp.xreadlines():
- if re.search("^#", record) is not None:
- continue
- categories_list.append(record.split(":"))
- cfp.close()
-
- def map_username_to_realname(username):
- """ Given a username, find the real name """
- name = username
- name = re.sub("@.*", "", name)
- for responsible_record in responsible_list:
- if responsible_record[0] == name:
- return responsible_record[1]
- if len(responsible_record) > 2:
- if responsible_record[2] == username:
- return responsible_record[1]
- return ""
- def get_userid(responsible):
- """ Given an email address, get the user id """
- global responsible_map
- global usermapping
- global userid_base
- if responsible is None:
- return -1
- responsible = responsible.lower()
- responsible = re.sub("sources.redhat.com", "gcc.gnu.org", responsible)
- if responsible_map.has_key(responsible):
- responsible = responsible_map[responsible]
- if usermapping.has_key(responsible):
- return usermapping[responsible]
- else:
- usermapping[responsible] = userid_base
- userid_base += 1
- return usermapping[responsible]
- def load_responsible(fname):
- """ Load in the GNATS responsible file """
- global responsible_map
- global responsible_list
- rfp = open(fname)
- for record in rfp.xreadlines():
- if re.search("^#", record) is not None:
- continue
- split_record = record.split(":")
- responsible_map[split_record[0]] = split_record[2].rstrip()
- responsible_list.append(record.split(":"))
- rfp.close()
- def split_csl(list):
- """ Split a comma separated list """
- newlist = re.split(r"""\s*,\s*""", list)
- return newlist
- def fix_email_addrs(addrs):
- """ Perform various fixups and cleaning on an e-mail address """
- addrs = split_csl(addrs)
- trimmed_addrs = []
- for addr in addrs:
- addr = re.sub(r"""\(.*\)""","",addr)
- addr = re.sub(r""".*<(.*)>.*""","\\1",addr)
- addr = addr.rstrip()
- addr = addr.lstrip()
- trimmed_addrs.append(addr)
- addrs = ", ".join(trimmed_addrs)
- return addrs
- class Bugzillabug(object):
- """ Class representing a bugzilla bug """
- def __init__(self, gbug):
- """ Initialize a bugzilla bug from a GNATS bug. """
- self.bug_id = gbug.bug_id
- self.long_descs = []
- self.bug_ccs = [get_userid("gcc-bugs@gcc.gnu.org")]
- self.bug_activity = []
- self.attachments = gbug.attachments
- self.gnatsfields = gbug.fields
- self.need_unformatted = gbug.has_unformatted_attach == 0
- self.need_unformatted &= gbug.fields.has_key("Unformatted")
- self.translate_pr()
- self.update_versions()
- if self.fields.has_key("Audit-Trail"):
- self.parse_audit_trail()
- self.write_bug()
-
- def parse_fromto(type, string):
- """ Parses the from and to parts of a changed-from-to line """
- fromstr = ""
- tostr = ""
- # Some slightly messed up changed lines have unassigned-new,
- # instead of unassigned->new. So we make the > optional.
- result = re.search(r"""(.*)-(?:>?)(.*)""", string)
-
- # Only know how to handle parsing of State and Responsible
- # changed-from-to right now
- if type == "State":
- fromstr = state_lookup[result.group(1)]
- tostr = state_lookup[result.group(2)]
- elif type == "Responsible":
- if result.group(1) != "":
- fromstr = result.group(1)
- if result.group(2) != "":
- tostr = result.group(2)
- if responsible_map.has_key(fromstr):
- fromstr = responsible_map[fromstr]
- if responsible_map.has_key(tostr):
- tostr = responsible_map[tostr]
- return (fromstr, tostr)
- parse_fromto = staticmethod(parse_fromto)
-
- def parse_audit_trail(self):
- """ Parse a GNATS audit trail """
- trail = self.fields["Audit-Trail"]
- # Begin to split the audit trail into pieces
- result = fromtore.finditer(trail)
- starts = []
- ends = []
- pieces = []
- # Make a list of the pieces
- for x in result:
- pieces.append (x)
- # Find the start and end of each piece
- if len(pieces) > 0:
- for x in xrange(len(pieces)-1):
- starts.append(pieces[x].start())
- ends.append(pieces[x+1].start())
- starts.append(pieces[-1].start())
- ends.append(len(trail))
- pieces = []
- # Now make the list of actual text of the pieces
- for x in xrange(len(starts)):
- pieces.append(trail[starts[x]:ends[x]])
- # And parse the actual pieces
- for piece in pieces:
- result = changedfromtore.search(piece)
- # See what things we actually have inside this entry, and
- # handle them appropriately
- if result is not None:
- type = result.group(1)
- changedfromto = result.group(2)
- # If the bug was reopened, mark it as such
- if changedfromto.find("closed->analyzed") != -1:
- if self.fields["bug_status"] == "'NEW'":
- self.fields["bug_status"] = "'REOPENED'"
- if type == "State" or type == "Responsible":
- oldstate, newstate = self.parse_fromto (type, changedfromto)
- result = changedbyre.search(piece)
- if result is not None:
- changedby = result.group(1)
- result = changedwhenre.search(piece)
- if result is not None:
- changedwhen = result.group(1)
- changedwhen = unixdate2datetime(changedwhen)
- changedwhen = SqlQuote(changedwhen)
- result = changedwhyre.search(piece)
- changedwhy = piece[result.start(1):]
- #changedwhy = changedwhy.lstrip()
- changedwhy = changedwhy.rstrip()
- changedby = get_userid(changedby)
- # Put us on the cc list if we aren't there already
- if changedby != self.fields["userid"] \
- and changedby not in self.bug_ccs:
- self.bug_ccs.append(changedby)
- # If it's a duplicate, mark it as such
- result = duplicatere.search(changedwhy)
- if result is not None:
- newtext = "*** This bug has been marked as a duplicate of %s ***" % result.group(1)
- newtext = SqlQuote(newtext)
- self.long_descs.append((self.bug_id, changedby,
- changedwhen, newtext))
- self.fields["bug_status"] = "'RESOLVED'"
- self.fields["resolution"] = "'DUPLICATE'"
- self.fields["userid"] = changedby
- else:
- newtext = "%s-Changed-From-To: %s\n%s-Changed-Why: %s\n" % (type, changedfromto, type, changedwhy)
- newtext = SqlQuote(newtext)
- self.long_descs.append((self.bug_id, changedby,
- changedwhen, newtext))
- if type == "State" or type == "Responsible":
- newstate = SqlQuote("%s" % newstate)
- oldstate = SqlQuote("%s" % oldstate)
- fieldid = fieldids[type]
- self.bug_activity.append((newstate, oldstate, fieldid, changedby, changedwhen))
-
- else:
- # It's an email
- result = fromre.search(piece)
- if result is None:
- continue
- fromstr = result.group(1)
- fromstr = fix_email_addrs(fromstr)
- fromstr = get_userid(fromstr)
- result = datere.search(piece)
- if result is None:
- continue
- datestr = result.group(1)
- datestr = SqlQuote(unixdate2timestamp(datestr))
- if fromstr != self.fields["userid"] \
- and fromstr not in self.bug_ccs:
- self.bug_ccs.append(fromstr)
- self.long_descs.append((self.bug_id, fromstr, datestr,
- SqlQuote(piece)))
-
-
- def write_bug(self):
- """ Output a bug to the data file """
- fields = self.fields
- print >>outfile, "\ninsert into bugs("
- print >>outfile, " bug_id, assigned_to, bug_severity, priority, bug_status, creation_ts, delta_ts,"
- print >>outfile, " short_desc,"
- print >>outfile, " reporter, version,"
- print >>outfile, " product, component, resolution, target_milestone, qa_contact,"
- print >>outfile, " gccbuild, gcctarget, gcchost, keywords"
- print >>outfile, " ) values ("
- print >>outfile, "%s, %s, %s, %s, %s, %s, %s," % (self.bug_id, fields["userid"], fields["bug_severity"], fields["priority"], fields["bug_status"], fields["creation_ts"], fields["delta_ts"])
- print >>outfile, "%s," % (fields["short_desc"])
- print >>outfile, "%s, %s," % (fields["reporter"], fields["version"])
- print >>outfile, "%s, %s, %s, %s, 0," %(fields["product"], fields["component"], fields["resolution"], fields["target_milestone"])
- print >>outfile, "%s, %s, %s, %s" % (fields["gccbuild"], fields["gcctarget"], fields["gcchost"], fields["keywords"])
- print >>outfile, ");"
- if self.fields["keywords"] != 0:
- print >>outfile, "\ninsert into keywords (bug_id, keywordid) values ("
- print >>outfile, " %s, %s);" % (self.bug_id, fields["keywordid"])
- for id, who, when, text in self.long_descs:
- print >>outfile, "\ninsert into longdescs ("
- print >>outfile, " bug_id, who, bug_when, thetext) values("
- print >>outfile, " %s, %s, %s, %s);" % (id, who, when, text)
- for name, data, who in self.attachments:
- print >>outfile, "\ninsert into attachments ("
- print >>outfile, " bug_id, filename, description, mimetype, ispatch, submitter_id) values ("
- ftype = None
- # It's *magic*!
- if name.endswith(".ii") == 1:
- ftype = "text/x-c++"
- elif name.endswith(".i") == 1:
- ftype = "text/x-c"
- else:
- ftype = magicf.detect(cStringIO.StringIO(data))
- if ftype is None:
- ftype = "application/octet-stream"
-
- print >>outfile, "%s,%s,%s, %s,0, %s,%s);" %(self.bug_id, SqlQuote(name), SqlQuote(name), SqlQuote (ftype), who)
- print >>outfile, "\ninsert into attach_data ("
- print >>outfile, "\n(id, thedata) values (last_insert_id(),"
- print >>outfile, "%s);" % (SqlQuote(zlib.compress(data)))
- for newstate, oldstate, fieldid, changedby, changedwhen in self.bug_activity:
- print >>outfile, "\ninsert into bugs_activity ("
- print >>outfile, " bug_id, who, bug_when, fieldid, added, removed) values ("
- print >>outfile, " %s, %s, %s, %s, %s, %s);" % (self.bug_id,
- changedby,
- changedwhen,
- fieldid,
- newstate,
- oldstate)
- for cc in self.bug_ccs:
- print >>outfile, "\ninsert into cc(bug_id, who) values (%s, %s);" %(self.bug_id, cc)
- def update_versions(self):
- """ Update the versions table to account for the version on this bug """
- global versions_table
- if self.fields.has_key("Release") == 0 \
- or self.fields.has_key("Category") == 0:
- return
- curr_product = "gcc"
- curr_version = self.fields["Release"]
- if curr_version == "":
- return
- curr_version = convert_gccver_to_ver (curr_version)
- if versions_table.has_key(curr_product) == 0:
- versions_table[curr_product] = []
- for version in versions_table[curr_product]:
- if version == curr_version:
- return
- versions_table[curr_product].append(curr_version)
- def translate_pr(self):
- """ Transform a GNATS PR into a Bugzilla bug """
- self.fields = self.gnatsfields
- if (self.fields.has_key("Organization") == 0) \
- or self.fields["Organization"].find("GCC"):
- self.fields["Originator"] = ""
- self.fields["Organization"] = ""
- self.fields["Organization"].lstrip()
- if (self.fields.has_key("Release") == 0) \
- or self.fields["Release"] == "" \
- or self.fields["Release"].find("unknown-1.0") != -1:
- self.fields["Release"]="unknown"
- if self.fields.has_key("Responsible"):
- result = re.search(r"""\w+""", self.fields["Responsible"])
- self.fields["Responsible"] = "%s%s" % (result.group(0), "@gcc.gnu.org")
- self.fields["gcchost"] = ""
- self.fields["gcctarget"] = ""
- self.fields["gccbuild"] = ""
- if self.fields.has_key("Environment"):
- result = re.search("^host: (.+?)$", self.fields["Environment"],
- re.MULTILINE)
- if result is not None:
- self.fields["gcchost"] = result.group(1)
- result = re.search("^target: (.+?)$", self.fields["Environment"],
- re.MULTILINE)
- if result is not None:
- self.fields["gcctarget"] = result.group(1)
- result = re.search("^build: (.+?)$", self.fields["Environment"],
- re.MULTILINE)
- if result is not None:
- self.fields["gccbuild"] = result.group(1)
- self.fields["userid"] = get_userid(self.fields["Responsible"])
- self.fields["bug_severity"] = "normal"
- if self.fields["Class"] == "change-request":
- self.fields["bug_severity"] = "enhancement"
- elif self.fields.has_key("Severity"):
- if self.fields["Severity"] == "critical":
- self.fields["bug_severity"] = "critical"
- elif self.fields["Severity"] == "serious":
- self.fields["bug_severity"] = "major"
- elif self.fields.has_key("Synopsis"):
- if re.search("crash|assert", self.fields["Synopsis"]):
- self.fields["bug_severity"] = "critical"
- elif re.search("wrong|error", self.fields["Synopsis"]):
- self.fields["bug_severity"] = "major"
- self.fields["bug_severity"] = SqlQuote(self.fields["bug_severity"])
- self.fields["keywords"] = 0
- if keywordids.has_key(self.fields["Class"]):
- self.fields["keywords"] = self.fields["Class"]
- self.fields["keywordid"] = keywordids[self.fields["Class"]]
- self.fields["keywords"] = SqlQuote(self.fields["keywords"])
- self.fields["priority"] = "P1"
- if self.fields.has_key("Severity") and self.fields.has_key("Priority"):
- severity = self.fields["Severity"]
- priority = self.fields["Priority"]
- if severity == "critical":
- if priority == "high":
- self.fields["priority"] = "P1"
- else:
- self.fields["priority"] = "P2"
- elif severity == "serious":
- if priority == "low":
- self.fields["priority"] = "P4"
- else:
- self.fields["priority"] = "P3"
- else:
- if priority == "high":
- self.fields["priority"] = "P4"
- else:
- self.fields["priority"] = "P5"
- self.fields["priority"] = SqlQuote(self.fields["priority"])
- state = self.fields["State"]
- if (state == "open" or state == "analyzed") and self.fields["userid"] != 3:
- self.fields["bug_status"] = "ASSIGNED"
- self.fields["resolution"] = ""
- elif state == "feedback":
- self.fields["bug_status"] = "WAITING"
- self.fields["resolution"] = ""
- elif state == "closed":
- self.fields["bug_status"] = "CLOSED"
- if self.fields.has_key("Class"):
- theclass = self.fields["Class"]
- if theclass.find("duplicate") != -1:
- self.fields["resolution"]="DUPLICATE"
- elif theclass.find("mistaken") != -1:
- self.fields["resolution"]="INVALID"
- else:
- self.fields["resolution"]="FIXED"
- else:
- self.fields["resolution"]="FIXED"
- elif state == "suspended":
- self.fields["bug_status"] = "SUSPENDED"
- self.fields["resolution"] = ""
- elif state == "analyzed" and self.fields["userid"] == 3:
- self.fields["bug_status"] = "NEW"
- self.fields["resolution"] = ""
- else:
- self.fields["bug_status"] = "UNCONFIRMED"
- self.fields["resolution"] = ""
- self.fields["bug_status"] = SqlQuote(self.fields["bug_status"])
- self.fields["resolution"] = SqlQuote(self.fields["resolution"])
- self.fields["creation_ts"] = ""
- if self.fields.has_key("Arrival-Date") and self.fields["Arrival-Date"] != "":
- self.fields["creation_ts"] = unixdate2datetime(self.fields["Arrival-Date"])
- self.fields["creation_ts"] = SqlQuote(self.fields["creation_ts"])
- self.fields["delta_ts"] = ""
- if self.fields.has_key("Audit-Trail"):
- result = lastdatere.findall(self.fields["Audit-Trail"])
- result.reverse()
- if len(result) > 0:
- self.fields["delta_ts"] = unixdate2timestamp(result[0])
- if self.fields["delta_ts"] == "":
- if self.fields.has_key("Arrival-Date") and self.fields["Arrival-Date"] != "":
- self.fields["delta_ts"] = unixdate2timestamp(self.fields["Arrival-Date"])
- self.fields["delta_ts"] = SqlQuote(self.fields["delta_ts"])
- self.fields["short_desc"] = SqlQuote(self.fields["Synopsis"])
- if self.fields.has_key("Reply-To") and self.fields["Reply-To"] != "":
- self.fields["reporter"] = get_userid(self.fields["Reply-To"])
- elif self.fields.has_key("Mail-Header"):
- result = re.search(r"""From .*?([\w.]+@[\w.]+)""", self.fields["Mail-Header"])
- if result:
- self.fields["reporter"] = get_userid(result.group(1))
- else:
- self.fields["reporter"] = get_userid(gnats_username)
- else:
- self.fields["reporter"] = get_userid(gnats_username)
- long_desc = self.fields["Description"]
- long_desc2 = ""
- for field in ["Release", "Environment", "How-To-Repeat"]:
- if self.fields.has_key(field) and self.fields[field] != "":
- long_desc += ("\n\n%s:\n" % field) + self.fields[field]
- if self.fields.has_key("Fix") and self.fields["Fix"] != "":
- long_desc2 = "Fix:\n" + self.fields["Fix"]
- if self.need_unformatted == 1 and self.fields["Unformatted"] != "":
- long_desc += "\n\nUnformatted:\n" + self.fields["Unformatted"]
- if long_desc != "":
- self.long_descs.append((self.bug_id, self.fields["reporter"],
- self.fields["creation_ts"],
- SqlQuote(long_desc)))
- if long_desc2 != "":
- self.long_descs.append((self.bug_id, self.fields["reporter"],
- self.fields["creation_ts"],
- SqlQuote(long_desc2)))
- for field in ["gcchost", "gccbuild", "gcctarget"]:
- self.fields[field] = SqlQuote(self.fields[field])
- self.fields["version"] = ""
- if self.fields["Release"] != "":
- self.fields["version"] = convert_gccver_to_ver (self.fields["Release"])
- self.fields["version"] = SqlQuote(self.fields["version"])
- self.fields["product"] = SqlQuote("gcc")
- self.fields["component"] = "invalid"
- if self.fields.has_key("Category"):
- self.fields["component"] = self.fields["Category"]
- self.fields["component"] = SqlQuote(self.fields["component"])
- self.fields["target_milestone"] = "---"
- if self.fields["version"].find("3.4") != -1:
- self.fields["target_milestone"] = "3.4"
- self.fields["target_milestone"] = SqlQuote(self.fields["target_milestone"])
- if self.fields["userid"] == 2:
- self.fields["userid"] = "\'NULL\'"
- class GNATSbug(object):
- """ Represents a single GNATS PR """
- def __init__(self, filename):
- self.attachments = []
- self.has_unformatted_attach = 0
- fp = open (filename)
- self.fields = self.parse_pr(fp.xreadlines())
- self.bug_id = int(self.fields["Number"])
- if self.fields.has_key("Unformatted"):
- self.find_gnatsweb_attachments()
- if self.fields.has_key("How-To-Repeat"):
- self.find_regular_attachments("How-To-Repeat")
- if self.fields.has_key("Fix"):
- self.find_regular_attachments("Fix")
- def get_attacher(fields):
- if fields.has_key("Reply-To") and fields["Reply-To"] != "":
- return get_userid(fields["Reply-To"])
- else:
- result = None
- if fields.has_key("Mail-Header"):
- result = re.search(r"""From .*?([\w.]+\@[\w.]+)""",
- fields["Mail-Header"])
- if result is not None:
- reporter = get_userid(result.group(1))
- else:
- reporter = get_userid(gnats_username)
- get_attacher = staticmethod(get_attacher)
- def find_regular_attachments(self, which):
- fields = self.fields
- while re.search("^begin [0-7]{3}", fields[which],
- re.DOTALL | re.MULTILINE):
- outfp = cStringIO.StringIO()
- infp = cStringIO.StringIO(fields[which])
- filename, start, end = specialuu.decode(infp, outfp, quiet=0)
- fields[which]=fields[which].replace(fields[which][start:end],
- "See attachments for %s\n" % filename)
- self.attachments.append((filename, outfp.getvalue(),
- self.get_attacher(fields)))
- def decode_gnatsweb_attachment(self, attachment):
- result = re.split(r"""\n\n""", attachment, 1)
- if len(result) == 1:
- return -1
- envelope, body = result
- envelope = uselessre.split(envelope)
- envelope.pop(0)
- # Turn the list of key, value into a dict of key => value
- attachinfo = dict([(envelope[i], envelope[i+1]) for i in xrange(0,len(envelope),2)])
- for x in attachinfo.keys():
- attachinfo[x] = attachinfo[x].rstrip()
- if (attachinfo.has_key("Content-Type") == 0) or \
- (attachinfo.has_key("Content-Disposition") == 0):
- raise ValueError, "Unable to parse file attachment"
- result = dispositionre.search(attachinfo["Content-Disposition"])
- filename = result.group(2)
- filename = re.sub(".*/","", filename)
- filename = re.sub(".*\\\\","", filename)
- attachinfo["filename"]=filename
- result = re.search("""(\S+);.*""", attachinfo["Content-Type"])
- if result is not None:
- attachinfo["Content-Type"] = result.group(1)
- if attachinfo.has_key("Content-Transfer-Encoding"):
- if attachinfo["Content-Transfer-Encoding"] == "base64":
- attachinfo["data"] = base64.decodestring(body)
- else:
- attachinfo["data"]=body
- return (attachinfo["filename"], attachinfo["data"],
- self.get_attacher(self.fields))
- def find_gnatsweb_attachments(self):
- fields = self.fields
- attachments = re.split(attachment_delimiter, fields["Unformatted"])
- fields["Unformatted"] = attachments.pop(0)
- for attachment in attachments:
- result = self.decode_gnatsweb_attachment (attachment)
- if result != -1:
- self.attachments.append(result)
- self.has_unformatted_attach = 1
- def parse_pr(lines):
- #fields = {"envelope":[]}
- fields = {"envelope":array.array("c")}
- hdrmulti = "envelope"
- for line in lines:
- line = line.rstrip('\n')
- line += '\n'
- result = gnatfieldre.search(line)
- if result is None:
- if hdrmulti != "":
- if fields.has_key(hdrmulti):
- #fields[hdrmulti].append(line)
- fields[hdrmulti].fromstring(line)
- else:
- #fields[hdrmulti] = [line]
- fields[hdrmulti] = array.array("c", line)
- continue
- hdr, arg = result.groups()
- ghdr = "*not valid*"
- result = fieldnamere.search(hdr)
- if result != None:
- ghdr = result.groups()[0]
- if ghdr in fieldnames:
- if multilinefields.has_key(ghdr):
- hdrmulti = ghdr
- #fields[ghdr] = [""]
- fields[ghdr] = array.array("c")
- else:
- hdrmulti = ""
- #fields[ghdr] = [arg]
- fields[ghdr] = array.array("c", arg)
- elif hdrmulti != "":
- #fields[hdrmulti].append(line)
- fields[hdrmulti].fromstring(line)
- if hdrmulti == "envelope" and \
- (hdr == "Reply-To" or hdr == "From" \
- or hdr == "X-GNATS-Notify"):
- arg = fix_email_addrs(arg)
- #fields[hdr] = [arg]
- fields[hdr] = array.array("c", arg)
- if fields.has_key("Reply-To") and len(fields["Reply-To"]) > 0:
- fields["Reply-To"] = fields["Reply-To"]
- else:
- fields["Reply-To"] = fields["From"]
- if fields.has_key("From"):
- del fields["From"]
- if fields.has_key("X-GNATS-Notify") == 0:
- fields["X-GNATS-Notify"] = array.array("c")
- #fields["X-GNATS-Notify"] = ""
- for x in fields.keys():
- fields[x] = fields[x].tostring()
- #fields[x] = "".join(fields[x])
- for x in fields.keys():
- if multilinefields.has_key(x):
- fields[x] = fields[x].rstrip()
- return fields
- parse_pr = staticmethod(parse_pr)
- load_index("%s/gnats-adm/index" % gnats_db_dir)
- load_categories("%s/gnats-adm/categories" % gnats_db_dir)
- load_responsible("%s/gnats-adm/responsible" % gnats_db_dir)
- get_userid(gnats_username)
- get_userid(unassigned_username)
- for x in pr_list:
- print "Processing %s..." % x
- a = GNATSbug ("%s/%s" % (gnats_db_dir, x))
- b = Bugzillabug(a)
- write_non_bug_tables()
- outfile.close()
|