~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/canonical/launchpad/scripts/debsync.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-08-03 06:48:37 UTC
  • mfrom: (13589.2.2 kill-cruft)
  • Revision ID: launchpad@pqm.canonical.com-20110803064837-goo26rutec1opzlj
[r=stevenk][no-qa] Dig a shallow grave for debsync and the bugzilla
 importer.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
 
# GNU Affero General Public License version 3 (see the file LICENSE).
3
 
 
4
 
"""Functions related to the import of Debbugs bugs into Malone."""
5
 
 
6
 
__all__ = [
7
 
    'bug_filter',
8
 
    'do_import',
9
 
    'import_bug',
10
 
    ]
11
 
 
12
 
__metaclass__ = type
13
 
 
14
 
import datetime
15
 
import sys
16
 
 
17
 
from zope.component import getUtility
18
 
 
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 (
23
 
    CreateBugParams,
24
 
    IBugSet,
25
 
    )
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 (
31
 
    IMessageSet,
32
 
    InvalidEmailMessage,
33
 
    UnknownSender,
34
 
    )
35
 
 
36
 
 
37
 
def bug_filter(bug, previous_import_set, target_bugs, target_package_set,
38
 
    minimum_age):
39
 
    """Function to choose which debian bugs will get processed by the sync
40
 
    script.
41
 
    """
42
 
    # don't re-import one that exists already
43
 
    if str(bug.id) in previous_import_set:
44
 
        return False
45
 
    # if we've been given a list, import only those
46
 
    if target_bugs:
47
 
        if bug.id in target_bugs:
48
 
            return True
49
 
        return False
50
 
    # we only want bugs in Sid
51
 
    if not bug.affects_unstable():
52
 
        return False
53
 
    # and we only want RC bugs
54
 
    #if not bug.is_release_critical():
55
 
    #    return False
56
 
    # and we only want bugs that affect the packages we care about:
57
 
    if not bug.affects_package(target_package_set):
58
 
        return False
59
 
    # we will not import any dup bugs (any reason to?)
60
 
    if len(bug.mergedwith) > 0:
61
 
        return False
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):
65
 
        return False
66
 
    return True
67
 
 
68
 
 
69
 
def do_import(logger, max_imports, debbugs_location, target_bugs,
70
 
    target_package_set, previous_import_set, minimum_age, debbugs_pl):
71
 
 
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))
78
 
 
79
 
    # find the new bugs to import
80
 
    logger.info('Selecting new debian bugs...')
81
 
    debbugs_db = debbugs.Database(debbugs_location, debbugs_pl)
82
 
    debian_bugs = []
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))
88
 
 
89
 
    # put them in ascending order
90
 
    logger.info('Sorting bugs...')
91
 
    debian_bugs.sort(lambda a, b: cmp(a.id, b.id))
92
 
 
93
 
    logger.info('Importing bugs...')
94
 
    newbugs = 0
95
 
    for debian_bug in debian_bugs:
96
 
        newbug = import_bug(debian_bug, logger)
97
 
        if newbug is True:
98
 
            newbugs += 1
99
 
        if max_imports:
100
 
            if newbugs >= max_imports:
101
 
                logger.info('Imported %d new bugs!' % newbugs)
102
 
                break
103
 
 
104
 
 
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)
112
 
        return False
113
 
    # get the email which started it all
114
 
    try:
115
 
        email_txt = debian_bug.comments[0]
116
 
    except IndexError:
117
 
        logger.error('No initial mail for debian #%d' % debian_bug.id)
118
 
        return False
119
 
    except debbugs.LogParseFailed, e:
120
 
        logger.warning(e)
121
 
        return False
122
 
    msg = None
123
 
    messageset = getUtility(IMessageSet)
124
 
    debian = getUtility(ILaunchpadCelebrities).debian
125
 
    ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
126
 
    try:
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)
133
 
    if msg is None:
134
 
        logger.error('Failed to import debian #%d' % debian_bug.id)
135
 
        return False
136
 
 
137
 
    # get the bug details
138
 
    title = debian_bug.subject
139
 
    if not title:
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():
148
 
        try:
149
 
            srcpkg = ubuntu.guessPublishedSourcePackageName(pkgname)
150
 
        except NotFoundError:
151
 
            logger.error(sys.exc_value)
152
 
    if srcpkg is None:
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' % (
157
 
            debian_bug.package))
158
 
        return False
159
 
    # sometimes debbugs has initial emails that contain the package name, we
160
 
    # can remove that
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),
170
 
        malone_bug.owner)
171
 
    thewatch.remotestatus = debian_bug.status
172
 
 
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)
179
 
 
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))
183
 
 
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))
189
 
 
190
 
    # and also for CVE ref clues
191
 
    cveset = getUtility(ICveSet)
192
 
    cves = cveset.inMessage(msg)
193
 
    prior_cves = malone_bug.cves
194
 
    for cve in 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))
199
 
 
200
 
    flush_database_updates()
201
 
    return True