def cmp(x, y): if x == y: return 0 if x == '': if y == None: return -1 else: return 1 if y == '': if x == None: return 1 else: return -1 if x == None: return 1 if y == None: return -1 return packaging.compare_versions(x, y)
def check_duplicate(self, id, report=None): '''Check whether a crash is already known. If the crash is new, it will be added to the duplicate database and the function returns None. If the crash is already known, the function returns a pair (crash_id, fixed_version), where fixed_version might be None if the crash is not fixed in the latest version yet. Depending on whether the version in report is smaller than/equal to the fixed version or larger, this calls close_duplicate() or mark_regression(). If the report does not have a valid crash signature, this function does nothing and just returns None. By default, the report gets download()ed, but for performance reasons it can be explicitly passed to this function if it is already available. ''' assert self.duplicate_db, 'init_duplicate_db() needs to be called before' if not report: report = self.download(id) self._mark_dup_checked(id, report) if 'DuplicateSignature' in report: sig = report['DuplicateSignature'] else: sig = report.crash_signature() if not sig: return None existing = self._duplicate_search_signature(sig, id) # sort existing in ascending order, with unfixed last, so that # version comparisons find the closest fix first def cmp(x, y): if x == y: return 0 if x == '': if y == None: return -1 else: return 1 if y == '': if x == None: return 1 else: return -1 if x == None: return 1 if y == None: return -1 return packaging.compare_versions(x, y) existing.sort(cmp, lambda k: k[1]) if existing: # update status of existing master bugs for (ex_id, _) in existing: self._duplicate_db_sync_status(ex_id) existing = self._duplicate_search_signature(sig, id) existing.sort(cmp, lambda k: k[1]) if not existing: # add a new entry cur = self.duplicate_db.cursor() cur.execute('INSERT INTO crashes VALUES (?, ?, ?, CURRENT_TIMESTAMP)', (_u(sig), id, None)) self.duplicate_db.commit() return None try: report_package_version = report['Package'].split()[1] except (KeyError, IndexError): report_package_version = None # search the newest fixed id or an unfixed id to check whether there is # a regression (crash happening on a later version than the latest # fixed one) for (ex_id, ex_ver) in existing: if not ex_ver or \ not report_package_version or \ packaging.compare_versions(report_package_version, ex_ver) < 0: self.close_duplicate(id, ex_id) break else: # regression, mark it as such in the crash db self.mark_regression(id, ex_id) # create a new record cur = self.duplicate_db.cursor() cur.execute('INSERT INTO crashes VALUES (?, ?, ?, CURRENT_TIMESTAMP)', (_u(sig), id, None)) self.duplicate_db.commit() # we now track this as a new crash return None return (ex_id, ex_ver)