1- #!/usr/bin/python
1+ #!/usr/bin/env python3
22
33from optparse import OptionParser
4- import sys , string
4+ import sys
5+ import string
56import xml .sax
67import xml .sax .handler
78from xml .dom .minidom import getDOMImplementation
89from datetime import datetime
910
1011rfc822 = "%a, %d %b %Y %H:%M:%S GMT"
1112
12- def parse_args ():
13- parser = OptionParser ()
1413
15- parser .add_option ("-i" , dest = "input" , default = "" ,
16- help = "Scoreboard configuration file to generate reports" )
17- parser .add_option ("-o" , dest = "output" , default = "" ,
18- help = "Filename to output report to" )
19- parser .add_option ("-n" , dest = "number" , default = 10 ,
20- help = "Number of recent builds to include" )
21- parser .add_option ("--uri-regex" , dest = "uri_regex" , default = "" , nargs = 2 ,
22- help = "Regular expression used to transform URIs. Must be two strings, separated by a space, ie: --uri-regex search replace" )
23- parser .add_option ("-a" , dest = "name" , default = "DOC Group Scoreboard" ,
24- help = "Feed name" )
25- return parser .parse_args ()
14+ def parse_args ():
15+ parser = OptionParser ()
16+
17+ parser .add_option ("-i" , dest = "input" , default = "" ,
18+ help = "Scoreboard configuration file to generate reports" )
19+ parser .add_option ("-o" , dest = "output" , default = "" ,
20+ help = "Filename to output report to" )
21+ parser .add_option ("-n" , dest = "number" , default = 10 ,
22+ help = "Number of recent builds to include" )
23+ parser .add_option (
24+ "--uri-regex" ,
25+ dest = "uri_regex" ,
26+ default = "" ,
27+ nargs = 2 ,
28+ help = "Regular expression used to transform URIs. Must be two strings, separated by a space, ie: --uri-regex search replace" )
29+ parser .add_option ("-a" , dest = "name" , default = "DOC Group Scoreboard" ,
30+ help = "Feed name" )
31+ return parser .parse_args ()
32+
33+
34+ (opts , args ) = parse_args ()
2635
27- (opts , args ) = parse_args ()
2836
2937class ScoreboardHandler (xml .sax .handler .ContentHandler ):
30- def __init__ (self ):
31- self .pos = list ()
32- self .state = dict ()
33- self .builds = list ()
38+ def __init__ (self ):
39+ self .pos = list ()
40+ self .state = dict ()
41+ self .builds = list ()
3442 return
3543
36- def startElement (self , name , attrs ):
37- self .pos .append (name )
44+ def startElement (self , name , attrs ):
45+ self .pos .append (name )
3846
3947 if name == "build" :
4048 self .state ["name" ] = ""
@@ -43,184 +51,197 @@ def startElement (self, name, attrs):
4351
4452 return
4553
46- def characters (self , content ):
54+ def characters (self , content ):
4755 name = self .pos [- 1 ]
4856
4957 self .state [name ] = content
5058
51- def endElement (self , name ):
59+ def endElement (self , name ):
5260
53- if self .pos .pop () != name :
54- print "ERROR: endElement called for a state we shouldn't be in: " + name
61+ if self .pos .pop () != name :
62+ print ( "ERROR: endElement called for a state we shouldn't be in: " + name )
5563 return
5664
5765 if name == "build" :
58- self .builds .append ((self .state ["name" ], self .state ["url" ], self .state ["sponsor" ]))
66+ self .builds .append (
67+ (self .state ["name" ],
68+ self .state ["url" ],
69+ self .state ["sponsor" ]))
70+
71+ # Helper methond to append a text node onto a DOM tree.
72+
73+
74+ def appendTextNode (doc , parent , name , value ):
75+ ele = doc .createElement (name )
76+ ele .appendChild (doc .createTextNode (str (value )))
77+ parent .appendChild (ele )
5978
60- ### Helper methond to append a text node onto a DOM tree.
61- def appendTextNode (doc , parent , name , value ) :
62- ele = doc .createElement (name )
63- ele .appendChild (doc .createTextNode (str (value )))
64- parent .appendChild (ele )
6579
66- class RSSItem :
67- def __init__ (self ):
80+ class RSSItem :
81+ def __init__ (self ):
6882 self .title = ""
6983 self .link = ""
7084 self .description = ""
71- self .pubDate = datetime .utcnow ()
85+ self .pubDate = datetime .utcnow ()
7286 self .guid = ""
7387
74- def to_xml (self , parent , doc ):
75- item = doc .createElement ("item" )
88+ def to_xml (self , parent , doc ):
89+ item = doc .createElement ("item" )
7690
77- appendTextNode (doc , item , "title" , self .title )
78- appendTextNode (doc , item , "link" , self .link )
79- appendTextNode (doc , item , "description" , self .description )
80- appendTextNode (doc , item , "pubDate" , self .pubDate .strftime (rfc822 ))
81- appendTextNode (doc , item , "guid" , self .guid )
91+ appendTextNode (doc , item , "title" , self .title )
92+ appendTextNode (doc , item , "link" , self .link )
93+ appendTextNode (doc , item , "description" , self .description )
94+ appendTextNode (doc , item , "pubDate" , self .pubDate .strftime (rfc822 ))
95+ appendTextNode (doc , item , "guid" , self .guid )
8296
83- parent .appendChild (item )
97+ parent .appendChild (item )
8498 return
8599
86- class RSSChannel :
87- def __init__ (self ):
100+
101+ class RSSChannel :
102+ def __init__ (self ):
88103 self .title = ""
89104 self .link = ""
90105 self .desc = ""
91106 self .language = "en-us"
92- self .pubDate = datetime .utcnow ()
107+ self .pubDate = datetime .utcnow ()
93108 self .lastBuildDate = self .pubDate
94109 self .generator = "DOC Group Scoreboard RSS System"
95110 self .
managingEditor = "[email protected] " 96111 self .
webMaster = "[email protected] " 97- self .items = list ()
98-
99- def add_item (self , item ):
100- self .items .append (item )
101-
102- def to_xml (self , parent , doc ):
103- channel = doc .createElement ("channel" )
104- appendTextNode (doc , channel , "title" , self .title )
105- appendTextNode (doc , channel , "link" , self .link )
106- appendTextNode (doc , channel , "description" , self .desc )
107- appendTextNode (doc , channel , "language" , self .language )
108- appendTextNode (doc , channel , "pubDate" , self .pubDate .strftime (rfc822 ))
109- appendTextNode (doc , channel , "lastBuildDate" , self .lastBuildDate .strftime (rfc822 ))
110- appendTextNode (doc , channel , "generator" , self .generator )
111- appendTextNode (doc , channel , "managingEditor" , self .managingEditor )
112- appendTextNode (doc , channel , "webMaster" , self .webMaster )
113-
114- parent .appendChild (channel )
112+ self .items = list ()
113+
114+ def add_item (self , item ):
115+ self .items .append (item )
116+
117+ def to_xml (self , parent , doc ):
118+ channel = doc .createElement ("channel" )
119+ appendTextNode (doc , channel , "title" , self .title )
120+ appendTextNode (doc , channel , "link" , self .link )
121+ appendTextNode (doc , channel , "description" , self .desc )
122+ appendTextNode (doc , channel , "language" , self .language )
123+ appendTextNode (doc , channel , "pubDate" , self .pubDate .strftime (rfc822 ))
124+ appendTextNode (
125+ doc ,
126+ channel ,
127+ "lastBuildDate" ,
128+ self .lastBuildDate .strftime (rfc822 ))
129+ appendTextNode (doc , channel , "generator" , self .generator )
130+ appendTextNode (doc , channel , "managingEditor" , self .managingEditor )
131+ appendTextNode (doc , channel , "webMaster" , self .webMaster )
132+
133+ parent .appendChild (channel )
115134 for item in self .items :
116- item .to_xml (channel , doc )
135+ item .to_xml (channel , doc )
136+
117137
118- class RSS :
119- def __init__ (self ):
120- self .channels = list ()
138+ class RSS :
139+ def __init__ (self ):
140+ self .channels = list ()
121141
122- def add_channel (self , channel ):
123- self .channels .append (channel )
142+ def add_channel (self , channel ):
143+ self .channels .append (channel )
124144
125- def to_xml (self , outFile ):
126- impl = xml .dom .minidom .getDOMImplementation ()
127- rssdoc = impl .createDocument (None , "rss" , None )
145+ def to_xml (self , outFile ):
146+ impl = xml .dom .minidom .getDOMImplementation ()
147+ rssdoc = impl .createDocument (None , "rss" , None )
128148
129149 top = rssdoc .documentElement
130- top .setAttribute ("version" , "2.0" )
150+ top .setAttribute ("version" , "2.0" )
131151
132152 for channel in self .channels :
133- channel .to_xml (top , rssdoc )
153+ channel .to_xml (top , rssdoc )
134154
135- outfile = file (opts .output , 'w' )
136- outfile .write (rssdoc .toprettyxml (" " ))
155+ outfile = file (opts .output , 'w' )
156+ outfile .write (rssdoc .toprettyxml (" " ))
137157 outfile .close
138158
139159 # Clean up
140- rssdoc .unlink ()
160+ rssdoc .unlink ()
161+
141162
142- def parse (filename ):
143- handler = ScoreboardHandler ()
144- parser = xml .sax .make_parser ()
145- parser .setContentHandler (handler )
163+ def parse (filename ):
164+ handler = ScoreboardHandler ()
165+ parser = xml .sax .make_parser ()
166+ parser .setContentHandler (handler )
146167
147- infile = file (filename , 'r' )
148- parser .parse (infile )
149- infile .close ()
168+ infile = file (filename , 'r' )
169+ parser .parse (infile )
170+ infile .close ()
150171
151172 return handler
152173
153- def fetch_latest (builds ):
174+
175+ def fetch_latest (builds ):
154176 import re
155- from urllib import urlopen
177+ from urllib . request import urlopen
156178
157- latest_builds = list ()
179+ latest_builds = list ()
158180
159- valid_latest = re .compile ("\d\d\d\ d_\d \d" )
181+ valid_latest = re .compile ("\\ d \\ d \\ d \\ d_\\ d \ \ d" )
160182
161183 for build in builds :
162184 try :
163185 uri = build [1 ]
164186
165- if opts .uri_regex != "" :
166- uri = re .sub (opts .uri_regex [0 ],
167- opts .uri_regex [1 ],
168- uri )
187+ if opts .uri_regex :
188+ uri = re .sub (opts .uri_regex [0 ],
189+ opts .uri_regex [1 ],
190+ uri )
169191
170- latest = urlopen (uri + "/latest.txt" )
192+ latest = urlopen (uri + "/latest.txt" )
171193
172- #Get the contents, and make sure it represents a valid latest file
173- string = latest .read ()
174- if valid_latest .match (string ) != None :
175- latest_builds .append ((build [0 ],build [1 ],string ))
194+ # Get the contents, and make sure it represents a valid latest file
195+ string = latest .read ()
196+ if valid_latest .match (string ) is not None :
197+ latest_builds .append ((build [0 ], build [1 ], string ))
176198 else :
177- print "ERROR: " + build [0 ] + " returned an invalid latest file!"
178- latest .close ()
179- except :
180- print "Error: Failed to open latest file for " + build [0 ]
199+ print ( "ERROR: " + build [0 ] + " returned an invalid latest file!" )
200+ latest .close ()
201+ except BaseException :
202+ print ( "Error: Failed to open latest file for " + build [0 ])
181203
182204 return latest_builds
183205
184- def main ():
185- # (opts, args) = parse_args ()
186206
207+ def main ():
187208 if (opts .input == "" ) or (opts .output == "" ):
188- print "Error: Must supply both -i and -o arguments."
189- return - 1
209+ print ( "Error: Must supply both -i and -o arguments." )
210+ return 1
190211
191- handler = parse (opts .input )
192- latest = fetch_latest (handler .builds )
212+ handler = parse (opts .input )
213+ latest = fetch_latest (handler .builds )
193214
194- ## Sort in decending order of completion
195- latest .sort (cmp = lambda x , y : cmp (x [2 ], y [2 ]), reverse = True )
215+ # Sort in decending order of completion
216+ latest .sort (cmp = lambda x , y : cmp (x [2 ], y [2 ]), reverse = True )
196217
197218 # Prune off all but the request number of entries...
198- latest = latest [0 :int (opts .number )]
219+ latest = latest [0 :int (opts .number )]
199220
200- chan = RSSChannel ()
221+ chan = RSSChannel ()
201222 chan .title = opts .name
202223 chan .desc = "Build results"
203224 chan .link = "http://www.dre.vanderbilt.edu/scoreboard"
204225 for build in latest :
205- item = RSSItem ()
226+ item = RSSItem ()
206227 item .title = build [0 ]
207228 item .link = build [1 ] + "/index.html"
208229 item .guid = build [1 ] + "/" + build [2 ][0 :16 ] + "_Totals.html"
209230 item .description = build [2 ]
210- item .pubDate = datetime (int (build [2 ][0 :4 ]), # Year
211- int (build [2 ][5 :7 ]),
212- int (build [2 ][8 :10 ]),
213- int (build [2 ][11 :13 ]),
214- int (build [2 ][14 :16 ]))
215- chan .add_item (item )
231+ item .pubDate = datetime (int (build [2 ][0 :4 ]), # Year
232+ int (build [2 ][5 :7 ]),
233+ int (build [2 ][8 :10 ]),
234+ int (build [2 ][11 :13 ]),
235+ int (build [2 ][14 :16 ]))
236+ chan .add_item (item )
216237
217- rss = RSS ()
218- rss .add_channel (chan )
238+ rss = RSS ()
239+ rss .add_channel (chan )
219240
220- rss .to_xml (opts .output )
241+ rss .to_xml (opts .output )
221242
222243 return 0
223244
224- if __name__ == "__main__" :
225- main ()
226245
246+ if __name__ == "__main__" :
247+ main ()
0 commit comments