On Tue, Apr 07, 2009 at 12:18:03AM -0400, Geir Ove Myhr wrote:
> We both agree that tagging a bug with the ubuntu version(s) where the
> bug exist is useful. Others may think this is a bad idea.
It can't hurt, and in fact it could provide information that may be of
use for e.g. tracking down when the bug first appeared.
I generally consider non-targeted bugs that are open as existing in the
current development version until proven otherwise. If a bug only
affects, say, Hardy, I'll close the bug and sometimes open a task
against hardy if it seems warranted (e.g. if the reporter clearly wishes
to see the bug fixed in the LTS.)
> We also both think it makes sense to add the tags "intel" and "xorg"
> to all the bug reports. Within the scope of this package this is
> redundant, but many bugs originally reported for -intel may end up
> being in mesa, the kernel, xorg-server, etc. and the tags would then
> indicate that the bug affects intel chipsets and that it causes
> problem in xorg. Besides, people often add these tags anyway. Current
> status: intel: 133/267, xorg: 120/267.
I don't have a strong feeling either way on this.
> The point where we diverge is for tags identifying the hardware on
> which the bug is reported. Carey has been using the graphics core
> (gma900, gma950, gma3000, gma3100, gmaX3000, gmaX3100, gmaX3500, and
> gmaX4500, currently 18 bugs tagged), while I have been using the short
> name from http://intellinuxgraphics.org/documentation.html , which is
> what is reported as the chipset in Xorg.0.log (845g, 855gm, 865g,
> 915gm, 915g, 945gm, 945g, 946gz, 965q, 965g, 965gm, g33, q33, g35,
> q35, gm45, q45, and g45, 110/267 open bugs). Of course, we both favour
> our own scheme ;-)
Mapping based on the graphics core may be more accurate, but I'm not
certain. I would find the latter scheme more comfortable, since I'm
more familiar with the chipset short names. However, I prefer putting
the short names in the bug title (upstream requires it anyway, plus it
makes it a bit easier visually when reviewing reports, and it can help
cut down on me-too-ism), so maybe that is redundant with tagging.
> Finally, a set of tags for tossing bugs with similar problems in the
> same bin: crash, corruption, ghost-monitor, dual-head, edid, 3d,
> video, compiz, resolution, suspend, hibernate, resume, hang,
> performance are currently applied tags that come to my mind.
I really like this idea; it could very much help in tracking down
dupes. Also, when fixing bugs I like to look at other bugs that share
the same symptom since often I can use the same approach to fix them as
well. A few comments -
'video' is a bit ambiguous, as it could me "graphics" in general, or
"video playback ala Xv", or "SVideo output". I'd suggest using more
specific tag names here.
suspend, hibernate, resume tend to all basically mean the same thing. I
would lump them together personally.
hang / freeze / lockup are all typically used as synonyms. I think I'd
prefer 'freeze' over hang. "lockup" would imply a GPU lockup - which is
a common bug but not all freezes are the GPU.
For additional ideas on tags, maybe see the Troubleshooting X wiki.
> If this makes sense to the rest of you, I can write a wiki page with
> currently used Xorg tags.
I like it. I would suggest for sake of consistency, that we make sure
there is good correspondance with the Troubleshooting pages. So if a
bug is tagged 'foobar', we should have a troubleshooting guide for
'foobar' issues.
> For other drivers, the hardware tags would
> be different of course. I guess for -ati one could use r100, r200,
> r300, r400, r500, r600, r700 and rs690 (taken from
> http://wiki.x.org/wiki/RadeonProgram).
>
> Any thoughts on this, especially the core vs. chipset question?
As with Intel, I've also been putting the chipset name into the title,
and this has already had good results (I spent about a month on -ati
bugs and sorted a ton out via chipset correlation).
> PS: As of last week it was easy to get an overview of all the used
> tags, since they would all be shown on
> https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bugs
> . Now that only the most popular unofficial tags are shown, I don't
> know how to list all tags used for a package, so I may have missed
> some "active" tags in the above lists.
Wouldn't be too hard to write a launchpadlib script to list these out.
Attached is a script I wrote that does sort of the reverse - given a tag
and one or more source packages, list the bugs with that tag. Output
looks like this:
$ ./ls-tag.py hang xserver-xorg-video-intel
Atttempting to reuse existing credentials
== Bugs tagged 'hang' ==
=== xserver-xorg-video-intel ===
320821 Incomplete [i945GM] After loading background crashes back to GDM.
Works with 'driver "vesa"'.
312776 Incomplete [965GM] Intrepid RuneScape Fullscreen 3D Java Applet Crashes
X
321491 Confirmed [i915gm] Intrepid: Error in I830WaitLpRing
322613 Incomplete [945gme] Intrepid Xorg crashed coming out of screensaver -
log shows "[mi] EQ overflowing. The server is probably stuck in an infinite
loop."
328918 Incomplete [i945] underrun on pipe A! prevents Xorg from starting.
331596 Incomplete [i965] intel GM965/GL960 causes system hang when triple
buffer On after resume
337243 Confirmed [gma3100] X.org crash on Intel 82G33/G31 (with stacktrace)
339982 Confirmed [GMA950] X hangs for no apparent reason
340652 Incomplete [Intel] Jaunty desktop liveCD freezes on Intel iMacs on boot
340964 Confirmed [i915] Brightness change crashes X
10 total bugs tagged 'hang'
Bryce
#!/usr/bin/python
from arsenal_lib import *
if len(sys.argv) < 2:
sys.stderr.write("Usage: " + sys.argv[0] + " <tag> <source-package>")
exit(1)
total_count = 0
tag = sys.argv[1]
source_pkgs = sys.argv[2:]
arsenal = Arsenal()
d = arsenal.load_project("ubuntu")
print "== Bugs tagged '" + tag + "' =="
for source_pkg in source_pkgs:
count = 0
print "=== " + source_pkg + " ==="
for bugtask in d.searchTasks(search_text=source_pkg, tags=tag):
if bugtask.bug_target_display_name != source_pkg + " (Ubuntu)":
continue
bug = ArsenalBug(bugtask.bug, arsenal.launchpad)
print bug.id, " " + bugtask.status + " " + bug.title
count += 1
total_count += 1
print total_count, " total bugs tagged '" + tag + "'"
''' Miscellaneous Arsenal routines
This contains general purpose Arsenal code
Copyright (C) 2008 Canonical Lt.
Author: Bryce Harrington <[email protected]>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See http://www.gnu.org/copyleft/gpl.html for
the full text of the license.
'''
import re, os, sys
import time, datetime
from urllib2 import URLError, HTTPError
import httplib2
# TODO: Provide mechanism for selecting the testing service rather than edge
from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT
from launchpadlib.errors import HTTPError
from launchpadlib.credentials import Credentials
service_root = EDGE_SERVICE_ROOT
#service_root = "https://api.launchpad.net"
# TODO: Merge code ideas from other lpl users
# TODO: Remove use of first bugtask for some items
# TODO: Add ''' ''' code docs for all functions
# TODO: Separate the Xorg-specific stuff into a separate library file
class Arsenal:
''' High level interface to launchpad '''
def __init__(self):
''' Construct Arsenal object, including obtaining launchpad credentials '''
self.project_name = ""
home = os.path.expanduser('~')
self.name = 'arsenal'
''' Config dir '''
self.confdir = os.path.join(home, '.config', self.name)
if not os.path.exists(self.confdir):
# TODO: Create a dbgmsg type routine for controlling verbosity
print "Creating .config dir"
os.makedirs(self.confdir)
''' Cache dir '''
self.cachedir = os.path.join(home, '.cache', self.name)
if not os.path.exists(self.cachedir):
print "Creating cache dir"
os.makedirs(self.cachedir,0700)
return self.get_creds()
def get_creds(self):
''' Credentials '''
retrieve_credentials = False
# TODO: Should lp-credentials.txt be $script.cred ?
self.credentials_file = os.path.join(self.confdir, "lp-credentials.txt")
if not os.path.exists(self.credentials_file):
print "No existing credentials - need to create new ones"
retrieve_credentials = True
else:
print "Atttempting to reuse existing credentials"
try:
credentials = Credentials()
credentials.load(open(self.credentials_file))
self.launchpad = Launchpad(credentials, service_root, self.cachedir)
except:
print "Error: Launchpad failed to give credentials"
retrieve_credentials = True
if retrieve_credentials:
print "Retrieving credentials from launchpad for",self.name,"to",self.cachedir
self.launchpad = Launchpad.get_token_and_login(self.name, service_root, self.cachedir)
credfd = open(self.credentials_file, "w")
os.chmod(self.credentials_file, 0600)
self.launchpad.credentials.save(credfd)
credfd.close()
return
def reset(self):
self.get_creds()
if self.project_name:
self.load_project(self.project_name)
def Debug(self, level):
httplib2.debuglevel = level
def load_project(self, project):
tries = 3
while tries > 0:
tries -= 1
try:
self.project = self.launchpad.load("https://api.edge.launchpad.net/beta/" + project)
tries = 0
except:
print "*** Error: Exception cast loading project",project,"***"
self.project_name = project
return self.project
# TODO: Support positional parameters
def new_bug(self, package, title, description):
# TODO: Allow setting status, etc.
target = self.launchpad.load(self.project.self_link + "/+source/" + package);
bug_url = self.launchpad.bugs.createBug(
target = target,
title = title,
description = description)
return ArsenalBug(bug_url, self.launchpad)
def get_bug(self, bug_number):
return self.launchpad.bugs[bug_number]
class ArsenalBug:
''' Wrapper around launchpadlibs bug object '''
# TODO: Really want to wrapper a bug_task?
def __init__(self, bug, launchpad):
self.bug = bug
self.bug_tasks = bug.bug_tasks
self.id = bug.id
self.title = bug.title.encode('utf-8')
self.attachments = bug.attachments
self.description = bug.description.encode('utf-8')
self.owner = bug.owner
self.owner_firstname = self.owner.name.split(' ')[0]
self.launchpad = launchpad
return
def has_attachment(self, filename):
# TODO: Implement
# TODO: Maybe use regex for detection?
return False
def has_tag(self, tag):
return tag in self.bug.tags
def append_tag(self, tag):
id = self.id
if not tag in self.bug.tags:
#self.bug.tags.append(tag)
# Workaround bug #254901
self.bug = self.launchpad.load("https://api.edge.launchpad.net/beta/bugs/%d" % (id))
tag_list = self.bug.tags
tag_list.append(tag)
self.bug.tags = tag_list
print " ---> Tagged ",tag
# Workaround bug #336866
self.bug.lp_save()
# Reload bug
self.bug = self.launchpad.load("https://api.edge.launchpad.net/beta/bugs/%d" % (id))
return True
return False
def remove_tag(self, tag):
if tag in self.bug.tags:
# Workaround bug #254901
tag_list = self.bug.tags
tag_list.append(tag)
self.bug.tags = tag_list
# Workaround bug #336866
id = self.bug.id
self.bug.lp_save()
# Reload bug
self.bug = self.launchpad.load("https://api.edge.launchpad.net/beta/bugs/%d" % (id))
print " ---> Removed tag ",tag
return True
return False
def append_description(self, text):
self.bug.description = self.bug.description + "\n" + text
def append_comment(self, message):
# First doublecheck that we've not posted this comment before, so
# automated calls to this routine don't end up spamming the reporter
for m in self.bug.messages:
if m.content == message:
print " ---> Seems to already have this message"
return
self.bug.newMessage(subject = "Re: "+self.title, content = message)
return True
# These affect only bug_task, not bug
# def status(self, status):
# self.bug_task.transitionToStatus(status = status)
# return self.bug_task.status
# def importance(self, importance):
# self.bug_task.transitionToImportance(importance = importance)
# return self.bug_task.importance
def subscribe(self, subscriber):
person = self.launchpad.load('https://api.edge.launchpad.net/beta/~' + subscriber)
self.bug.subscribe(person = person)
return True
def dupe(self, dupe):
self.bug.duplicate_of = dupe
self.bug.lp_save()
# # Reload bug
# self.bug = self.launchpad.load("https://api.edge.launchpad.net/beta/bugs/%d" % (id))
return True
def subscribe(self, lp_id):
print "bug " + str(bug.id) + ": subscribing " + lp_id.display_name
self.bug.subscribe(person=lp_id)
def unsubscribe(self, lp_id):
# this currently does not work due to
# https://bugs.launchpad.net/malone/+bug/281028
print "bug " + str(self.bug.id) + ": unsubscribing " + lp_id.display_name
self.bug.unsubscribe(person=lp_id)
def age(self):
''' Age of bug in days '''
# now = datetime.datetime.now()
# dlm_str = self.bug.date_created.split('.')[0]
# dlm = datetime.datetime(*(time.strptime(dlm_str, "%Y-%m-%dT%H:%M:%S")[0:6]))
dlm = self.bug.date_created
now = dlm.now(dlm.tzinfo)
return (now - dlm).days
def age_last_message(self):
''' Age of last comment to bug in days '''
# now = datetime.datetime(now(), timezone=True)
# dlm_str = self.bug.date_last_message.split('.')[0]
# dlm = datetime.datetime(*(time.strptime(dlm_str, "%Y-%m-%dT%H:%M:%S")[0:6]))
dlm = self.bug.date_last_message
now = dlm.now(dlm.tzinfo)
return (now - dlm).days
def age_last_updated(self):
''' Age of last update to bug in days '''
# now = datetime.datetime.now()
# dlm_str = self.bug.date_last_updated.split('.')[0]
# dlm = datetime.datetime(*(time.strptime(dlm_str, "%Y-%m-%dT%H:%M:%S")[0:6]))
dlm = self.bug.date_last_updated
now = dlm.now(dlm.tzinfo)
return (now - dlm).days
# TODO: Need a class specifically for backtraces
# TODO: Review and adapt ideas from apport
def has_multiline_backtrace(text):
'''
Detects if there is a backtrace at least 3 levels deep
'''
regex_0 = re.compile('^#0 \w+')
regex_1 = re.compile('^#1 0x\d+')
regex_2 = re.compile('^#2 0x\d+')
return regex_0.search(text) and \
regex_1.search(text) and \
regex_2.search(text)
def has_full_backtrace(text):
'''
Detects if backtrace contains parameter values
'''
regex = re.compile('^#\d+ 0x\d+ in \w+ \(\s+.*\)')
regex_param = re.compile('^\s+\w+ = .+')
return regex.search(text) and \
regex_param.search(text)
def has_truncated_backtrace(text):
'''
Detects if the text has at least one line with a function name only
'''
regex = re.compile('^#\d+ 0x\d+ in \w+ \(\)$')
return regex.search(text)
def has_xorg_backtrace(text):
'''
Matches the typical Xorg.0.log backtrace, even if no symbols are installed
'''
regex_symbolless = re.compile('^#\d+: [\w\/\.]+ \[0x[0-9a-f]+\]')
regex_symbolled = re.compile('^#\d+: [\w\/\.]+\(.+\) \[0x[0-9a-f]+\]')
return regex_symbolless.search(text) or \
regex_symbolled.search(text)
def has_backtrace(text):
'''
General purpose check for presence of a backtrace of any format
'''
return has_xorg_backtrace(text) or \
has_multiline_backtrace(text)
# TODO:
# * Routine for comparing two backtraces and judging if they're equivalent
# -> Then a script could identify them as potential dupes
# * Parser to break a whole stack trace down into constituent pieces
# * Of a set of routines, identify the first one in actual X code
# * Identify crashes that seem to be kernel vs. driver vs. mesa vs. X
# * Extract code snippets for each function in the stacktrace
# * Spot null pointers or other irregular looking pointers
# * Tool to delete CoreDump.gz and un-privatize crash bugs with valid backtraces
# * Script to extract backtrace text and put into description
# * Add code to process-* scripts to identify crash bugs that lack
# full backtraces, and guide the user to collect them
def dump_launchpad_object(i):
print repr(i)
print " attr: ", sorted(i.lp_attributes)
print " ops: ", sorted(i.lp_operations)
print " coll: ", sorted(i.lp_collections)
print " entr: ", sorted(i.lp_entries)
print
--
Ubuntu-x mailing list
[email protected]
Modify settings or unsubscribe at:
https://lists.ubuntu.com/mailman/listinfo/ubuntu-x