~mdz/apport/ubuntu-bugpatterns-combined

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
#!/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 launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT
from launchpadlib.credentials import Credentials
from launchpadlib.errors import HTTPError

import apport
import optparse
import sys
import os
import tempfile

def connect(use_edge=True):
    cachedir = os.path.expanduser('~/.launchpadlib/cache')
    if not os.path.exists(cachedir):
        os.makedirs(cachedir,0700)

    if use_edge:
        root = EDGE_SERVICE_ROOT
        credfile = os.path.expanduser('~/.launchpadlib/credentials')
    else:
        root = 'https://api.launchpad.net/beta/'
        credfile = os.path.expanduser('~/.launchpadlib/credentials-lpnet')
    try:
        credentials = Credentials()
        credentials.load(open(credfile))
        launchpad = Launchpad(credentials, root, cachedir)
    except IOError:
        launchpad = Launchpad.get_token_and_login(sys.argv[0], root, cachedir)
        credfd = tempfile.NamedTemporaryFile(dir=os.path.dirname(credfile))
        launchpad.credentials.save(credfd)
        os.link(credfd.name, credfile)
        credfd.close()
    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]
    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, subject='')
        bug.duplicate_of = master
        bug.lp_save()
        print 'Modified LP: #%s' % ( task.bug.id )

parser = optparse.OptionParser(usage="usage: %prog -p PACKAGE -t TAGS [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 TAGS", 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("-C", "--consolidate", help="Mark bugs as duplicate of master bug in pattern", dest="consolidate", action="store_true")

(opt, args) = parser.parse_args()

# Connect to Launchpad
lp = connect()

status_list = []
tags_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:
    package = ubuntu.getSourcePackage(name='%s' % opt.package)
elif not opt.package:
    print >> sys.stderr, ("A package is required.")
    sys.exit(1)

if opt.tags:
    tags_list.append(opt.tags)
elif not opt.tags:
    print >> sys.stderr, ("Tags are required at this point in time.  Aborting")
    sys.exit(1)

if opt.dupes:
    dupes = False
elif not opt.dupes:
    dupes = True

if opt.keywords:
    tasks = package.searchTasks(search_text=opt.keywords,status=status_list,order_by='-datecreated',tags=tags_list,omit_duplicates=dupes)
else:
    tasks = package.searchTasks(status=status_list,order_by='-datecreated',tags=tags_list,omit_duplicates=dupes)

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

    try:
        match = report.search_bug_patterns('.')
    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: Matched bug pattern: %s' % ( task.bug.id, match )
        if opt.consolidate:
            if task.bug.duplicate_of:
                print 'LP: #%s is already a duplicate of another bug' % (bug.id)
                break
            mark_as_duplicate(master_number, task.bug)
    elif match and opt.quiet:
        print '%s' % ( task.bug.id )