10637.3.1
by Guilherme Salgado
Use the default python version instead of a hard-coded version |
1 |
#!/usr/bin/python -S
|
8687.15.7
by Karl Fogel
Add the copyright header block to more files. |
2 |
#
|
3 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
|
4 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
5 |
|
6 |
# This script runs through the set of Debbugs watches, and tries to
|
|
7 |
# syncronise each of those to the malone bug which is watching it.
|
|
8 |
||
9641.1.4
by Gary Poster
more updates for _pythonpath. Still need to update all subprocess calls to python to use -S; still need to update z3c.recipe.filetemplate to provide sys.modules from -S run. |
9 |
import _pythonpath |
2450
by Canonical.com Patch Queue Manager
[r=jamesh] rework cve structure, and general polish |
10 |
import os |
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
11 |
import sys |
12 |
import email |
|
13 |
import logging |
|
14 |
||
15 |
# zope bits
|
|
16 |
from zope.component import getUtility |
|
17 |
||
8523.3.1
by Gavin Panella
Bugs tree reorg after automated migration. |
18 |
from lp.bugs.scripts import debbugs |
8356.1.1
by Leonard Richardson
Partial move. |
19 |
from lp.services.scripts.base import (LaunchpadCronScript, |
3691.348.19
by kiko
Two more scripts converted. |
20 |
LaunchpadScriptFailure) |
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
21 |
from canonical.launchpad.interfaces import (IBugSet, |
3691.348.1
by kiko
Remove the original lockfile class and use our contributed GlobalLock everywhere to avoid stale locks making our scripts stop to run. Update a bunch of scripts to use it. Hopefully backwards-compatible enough to survive tests. |
22 |
ILaunchpadCelebrities, InvalidEmailMessage, IBugTaskSet, |
3691.348.19
by kiko
Two more scripts converted. |
23 |
IBugWatchSet, IMessageSet, ICveSet, BugTaskSearchParams) |
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
24 |
from canonical.database.constants import UTC_NOW |
25 |
||
26 |
# setup core values and defaults
|
|
2450
by Canonical.com Patch Queue Manager
[r=jamesh] rework cve structure, and general polish |
27 |
debbugs_location_default = '/srv/bugs-mirror.debian.org/' |
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
28 |
|
3691.348.19
by kiko
Two more scripts converted. |
29 |
|
4264.2.1
by James Henstridge
add a LaunchpadCronScript subclass, and make cronscripts/*.py use it |
30 |
class DebWatchUpdater(LaunchpadCronScript): |
3691.348.19
by kiko
Two more scripts converted. |
31 |
loglevel = logging.WARNING |
32 |
||
33 |
def add_my_options(self): |
|
34 |
self.parser.add_option('--max', action='store', type='int', dest='max', |
|
35 |
default=None, help="The maximum number of bugs to synchronise.") |
|
36 |
self.parser.add_option('--debbugs', action='store', type='string', |
|
37 |
dest='debbugs', |
|
38 |
default=debbugs_location_default, |
|
39 |
help="The location of your debbugs database.") |
|
40 |
||
41 |
def main(self): |
|
42 |
if not os.path.exists(os.path.join(self.options.debbugs, 'index/index.db')): |
|
43 |
raise LaunchpadScriptFailure('%s is not a debbugs db.' |
|
44 |
% self.options.debbugs) |
|
45 |
||
46 |
self.txn.begin() |
|
47 |
self.debbugs_db = debbugs.Database(self.options.debbugs) |
|
48 |
self.sync() |
|
49 |
self.txn.commit() |
|
50 |
||
51 |
self.logger.info('Done!') |
|
52 |
||
53 |
def sync(self): |
|
54 |
changedcounter = 0 |
|
55 |
||
56 |
self.logger.info('Finding existing debbugs watches...') |
|
57 |
debbugs_tracker = getUtility(ILaunchpadCelebrities).debbugs |
|
58 |
debwatches = debbugs_tracker.watches |
|
59 |
||
60 |
previousimportset = set([b.remotebug for b in debwatches]) |
|
61 |
self.logger.info('%d debbugs previously imported.' % len(previousimportset)) |
|
62 |
||
63 |
target_watches = [watch for watch in debwatches if watch.needscheck] |
|
64 |
self.logger.info('%d debbugs watches to syncronise.' % len(target_watches)) |
|
65 |
||
66 |
self.logger.info('Sorting bug watches...') |
|
67 |
target_watches.sort(key=lambda a: a.remotebug) |
|
68 |
||
69 |
self.logger.info('Syncing bug watches...') |
|
70 |
for watch in target_watches: |
|
71 |
if self.sync_watch(watch): |
|
72 |
changedcounter += 1 |
|
73 |
self.txn.commit() |
|
74 |
if self.options.max: |
|
75 |
if changedcounter >= self.options.max: |
|
76 |
self.logger.info('Synchronised %d bugs!' % changedcounter) |
|
77 |
return
|
|
78 |
||
79 |
def sync_watch(self, watch): |
|
80 |
# keep track of whether or not something changed
|
|
81 |
waschanged = False |
|
82 |
# find the bug in malone
|
|
83 |
malone_bug = watch.bug |
|
84 |
# find the bug in debbugs
|
|
85 |
debian_bug = self.debbugs_db[int(watch.remotebug)] |
|
86 |
bugset = getUtility(IBugSet) |
|
87 |
bugtaskset = getUtility(IBugTaskSet) |
|
88 |
bugwatchset = getUtility(IBugWatchSet) |
|
89 |
messageset = getUtility(IMessageSet) |
|
90 |
debian = getUtility(ILaunchpadCelebrities).debian |
|
91 |
debbugs_tracker = getUtility(ILaunchpadCelebrities).debbugs |
|
92 |
||
93 |
# make sure we have tasks for all the debian package linkages, and also
|
|
94 |
# make sure we have updated their status and severity appropriately
|
|
95 |
for packagename in debian_bug.packagelist(): |
|
96 |
try: |
|
97 |
srcpkgname, binpkgname = debian.guessPackageNames(packagename) |
|
98 |
except ValueError: |
|
99 |
self.logger.error(sys.exc_value) |
|
100 |
continue
|
|
101 |
search_params = BugTaskSearchParams(user=None, bug=malone_bug, |
|
102 |
sourcepackagename=srcpkgname) |
|
103 |
search_params.setDistribution(debian) |
|
104 |
bugtasks = bugtaskset.search(search_params) |
|
105 |
if len(bugtasks) == 0: |
|
106 |
# we need a new task to link the bug to the debian package
|
|
107 |
self.logger.info('Linking %d and debian %s/%s' % ( |
|
108 |
malone_bug.id, srcpkgname.name, binpkgname.name)) |
|
4664.1.1
by Curtis Hovey
Normalized comments for bug 3732. |
109 |
# XXX: kiko 2007-02-03:
|
110 |
# This code is completely untested and broken.
|
|
3691.348.19
by kiko
Two more scripts converted. |
111 |
bugtask = malone_bug.addTask( |
112 |
owner=malone_bug.owner, distribution=debian, |
|
113 |
sourcepackagename=srcpkgname) |
|
114 |
bugtask.bugwatch = watch |
|
115 |
waschanged = True |
|
116 |
else: |
|
117 |
assert len(bugtasks) == 1, 'Should only find a single task' |
|
118 |
bugtask = bugtasks[0] |
|
119 |
status = bugtask.status |
|
120 |
if status <> bugtask.setStatusFromDebbugs(debian_bug.status): |
|
121 |
waschanged = True |
|
122 |
severity = bugtask.severity |
|
123 |
if severity <> bugtask.setSeverityFromDebbugs(debian_bug.severity): |
|
124 |
waschanged = True |
|
125 |
||
126 |
known_msg_ids = set([msg.rfc822msgid for msg in malone_bug.messages]) |
|
127 |
||
128 |
for raw_msg in debian_bug.comments: |
|
129 |
||
130 |
# parse it so we can extract the message id easily
|
|
131 |
message = email.message_from_string(raw_msg) |
|
132 |
||
133 |
# see if we already have imported a message with this id for this
|
|
134 |
# bug
|
|
135 |
message_id = message['message-id'] |
|
136 |
if message_id in known_msg_ids: |
|
137 |
# Skipping msg that is already imported
|
|
138 |
continue
|
|
139 |
||
140 |
# make sure this message is in the db
|
|
141 |
msg = None |
|
142 |
try: |
|
143 |
msg = messageset.fromEmail(raw_msg, parsed_message=message, |
|
144 |
create_missing_persons=True) |
|
145 |
except InvalidEmailMessage: |
|
146 |
self.logger.error('Invalid email: %s' % sys.exc_value) |
|
147 |
if msg is None: |
|
148 |
continue
|
|
149 |
||
150 |
# create the link between the bug and this message
|
|
151 |
bugmsg = malone_bug.linkMessage(msg) |
|
152 |
||
153 |
# ok, this is a new message for this bug, so in effect something has
|
|
154 |
# changed
|
|
155 |
waschanged = True |
|
156 |
||
157 |
# now we need to analyse the message for useful data
|
|
158 |
watches = bugwatchset.fromMessage(msg, malone_bug) |
|
159 |
for watch in watches: |
|
160 |
self.logger.info('New watch for #%s on %s' % (watch.bug.id, watch.url)) |
|
161 |
waschanged = True |
|
162 |
||
163 |
# and also for CVE ref clues
|
|
164 |
prior_cves = set(malone_bug.cves) |
|
165 |
cveset = getUtility(ICveSet) |
|
166 |
cves = cveset.inMessage(msg) |
|
167 |
for cve in cves: |
|
168 |
malone_bug.linkCVE(cve) |
|
169 |
if cve not in prior_cves: |
|
170 |
self.logger.info('CVE-%s (%s) found for Malone #%s' % ( |
|
171 |
cve.sequence, cve.status.name, malone_bug.id)) |
|
172 |
||
173 |
# now we know about this message for this bug
|
|
174 |
known_msg_ids.add(message_id) |
|
175 |
||
176 |
# and best we commit, so that we can see the email that the
|
|
177 |
# librarian has created in the db
|
|
178 |
self.txn.commit() |
|
179 |
||
180 |
# Mark all merged bugs as duplicates of the lowest-numbered bug
|
|
181 |
if (len(debian_bug.mergedwith) > 0 and |
|
182 |
min(debian_bug.mergedwith) > debian_bug.id): |
|
183 |
for merged_id in debian_bug.mergedwith: |
|
184 |
merged_bug = bugset.queryByRemoteBug(debbugs_tracker, merged_id) |
|
185 |
if merged_bug is not None: |
|
186 |
# Bug has been imported already
|
|
187 |
if merged_bug.duplicateof == malone_bug: |
|
188 |
# we already know about this
|
|
189 |
continue
|
|
190 |
elif merged_bug.duplicateof is not None: |
|
191 |
# Interesting, we think it's a dup of something else
|
|
192 |
self.logger.warning('Debbugs thinks #%d is a dup of #%d' % ( |
|
193 |
merged_bug.id, merged_bug.duplicateof)) |
|
194 |
continue
|
|
195 |
# Go ahead and merge it
|
|
196 |
self.logger.info("Malone #%d is a duplicate of Malone #%d" % ( |
|
197 |
merged_bug.id, malone_bug.id)) |
|
198 |
merged_bug.duplicateof = malone_bug.id |
|
199 |
||
200 |
# the dup status has changed
|
|
201 |
waschanged = True |
|
202 |
||
203 |
# make a note of the remote watch status, if it has changed
|
|
204 |
if watch.remotestatus <> debian_bug.status: |
|
205 |
watch.remotestatus = debian_bug.status |
|
206 |
waschanged = True |
|
207 |
||
208 |
# update the watch date details
|
|
209 |
watch.lastchecked = UTC_NOW |
|
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
210 |
if waschanged: |
3691.348.19
by kiko
Two more scripts converted. |
211 |
watch.lastchanged = UTC_NOW |
212 |
self.logger.info('Watch on Malone #%d changed.' % watch.bug.id) |
|
213 |
return waschanged |
|
214 |
||
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
215 |
|
216 |
if __name__ == '__main__': |
|
3691.348.19
by kiko
Two more scripts converted. |
217 |
script = DebWatchUpdater('launchpad-debbugs-sync') |
218 |
script.lock_and_run() |
|
2048
by Canonical.com Patch Queue Manager
debbugssync, hct enabling, and ui fixes. r=jamesh |
219 |