Add DocBook entities for the env.*() forms of Builder and function calls.
[scons.git] / bin / sfsum
1 #!/usr/bin/env python
2 #
3 # sfsum.py:  A script for parsing XML data exported from
4 #            SourceForge projects.
5 #
6 # Right now, this is hard-coded to generate a summary of open bugs.
7 #
8 # XML data for SourceForge project is available for download by project
9 # administrators.  Because it's intended for backup purposes, you have
10 # to slurp the whole set of data, including info about all of the closed
11 # items, the feature requests, etc., so it can get big.
12 #
13 # You can do this by hand (if you're an administrator) with a URL like
14 # this (where 30337 is the group_id for SCons):
15 #
16 #       http://sourceforge.net/export/xml_export.php?group_id=30337
17 #
18 # They also have a Perl script, called xml_export, available as part
19 # of a set of utilities called "adocman" which automate dealing with
20 # SourceForge document management from the command line.  "adocman"
21 # is available at:
22 #
23 #       https://sourceforge.net/projects/sitedocs/
24 #
25
26 import xml.sax
27 import xml.sax.saxutils
28 import string
29 import sys
30
31 SFName = {
32     'Unassigned'                : 'nobody',
33     'Chad Austin'               : 'aegis',
34     'Charle Crain'              : 'diewarzau',
35     'Steven Knight'             : 'stevenknight',
36     'Steve Leblanc'             : 'stevenleblanc',
37     'Jeff Petkau'               : 'jpet',
38     'Anthony Roach'             : 'anthonyroach',
39     'Steven Shaw'               : 'steven_shaw',
40     'Terrel Shumway'            : 'terrelshumway',
41     'Greg Spencer'              : 'greg_spencer',
42     'Christoph Wiedemann'       : 'wiedeman',
43 }
44
45 class Artifact:
46     """Just a place to hold attributes that we find in the XML."""
47     pass
48
49 Artifacts = {}
50
51 def nws(text):
52     """Normalize white space.  This will become important if/when
53     we enhance this to search for arbitrary fields."""
54     return string.join(string.split(text), ' ')
55
56 class ClassifyArtifacts(xml.sax.saxutils.DefaultHandler):
57     """
58     Simple SAX subclass to classify the artifacts in SourceForge
59     XML output.
60
61     This reads up the fields in an XML description and turns the field
62     descriptions into attributes of an Artificat object, on the fly.
63     Artifacts are of the following types:
64
65         Bugs
66         Feature Requests
67         Patches
68         Support Requests
69
70     We could, if we choose to, add additional types in the future
71     by creating additional trackers.
72
73     This class loses some info right now because we don't pay attention
74     to the <messages> tag in the output, which contains a list of items
75     that have <field> tags in them.  Right now, these just overwrite
76     each other in the Arifact object we create.
77
78     We also don't pay attention to any attributes of a <field> tag other
79     than the "name" attribute.  We'll need to extend this class if we
80     ever want to pay attention to those attributes.
81     """
82     def __init__(self):
83         self.artifact = None
84
85     def startElement(self, name, attrs):
86         self.text = ""
87         if name == 'artifact':
88             self.artifact = Artifact()
89         elif not self.artifact is None and name == 'field':
90             self.fname = attrs.get('name', None)
91
92     def characters(self, ch):
93         if not self.artifact is None:
94             self.text = self.text + ch
95
96     def endElement(self, name):
97         global Artifacts
98         if name == 'artifact':
99             type = self.artifact.artifact_type
100             try:
101                 list = Artifacts[type]
102             except KeyError:
103                 Artifacts[type] = list = []
104             list.append(self.artifact)
105             self.artifact = None
106         elif not self.artifact is None and name == 'field':
107             setattr(self.artifact, self.fname, self.text)
108
109 if __name__ == '__main__':
110     # Create a parser.
111     parser = xml.sax.make_parser()
112     # Tell the parser we are not interested in XML namespaces.
113     parser.setFeature(xml.sax.handler.feature_namespaces, 0)
114
115     # Instantiate our handler and tell the parser to use it.
116     parser.setContentHandler(ClassifyArtifacts())
117
118     # Parse the input.
119     parser.parse(sys.argv[1])
120
121     # Hard-coded search for 'Open' bugs.  This should be easily
122     # generalized once we figure out other things for this script to do.
123     bugs = filter(lambda x: x.status == 'Open', Artifacts['Bugs'])
124
125     print Artifacts.keys()
126
127     print "%d open bugs" % len(bugs)
128
129     # Sort them into a separate list for each assignee.
130     Assigned = {}
131     for bug in bugs:
132         a = bug.assigned_to
133         try:
134             list = Assigned[a]
135         except KeyError:
136             Assigned[a] = list = []
137         list.append(bug)
138
139     for a in SFName.keys():
140         try:
141             b = Assigned[SFName[a]]
142         except KeyError:
143             pass
144         else:
145             print "    %s" % a
146             b.sort(lambda x, y: cmp(x.artifact_id, y.artifact_id))
147             for bug in b:
148                 print "        %-6s  %s" % (bug.artifact_id, bug.summary)