1
# Copyright 2009 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Functions related to the import of Debbugs bugs into Malone."""
17
from zope.component import getUtility
19
from canonical.database.sqlbase import flush_database_updates
20
from lp.app.errors import NotFoundError
21
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
22
from lp.bugs.interfaces.bug import (
26
from lp.bugs.interfaces.bugwatch import IBugWatchSet
27
from lp.bugs.interfaces.cve import ICveSet
28
from lp.bugs.scripts import debbugs
29
from lp.services.encoding import guess as ensure_unicode
30
from lp.services.messages.interfaces.message import (
37
def bug_filter(bug, previous_import_set, target_bugs, target_package_set,
39
"""Function to choose which debian bugs will get processed by the sync
42
# don't re-import one that exists already
43
if str(bug.id) in previous_import_set:
45
# if we've been given a list, import only those
47
if bug.id in target_bugs:
50
# we only want bugs in Sid
51
if not bug.affects_unstable():
53
# and we only want RC bugs
54
#if not bug.is_release_critical():
56
# and we only want bugs that affect the packages we care about:
57
if not bug.affects_package(target_package_set):
59
# we will not import any dup bugs (any reason to?)
60
if len(bug.mergedwith) > 0:
62
# and we won't import any bug that is newer than one week, to give
63
# debian some time to find dups
64
if bug.date > datetime.datetime.now() - datetime.timedelta(minimum_age):
69
def do_import(logger, max_imports, debbugs_location, target_bugs,
70
target_package_set, previous_import_set, minimum_age, debbugs_pl):
72
# figure out which bugs have been imported previously
73
debbugs_tracker = getUtility(ILaunchpadCelebrities).debbugs
74
for w in debbugs_tracker.watches:
75
previous_import_set.add(w.remotebug)
76
logger.info('%d debian bugs previously imported.' %
77
len(previous_import_set))
79
# find the new bugs to import
80
logger.info('Selecting new debian bugs...')
81
debbugs_db = debbugs.Database(debbugs_location, debbugs_pl)
83
for debian_bug in debbugs_db:
84
if bug_filter(debian_bug, previous_import_set, target_bugs,
85
target_package_set, minimum_age):
86
debian_bugs.append(debian_bug)
87
logger.info('%d debian bugs ready to import.' % len(debian_bugs))
89
# put them in ascending order
90
logger.info('Sorting bugs...')
91
debian_bugs.sort(lambda a, b: cmp(a.id, b.id))
93
logger.info('Importing bugs...')
95
for debian_bug in debian_bugs:
96
newbug = import_bug(debian_bug, logger)
100
if newbugs >= max_imports:
101
logger.info('Imported %d new bugs!' % newbugs)
105
def import_bug(debian_bug, logger):
106
"""Consider importing a debian bug, return True if you did."""
107
bugset = getUtility(IBugSet)
108
debbugs_tracker = getUtility(ILaunchpadCelebrities).debbugs
109
malone_bug = bugset.queryByRemoteBug(debbugs_tracker, debian_bug.id)
110
if malone_bug is not None:
111
logger.error('Debbugs #%d was previously imported.' % debian_bug.id)
113
# get the email which started it all
115
email_txt = debian_bug.comments[0]
117
logger.error('No initial mail for debian #%d' % debian_bug.id)
119
except debbugs.LogParseFailed, e:
123
messageset = getUtility(IMessageSet)
124
debian = getUtility(ILaunchpadCelebrities).debian
125
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
127
msg = messageset.fromEmail(email_txt, distribution=debian,
128
create_missing_persons=True)
129
except UnknownSender:
130
logger.error('Cannot create person for %s' % sys.exc_value)
131
except InvalidEmailMessage:
132
logger.error('Invalid email: %s' % sys.exc_value)
134
logger.error('Failed to import debian #%d' % debian_bug.id)
137
# get the bug details
138
title = debian_bug.subject
140
title = 'Debbugs #%d with no title' % debian_bug.id
141
title = ensure_unicode(title)
142
# debian_bug.package may have ,-separated package names, but
143
# debian_bug.packagelist[0] is going to be a single package name for
144
# sure. we work through the package list, try to find one we can
145
# work with, otherwise give up
146
srcpkg = pkgname = None
147
for pkgname in debian_bug.packagelist():
149
srcpkg = ubuntu.guessPublishedSourcePackageName(pkgname)
150
except NotFoundError:
151
logger.error(sys.exc_value)
153
# none of the package names gave us a source package we can use
154
# XXX sabdfl 2005-09-16: Maybe this should just be connected to the
155
# distro, and allowed to wait for re-assignment to a specific package?
156
logger.error('Unable to find package details for %s' % (
159
# sometimes debbugs has initial emails that contain the package name, we
161
if title.startswith(pkgname + ':'):
162
title = title[len(pkgname) + 2:].strip()
163
params = CreateBugParams(
164
title=title, msg=msg, owner=msg.owner,
165
datecreated=msg.datecreated)
166
params.setBugTarget(distribution=debian, sourcepackagename=srcpkg)
167
malone_bug = bugset.createBug(params)
168
# create a debwatch for this bug
169
thewatch = malone_bug.addWatch(debbugs_tracker, str(debian_bug.id),
171
thewatch.remotestatus = debian_bug.status
173
# link the relevant task to this watch
174
assert len(malone_bug.bugtasks) == 1, 'New bug should have only one task'
175
task = malone_bug.bugtasks[0]
176
task.bugwatch = thewatch
177
task.setStatusFromDebbugs(debian_bug.status)
178
task.setSeverityFromDebbugs(debian_bug.severity)
180
# Let the world know about it!
181
logger.info('%d/%s: %s: %s' % (
182
debian_bug.id, malone_bug.id, debian_bug.package, title))
184
# now we need to analyse the message for bugwatch clues
185
bugwatchset = getUtility(IBugWatchSet)
186
watches = bugwatchset.fromMessage(msg, malone_bug)
187
for watch in watches:
188
logger.info('New watch for %s on %s' % (watch.bug.id, watch.url))
190
# and also for CVE ref clues
191
cveset = getUtility(ICveSet)
192
cves = cveset.inMessage(msg)
193
prior_cves = malone_bug.cves
195
if cve not in prior_cves:
196
malone_bug.linkCVE(cve)
197
logger.info('CVE-%s (%s) found for Malone #%s' % (
198
cve.sequence, cve.status.name, malone_bug.id))
200
flush_database_updates()