1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
#!/usr/bin/python
# Author: Brian Murray <brian@canonical.com>
# Copyright (C) 2009 Canonical, Ltd.
# License: GPLv3
#
# Given a package name and some criteria query Launchpad for a bug list
# then check each bug against the package's bug pattern
#
# missing the ability to search for no tags
from apport.crashdb import get_crashdb
from datetime import datetime
from datetime import timedelta
from launchpadlib.launchpad import Launchpad
from launchpadlib.credentials import Credentials
from launchpadlib.errors import HTTPError
import apport
import optparse
import os
import re
import sys
import tempfile
def connect():
cachedir = os.path.expanduser('~/.launchpadlib/cache')
if not os.path.exists(cachedir):
os.makedirs(cachedir,0700)
root = 'production'
credfile = os.path.expanduser('~/.launchpadlib/credentials-lpnet')
launchpad = Launchpad.login_with(sys.argv[0], credentials_file=credfile,
service_root=root, launchpadlib_dir=cachedir, version="devel")
return launchpad
def mark_as_duplicate(master_number, bug):
comment="Thank you for taking the time to report this bug and helping to make Ubuntu better. This particular bug has already been reported and is a duplicate of bug %s, so it is being marked as such. Please look at the other bug report to see if there is any missing information that you can provide, or to see if there is a workaround for the bug. Additionally, any further discussion regarding the bug should occur in the other report. Please continue to report any other bugs you may find." % (master_number)
master = lp.bugs[master_number]
# 2011-02-17 this is redundant as it is built into LP (I think)
#if bug.duplicates:
# for duplicate in bug.duplicates:
# mark_as_duplicate(master_number, duplicate)
# print 'Taking care of a bug with duplicates'
# mark_as_duplicate(master_number, bug)
#else:
for task in bug.bug_tasks:
task.status = 'Confirmed'
bug.newMessage(content=comment)
bug.duplicate_of = master
bug.lp_save()
print 'Modified LP: #%s' % ( task.bug.id )
def trim_dpkg_log(report):
'''Trim DpkgTerminalLog to the most recent installation session.
Taken from apport data/general-hook/ubuntu.py'''
if 'DpkgTerminalLog' not in report:
return
lines = []
trim_re = re.compile('^\(.* ... \d+ .*\)$')
for line in report['DpkgTerminalLog'].splitlines():
if line.startswith('Log started: ') or trim_re.match(line):
lines = []
continue
lines.append(line)
report['DpkgTerminalLog'] = '\n'.join(lines)
parser = optparse.OptionParser(usage="usage: %prog -p PACKAGE -t TAG(s) "\
"[options]")
parser.add_option("-p", "--package", help="Filter on PACKAGE", dest="package",
metavar="PACKAGE")
parser.add_option("-s", "--status", help="Filter on STATUS", dest="status",
metavar="STATUS")
parser.add_option("-t", "--tags", help="Filter on TAG,TAG", dest="tags",
metavar="TAGS")
parser.add_option("-d", "--dupes", help="Include duplicates in search",
dest="dupes", action="store_true")
parser.add_option("-q", "--quiet", help="Only print bug numbers",
dest="quiet", action="store_true")
parser.add_option("-a", "--all", help="Check all package bugs", dest="all",
action="store_true")
parser.add_option("-k", "--keywords", help="Search for KEYWORDS",
dest="keywords", metavar="KEYWORDS")
parser.add_option("-w", "--within", help="Search for bugs reported within the past X days",
dest="within", metavar="WITHIN")
parser.add_option("-C", "--consolidate", dest="consolidate",
help="Mark bugs as duplicate of master bug in pattern",
action="store_true")
(opt, args) = parser.parse_args()
# Connect to Launchpad
lp = connect()
status_list = []
tag_list = []
ubuntu = lp.distributions['ubuntu']
valid_status = ['New', 'Incomplete', 'Invalid', "Won't Fix", 'Confirmed',
'Triaged', 'In Progress', 'Fix Committed', 'Fix Released',
'Unknown']
if not opt.status:
status_list = ['New', 'Incomplete', 'Confirmed', 'Triaged',
'In Progress', 'Fix Committed' ]
elif opt.status:
if opt.status not in valid_status:
print >> sys.stderr, ("Invalid status '%s'. Aborting") % (opt.status)
sys.exit(1)
else:
status_list.append(opt.status)
if opt.package == 'ubuntu':
package = ubuntu
if opt.package != 'ubuntu':
package = ubuntu.getSourcePackage(name='%s' % opt.package)
elif not opt.package:
print >> sys.stderr, ("A package is required.")
sys.exit(1)
if opt.dupes:
dupes = False
elif not opt.dupes:
dupes = True
if opt.tags:
for tag in opt.tags.split(','):
tag_list.append(tag)
if opt.within:
period = int(opt.within)
today = datetime.utcnow()
search_start = today - timedelta(period)
elif not opt.within:
search_start = None
search_args = {'tags': tag_list,
'tags_combinator': 'All',
'order_by': '-datecreated',
'status': opt.status,
'search_text': opt.keywords,
'omit_duplicates': dupes,
'created_since': search_start}
tasks = package.searchTasks(**search_args)
for task in tasks:
# they should be retraced first
if 'need-i386-retrace' in task.bug.tags or 'need-amd64-retrace' in task.bug.tags:
continue
db = get_crashdb(None)
try:
report = db.download(task.bug.id)
except AssertionError, error:
print "LP: #%s: %s" % (task.bug.id, error)
continue
except Exception, error:
print "LP: #%s: %s" % (task.bug.id, error)
continue
# trim the dpkg log file
trim_dpkg_log(report)
try:
match = report.search_bug_patterns('bugpatterns.xml')
except AssertionError, error:
print "%s" % error
continue
if match and not opt.quiet:
# this should handle wiki urls somehow
master_number = match.split('/')[-1]
if str(master_number) == str(task.bug.id) and not opt.all:
print "Reached master bug LP: #%s" % master_number
break
print 'LP: #%s (%s, %s): Matched bug pattern: %s' % (task.bug.id,
task.status, task.importance, match)
if opt.consolidate:
if task.bug.duplicate_of:
print 'LP: #%s is already a duplicate of another bug' % (task.bug.id)
break
elif int(task.bug.id) == int(master_number):
continue
mark_as_duplicate(master_number, task.bug)
elif match and opt.quiet:
print '%s' % (task.bug.id)
|