]>
Commit | Line | Data |
---|---|---|
2b60fce9 MT |
1 | #!/usr/bin/python |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5 | # Copyright (C) 2008 Michael Tremer & Christian Schmidt # | |
6 | # # | |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | import os | |
23 | import sys | |
24 | import time | |
25 | ||
26 | sys.path.append(".") | |
27 | ||
28 | from builder import Builder, getAllBuilders | |
29 | from constants import * | |
30 | ||
31 | def format_time(seconds, use_hours=1): | |
32 | if seconds is None or seconds < 0: | |
33 | if use_hours: return '--:--:--' | |
34 | else: return '--:--' | |
35 | else: | |
36 | seconds = int(seconds) | |
37 | minutes = seconds / 60 | |
38 | seconds = seconds % 60 | |
39 | if use_hours: | |
40 | hours = minutes / 60 | |
41 | minutes = minutes % 60 | |
42 | return '%02i:%02i:%02i' % (hours, minutes, seconds) | |
43 | else: | |
44 | return '%02i:%02i' % (minutes, seconds) | |
45 | ||
46 | class Site: | |
47 | def __init__(self, config): | |
48 | self.builders = None | |
49 | self.config = config | |
50 | print "Content-type: text/html" | |
51 | ||
52 | ||
53 | def __call__(self, builders=None): | |
54 | self.builders = builders | |
55 | print """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
56 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
57 | <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> | |
58 | <head> | |
59 | <title>%(title)s</title> | |
60 | <style type="text/css"> | |
61 | * { | |
62 | margin: auto; | |
63 | padding: 0; | |
64 | text-decoration: none; | |
65 | outline: none; | |
66 | } | |
67 | body { | |
68 | font-family: Verdana; | |
69 | font-size: 90%%; | |
70 | background-color:#f9f9f9; | |
71 | } | |
72 | h1 { | |
73 | text-decoration: underline; | |
74 | } | |
75 | #header { | |
76 | width: 800px; | |
2b60fce9 MT |
77 | text-align: center; |
78 | background: #E0E0E0; | |
79 | border: 1px solid #999; | |
80 | padding-top: 10px; | |
f3fdc4c6 | 81 | padding-bottom: 5px; |
2b60fce9 MT |
82 | } |
83 | #content { | |
84 | padding-top: 10px; | |
85 | width: 800px; | |
86 | } | |
87 | div.box { | |
88 | padding: 5px; | |
89 | margin: 10px 0 10px 0; | |
10da7ad4 | 90 | /* height: 80px; */ |
2b60fce9 MT |
91 | border: 1px solid; |
92 | } | |
93 | div.infobox { | |
94 | float: right; | |
95 | width: 240px; | |
96 | } | |
10da7ad4 MT |
97 | div.log { |
98 | background: #e55; | |
99 | border: 1px dotted; | |
100 | margin-top: 12px; | |
101 | /* visibility: hidden; */ | |
102 | } | |
103 | div.log p { | |
104 | font-family: Courier New; | |
105 | } | |
0e744e5a MT |
106 | div.footer { |
107 | } | |
108 | div.footer p { | |
109 | text-align: center; | |
110 | font-size: 5px; | |
111 | } | |
2b60fce9 MT |
112 | p { |
113 | margin: 2px; | |
114 | } | |
115 | p.boxheader { | |
116 | font-weight: bold; | |
117 | } | |
118 | p.online { | |
119 | color: green; | |
120 | } | |
121 | p.offline { | |
122 | color: red; | |
123 | } | |
124 | p.package { | |
125 | font: bold; | |
126 | font-size: 150%%; | |
127 | } | |
128 | img.right { | |
129 | float: right; | |
130 | } | |
131 | p.desc { | |
132 | text-decoration: bold; | |
133 | } | |
134 | a:link { | |
135 | color: black; text-decoration: none; | |
136 | } | |
137 | a:visited { | |
138 | color: black; text-decoration: none; | |
139 | } | |
140 | </style> | |
141 | <meta http-equiv="refresh" content="90; URL=%(script)s" /> | |
142 | </head> | |
143 | <body> | |
144 | <div id="header"> | |
145 | <h1>IPFire Builder</h1>""" % self.config | |
2b60fce9 MT |
146 | for i in self.config["nightly_url"]: |
147 | print """\ | |
148 | <p><a href="%s" target="_blank">%s</a></p>""" % (i, i,) | |
149 | print """\ | |
150 | </div>""" | |
151 | ||
152 | self.content() | |
153 | ||
154 | print "\t\t</body>\n</html>" | |
155 | ||
156 | def content(self): | |
157 | if self.builders: | |
2b60fce9 MT |
158 | print """\ |
159 | <div id="content">""" | |
160 | for builder in self.builders: | |
f006517e | 161 | builder() |
2b60fce9 MT |
162 | print """\ |
163 | </div>""" | |
164 | ||
165 | class Box: | |
166 | def __init__(self, builder): | |
f006517e MT |
167 | self.builder = builder |
168 | self.points = POINTS_UNKNOWN | |
2b60fce9 | 169 | |
f006517e MT |
170 | def __cmp__(self, other): |
171 | if self.points > other.points: | |
172 | return -1 | |
173 | elif self.points == other.points: | |
174 | return 0 | |
175 | elif self.points < other.points: | |
176 | return 1 | |
177 | ||
2b60fce9 MT |
178 | def __str__(self): |
179 | return """<a href="#%(hostname)s">%(hostname)s</a>""" % { "hostname" : self.builder.hostname(), } | |
180 | ||
f006517e MT |
181 | def open_bigbox(self): |
182 | print """<a name="%s"></a><div class="box" style="%s">""" \ | |
183 | % (self.builder.hostname(), state2style[self.builder.state()],) | |
184 | ||
185 | def open_infobox(self): | |
186 | print """<div class="infobox">""" | |
187 | ||
188 | def close_bigbox(self): | |
189 | print """</div>""" | |
190 | ||
191 | close_infobox = close_bigbox | |
192 | ||
2b60fce9 | 193 | def header(self): |
f006517e MT |
194 | print """<p class="boxheader">%(hostname)s <span>[%(uuid)s]</span></p>""" \ |
195 | % { "hostname" : self.builder.hostname(), | |
196 | "state" : self.builder.state(), | |
197 | "uuid" : self.builder.uuid, } | |
2b60fce9 MT |
198 | |
199 | def package(self): | |
200 | if self.builder.state() in [ "compiling", "error", ]: | |
201 | print """\ | |
202 | <p class="package">%s</p>"""\ | |
203 | % self.builder.package() | |
204 | ||
205 | def time(self): | |
f006517e MT |
206 | print """<p>%s</p>""" \ |
207 | % time.ctime(float(self.builder.state.time())) | |
2b60fce9 MT |
208 | |
209 | def stateinfo(self): | |
f006517e MT |
210 | print """<p class="desc">%s</p>""" \ |
211 | % statedesc[self.builder.state()] | |
2b60fce9 MT |
212 | |
213 | def durations(self): | |
f006517e MT |
214 | print """<p>Average Build Duration: %s</p>""" \ |
215 | % format_time(self.builder.duration.get_avg()) | |
2b60fce9 | 216 | if self.builder.state() == "compiling": |
f006517e | 217 | print """<p>ETA: %s</p>""" \ |
2b60fce9 MT |
218 | % self.builder.duration.get_eta(self.builder.state.time()) |
219 | ||
220 | def distccinfo(self): | |
221 | state = self.builder.distcc.ping() | |
fda98c60 MT |
222 | port = self.builder.distcc() |
223 | if port == "0": | |
224 | state = False | |
225 | port = "disabled" | |
f006517e | 226 | print """<p class="%s">Distcc: %s</p>""" \ |
fda98c60 | 227 | % (ping2class[state], port,) |
10da7ad4 MT |
228 | |
229 | def log(self): | |
230 | log = self.builder.log() | |
231 | if log: | |
f006517e | 232 | print """<div class="log"><p>""" |
10da7ad4 | 233 | for i in log: |
0359f8fc MT |
234 | if i: |
235 | print "%s<br />" % (i.rstrip("\n"),) | |
f006517e | 236 | print """</p></div>""" |
2b60fce9 | 237 | |
0e744e5a | 238 | def footer(self): |
7f77b1db MT |
239 | print """<div class="footer"><p>cpu: %s - target: %s - jobs: %s</p></div>""" \ |
240 | % (self.builder.cpu(), self.builder.target(), self.builder.jobs(),) | |
f006517e MT |
241 | |
242 | class BoxCompiling(Box): | |
243 | def __init__(self, builder): | |
244 | Box.__init__(self, builder) | |
245 | self.points = POINTS_COMPILING | |
246 | ||
247 | def __call__(self): | |
248 | self.open_bigbox() | |
249 | self.open_infobox() | |
250 | self.distccinfo() | |
251 | self.package() | |
252 | self.time() | |
253 | self.close_infobox() | |
254 | self.header() | |
255 | self.stateinfo() | |
256 | self.durations() | |
257 | self.footer() | |
258 | self.close_bigbox() | |
259 | ||
260 | class BoxError(Box): | |
261 | def __init__(self, builder): | |
262 | Box.__init__(self, builder) | |
263 | self.points = POINTS_ERROR | |
264 | ||
265 | def __call__(self): | |
266 | self.open_bigbox() | |
267 | self.open_infobox() | |
268 | self.distccinfo() | |
269 | self.package() | |
270 | self.time() | |
271 | self.close_infobox() | |
272 | self.header() | |
273 | self.stateinfo() | |
274 | self.durations() | |
275 | self.log() | |
276 | self.footer() | |
277 | self.close_bigbox() | |
278 | ||
279 | class BoxDistcc(Box): | |
280 | def __init__(self, builder): | |
281 | Box.__init__(self, builder) | |
282 | self.points = POINTS_DISTCC | |
283 | ||
284 | def __call__(self): | |
285 | self.open_bigbox() | |
286 | self.open_infobox() | |
287 | self.distccinfo() | |
288 | self.time() | |
289 | self.close_infobox() | |
290 | self.header() | |
291 | self.stateinfo() | |
292 | self.durations() | |
293 | self.footer() | |
294 | self.close_bigbox() | |
295 | ||
296 | class BoxIdle(Box): | |
297 | def __init__(self, builder): | |
298 | Box.__init__(self, builder) | |
299 | self.points = POINTS_IDLE | |
300 | ||
301 | def __call__(self): | |
302 | self.open_bigbox() | |
303 | self.open_infobox() | |
304 | self.distccinfo() | |
305 | self.time() | |
306 | self.close_infobox() | |
307 | self.header() | |
308 | self.stateinfo() | |
309 | self.durations() | |
310 | self.footer() | |
311 | self.close_bigbox() | |
0e744e5a | 312 | |
2b60fce9 MT |
313 | site = Site(config) |
314 | ||
315 | boxes = [] | |
f006517e MT |
316 | for builder in getAllBuilders(): |
317 | box = None | |
318 | if builder.state() == "compiling": | |
319 | box = BoxCompiling(builder) | |
320 | elif builder.state() == "error": | |
321 | box = BoxError(builder) | |
322 | elif builder.state() == "idle": | |
323 | box = BoxIdle(builder) | |
324 | elif builder.state() == "distcc": | |
325 | if builder.distcc() == "0": | |
326 | continue | |
327 | box = BoxDistcc(builder) | |
328 | if box: | |
329 | boxes.append(box) | |
2b60fce9 | 330 | |
f006517e | 331 | boxes.sort() |
2b60fce9 | 332 | site(boxes) |