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
|
#!/usr/bin/env python
#
# sfsum.py: A script for parsing XML data exported from
# SourceForge projects.
#
# Right now, this is hard-coded to generate a summary of open bugs.
#
# XML data for SourceForge project is available for download by project
# administrators. Because it's intended for backup purposes, you have
# to slurp the whole set of data, including info about all of the closed
# items, the feature requests, etc., so it can get big.
#
# You can do this by hand (if you're an administrator) with a URL like
# this (where 30337 is the group_id for SCons):
#
# http://sourceforge.net/export/xml_export.php?group_id=30337
#
# They also have a Perl script, called xml_export, available as part
# of a set of utilities called "adocman" which automate dealing with
# SourceForge document management from the command line. "adocman"
# is available at:
#
# https://sourceforge.net/projects/sitedocs/
#
import xml.sax
import xml.sax.saxutils
import sys
SFName = {
'Unassigned' : 'nobody',
'Chad Austin' : 'aegis',
'Charle Crain' : 'diewarzau',
'Steven Knight' : 'stevenknight',
'Steve Leblanc' : 'stevenleblanc',
'Jeff Petkau' : 'jpet',
'Anthony Roach' : 'anthonyroach',
'Steven Shaw' : 'steven_shaw',
'Terrel Shumway' : 'terrelshumway',
'Greg Spencer' : 'greg_spencer',
'Christoph Wiedemann' : 'wiedeman',
}
class Artifact:
"""Just a place to hold attributes that we find in the XML."""
pass
Artifacts = {}
def nws(text):
"""Normalize white space. This will become important if/when
we enhance this to search for arbitrary fields."""
return ' '.join(text.split())
class ClassifyArtifacts(xml.sax.saxutils.DefaultHandler):
"""
Simple SAX subclass to classify the artifacts in SourceForge
XML output.
This reads up the fields in an XML description and turns the field
descriptions into attributes of an Artificat object, on the fly.
Artifacts are of the following types:
Bugs
Feature Requests
Patches
Support Requests
We could, if we choose to, add additional types in the future
by creating additional trackers.
This class loses some info right now because we don't pay attention
to the <messages> tag in the output, which contains a list of items
that have <field> tags in them. Right now, these just overwrite
each other in the Arifact object we create.
We also don't pay attention to any attributes of a <field> tag other
than the "name" attribute. We'll need to extend this class if we
ever want to pay attention to those attributes.
"""
def __init__(self):
self.artifact = None
def startElement(self, name, attrs):
self.text = ""
if name == 'artifact':
self.artifact = Artifact()
elif not self.artifact is None and name == 'field':
self.fname = attrs.get('name', None)
def characters(self, ch):
if not self.artifact is None:
self.text = self.text + ch
def endElement(self, name):
global Artifacts
if name == 'artifact':
type = self.artifact.artifact_type
try:
list = Artifacts[type]
except KeyError:
Artifacts[type] = list = []
list.append(self.artifact)
self.artifact = None
elif not self.artifact is None and name == 'field':
setattr(self.artifact, self.fname, self.text)
if __name__ == '__main__':
# Create a parser.
parser = xml.sax.make_parser()
# Tell the parser we are not interested in XML namespaces.
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
# Instantiate our handler and tell the parser to use it.
parser.setContentHandler(ClassifyArtifacts())
# Parse the input.
parser.parse(sys.argv[1])
# Hard-coded search for 'Open' bugs. This should be easily
# generalized once we figure out other things for this script to do.
bugs = filter(lambda x: x.status == 'Open', Artifacts['Bugs'])
print Artifacts.keys()
print "%d open bugs" % len(bugs)
# Sort them into a separate list for each assignee.
Assigned = {}
for bug in bugs:
a = bug.assigned_to
try:
list = Assigned[a]
except KeyError:
Assigned[a] = list = []
list.append(bug)
for a in SFName.keys():
try:
b = Assigned[SFName[a]]
except KeyError:
pass
else:
print " %s" % a
b.sort(lambda x, y: cmp(x.artifact_id, y.artifact_id))
for bug in b:
print " %-6s %s" % (bug.artifact_id, bug.summary)
|