Skip to content

Commit caec6c1

Browse files
committed
Added specbugs.py in order to automatically generate section annotations.
1 parent f40e02d commit caec6c1

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed

bin/specbugs.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#!/usr/bin/env python
2+
#
3+
# Retrieves a bug list, parses the bug list for the
4+
import sys, os, os.path
5+
from optparse import OptionParser
6+
import urllib
7+
import getpass
8+
from xml.etree.ElementTree import parse
9+
10+
# BUGLIST URL:
11+
#http://www.w3.org/Bugs/Public/buglist.cgi?bug_file_loc=&bug_file_loc_type=allwordssubstr&bug_id=&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bugidtype=include&chfieldfrom=&chfieldto=Now&chfieldvalue=&component=HTML%2BRDFa%20%28editor%3A%20Manu%20Sporny%29&email1=&email2=&emailtype1=substring&emailtype2=substring&field-1-0-0=product&field-1-1-0=component&field-1-2-0=bug_status&field0-0-0=noop&keywords=&keywords_type=allwords&long_desc=&long_desc_type=allwordssubstr&product=HTML%20WG&query_format=advanced&remaction=&short_desc=&short_desc_type=allwordssubstr&status_whiteboard=&status_whiteboard_type=allwordssubstr&type-1-0-0=anyexact&type-1-1-0=anyexact&type-1-2-0=anyexact&type0-0-0=noop&value-1-0-0=HTML%20WG&value-1-1-0=HTML%2BRDFa%20%28editor%3A%20Manu%20Sporny%29&value-1-2-0=NEW%2CASSIGNED%2CREOPENED&value0-0-0=&votes=&ctype=csv
12+
13+
# BUG XML URL:
14+
#http://www.w3.org/Bugs/Public/show_bug.cgi?ctype=xml&id=8998
15+
16+
# Opens a W3C URL
17+
class W3CUrlOpener(urllib.FancyURLopener):
18+
def __init__(self):
19+
urllib.FancyURLopener.__init__(self)
20+
self.username = None
21+
self.password = None
22+
23+
def prompt_user_passwd(self, host, realm):
24+
print "Enter your username and password for the W3C Bug tracker"
25+
26+
if(self.username == None):
27+
self.username = getpass.getuser()
28+
self.password = getpass.getpass()
29+
30+
return (self.username, self.password)
31+
32+
##
33+
# Logs a string to the proper location (file or console)
34+
def log(str):
35+
print str
36+
37+
##
38+
# Sets up the option string parser for this script.
39+
#
40+
# @param argv the argument list specified on the command line.
41+
def setupParser(argv):
42+
usage = "usage: %prog [options]"
43+
parser = OptionParser(usage)
44+
45+
parser.add_option('-w', '--working-dir',
46+
action='store', dest='workingDir', default="dist",
47+
help='The working directory for the application. [Default: %default]')
48+
49+
parser.add_option('-s', '--spec',
50+
action='store', dest='specFile',
51+
help='The specification file to modify with the buglist.')
52+
53+
parser.add_option('-o', '--output-spec',
54+
action='store', dest='outFile',
55+
help='The output specification file.')
56+
57+
parser.add_option('-n', '--name',
58+
action='store', dest='specName',
59+
help='The name of the specification file.')
60+
61+
options, args = parser.parse_args(argv)
62+
largs = parser.largs
63+
64+
return (options, args, largs)
65+
66+
##
67+
# Adds the specification bug warnings
68+
def addSpecBugWarnings(argv, stdout, environ):
69+
(options, args, largs) = setupParser(argv)
70+
71+
component = "HTML+RDFa (editor: Manu Sporny)"
72+
quotedBugUrl = "http://www.w3.org/Bugs/Public/buglist.cgi?bug_file_loc=&bug_file_loc_type=allwordssubstr&bug_id=&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bugidtype=include&chfieldfrom=&chfieldto=Now&chfieldvalue=&component=" + urllib.quote(component) + "&email1=&email2=&emailtype1=substring&emailtype2=substring&field-1-0-0=product&field-1-1-0=component&field-1-2-0=bug_status&field0-0-0=noop&keywords=&keywords_type=allwords&long_desc=&long_desc_type=allwordssubstr&product=HTML%20WG&query_format=advanced&remaction=&short_desc=&short_desc_type=allwordssubstr&status_whiteboard=&status_whiteboard_type=allwordssubstr&type-1-0-0=anyexact&type-1-1-0=anyexact&type-1-2-0=anyexact&type0-0-0=noop&value-1-0-0=HTML%20WG&value-1-1-0=" + urllib.quote(component) + "&value-1-2-0=NEW%2CASSIGNED%2CREOPENED&value0-0-0=&votes=&ctype=csv"
73+
bugs = {}
74+
75+
# Create the buglist directory
76+
specBugsDir = os.path.join(options.workingDir, "specbugs")
77+
if(not os.path.exists(specBugsDir)):
78+
os.makedirs(specBugsDir)
79+
80+
# Generate the buglist file name
81+
shortname = component.split()[0].lower().replace("+", "")
82+
buglistFile = os.path.join(specBugsDir, shortname + ".buglist")
83+
84+
# Download the buglist if it doesn't already exist
85+
blFetcher = W3CUrlOpener()
86+
if(not os.path.exists(buglistFile)):
87+
log("INFO: Downloading %s buglist to %s..." % (buglistFile,))
88+
blFetcher.retrieve(quotedBugUrl, buglistFile)
89+
90+
# Download all of the bugs in the buglist
91+
buglist = open(buglistFile)
92+
allBugs = []
93+
bugUrlBase = "http://www.w3.org/Bugs/Public/show_bug.cgi?ctype=xml&id="
94+
for line in buglist.readlines()[1:]:
95+
bugInfo = line.split(",")
96+
bugId = str(bugInfo[0])
97+
bugfilename = os.path.join(specBugsDir, bugId + ".bug")
98+
bugs[bugId] = {"filename": bugfilename}
99+
if(not os.path.exists(bugfilename)):
100+
log("INFO: Downloading bug %s to %s" % (bugId, bugfilename))
101+
blFetcher.retrieve(bugUrlBase + bugId, bugfilename)
102+
103+
# Process each of the bug reports
104+
for (key, value) in bugs.items():
105+
log("INFO: Processing bug %s" % (key,))
106+
bug = None
107+
try:
108+
bug = parse(value["filename"])
109+
except Exception:
110+
log("ERROR: Failed to parse bug %s" % (key,))
111+
112+
# If a bug was found extract all of the long descriptions and search
113+
# for -SPEC-SECTIONS
114+
if(bug != None):
115+
# Search all of the sections for spec section identifiers
116+
value["sections"] = []
117+
for element in bug.findall("bug/long_desc/thetext"):
118+
spos = element.text.find("-SPEC-SECTIONS")
119+
if(spos != -1):
120+
spos = element.text.find("[", spos) + 1
121+
epos = element.text.find("]", spos + 1)
122+
sections = element.text[spos:epos].split(" ")
123+
value["sections"] += sections
124+
125+
# Save the short description
126+
for element in bug.findall("bug/short_desc"):
127+
value["description"] = element.text
128+
129+
# Save the bug ID and URL for insertion into the spec source
130+
value["id"] = key
131+
value["url"] = \
132+
"http://www.w3.org/Bugs/Public/show_bug.cgi?id=%s#c0" % (key,)
133+
bugs[key] = value
134+
135+
# Gather the bugs by spec section ID
136+
bugsBySection = {}
137+
for bugId, bugInfo in bugs.items():
138+
if(bugInfo.has_key("sections") and len(bugInfo["sections"]) > 0):
139+
for section in bugInfo["sections"]:
140+
if(not bugsBySection.has_key(section)):
141+
bugsBySection[section] = []
142+
bugsBySection[section].append(bugInfo)
143+
else:
144+
log("WARNING: Bug %s does not have an associated spec section" % \
145+
(bugId,))
146+
147+
# Process the input HTML file
148+
specfile = open(options.specFile, "r")
149+
outfile = open(options.outFile, "w")
150+
activeElement = None
151+
for line in specfile.readlines():
152+
idstart = line.find(" id=\"")
153+
if(idstart != -1):
154+
idstart += 5
155+
idend = line.find("\"", idstart)
156+
idvalue = line[idstart:idend]
157+
158+
if(bugsBySection.has_key(idvalue)):
159+
aestart = line[:idstart].rfind("<") + 1
160+
activeElement = line[aestart:idstart-5].strip()
161+
162+
outfile.write(line)
163+
164+
if(activeElement != None and
165+
line.find("</%s>" % activeElement) != -1):
166+
outfile.write(
167+
"\n<ul class=\"XXX annotation\"><li><b>Status</b>: " +
168+
"There are W3C bug tracker items associated with this " +
169+
" section.</b></li>\n")
170+
for bug in bugsBySection[idvalue]:
171+
outfile.write("<li class=\"XXX annotation\">" +
172+
"BUG #<a href=\"%s\">%s</a>: %s</li>" % \
173+
(bug["url"], bug["id"], bug["description"]))
174+
outfile.write("</ul>")
175+
activeElement = None
176+
177+
specfile.close()
178+
outfile.close()
179+
180+
# Call main function if run from command line.
181+
if __name__ == "__main__":
182+
183+
addSpecBugWarnings(sys.argv, sys.stdout, os.environ)
184+

0 commit comments

Comments
 (0)