]>
Commit | Line | Data |
---|---|---|
dfff8bd5 MM |
1 | # vi: encoding=utf-8 ts=8 sts=4 sw=4 et |
2 | ||
51a6a3a6 MM |
3 | from xml.dom.minidom import * |
4 | import string | |
94169186 | 5 | import time |
2ba00366 MM |
6 | import xml.sax.saxutils |
7 | import fnmatch | |
482da2b1 | 8 | import os |
73bfd962 | 9 | import urllib |
7d73f518 | 10 | import cgi |
51a6a3a6 | 11 | |
30dbf6a3 | 12 | import util |
17f23d66 | 13 | import log |
e2cad913 | 14 | from acl import acl |
b3c8d962 | 15 | from config import config |
30dbf6a3 | 16 | |
94169186 | 17 | __all__ = ['parse_request', 'parse_requests'] |
0d52c382 | 18 | |
51a6a3a6 | 19 | def text(e): |
dfff8bd5 MM |
20 | res = "" |
21 | for n in e.childNodes: | |
22 | if n.nodeType != Element.TEXT_NODE: | |
23 | log.panic("xml: text expected in <%s>, got %d" % (e.nodeName, n.nodeType)) | |
24 | res += n.nodeValue | |
25 | return res | |
51a6a3a6 | 26 | |
30dbf6a3 | 27 | def attr(e, a, default = None): |
dfff8bd5 MM |
28 | try: |
29 | return e.attributes[a].value | |
30 | except: | |
31 | if default != None: | |
32 | return default | |
33 | raise | |
51a6a3a6 | 34 | |
cf1741af | 35 | def escape(s): |
dfff8bd5 | 36 | return xml.sax.saxutils.escape(s) |
cf1741af | 37 | |
04ce7f54 ER |
38 | # return timestamp with timezone information |
39 | # so we could parse it in javascript | |
40 | def tzdate(t): | |
41 | # as strftime %z is unofficial, and does not work, need to make it numeric ourselves | |
42 | # date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t)) | |
c0e5c8cc | 43 | date = time.strftime("%a %b %d %Y %H:%M:%S", time.localtime(t)) |
04ce7f54 | 44 | # NOTE: the altzone is showing CURRENT timezone, not what the "t" reflects |
6e2aab74 | 45 | # NOTE: when DST is off timezone gets it right, altzone not |
42c9621c ER |
46 | if time.daylight: |
47 | tzoffset = time.altzone | |
48 | else: | |
3f85c9bc | 49 | tzoffset = time.timezone |
ba569b5d | 50 | tz = '%+05d' % (-tzoffset / 3600 * 100) |
04ce7f54 ER |
51 | return date + ' ' + tz |
52 | ||
51a6a3a6 | 53 | def is_blank(e): |
dfff8bd5 | 54 | return e.nodeType == Element.TEXT_NODE and string.strip(e.nodeValue) == "" |
0d52c382 | 55 | |
51a6a3a6 | 56 | class Group: |
dfff8bd5 MM |
57 | def __init__(self, e): |
58 | self.batches = [] | |
59 | self.kind = 'group' | |
60 | self.id = attr(e, "id") | |
61 | self.no = int(attr(e, "no")) | |
62 | self.priority = 2 | |
63 | self.time = time.time() | |
64 | self.requester = "" | |
85303822 | 65 | self.max_jobs = 0 |
dfff8bd5 MM |
66 | self.requester_email = "" |
67 | self.flags = string.split(attr(e, "flags", "")) | |
68 | for c in e.childNodes: | |
69 | if is_blank(c): continue | |
b051f064 | 70 | |
dfff8bd5 MM |
71 | if c.nodeType != Element.ELEMENT_NODE: |
72 | log.panic("xml: evil group child %d" % c.nodeType) | |
73 | if c.nodeName == "batch": | |
74 | self.batches.append(Batch(c)) | |
75 | elif c.nodeName == "requester": | |
b4d7e94a | 76 | self.requester = text(c) |
dfff8bd5 MM |
77 | self.requester_email = attr(c, "email", "") |
78 | elif c.nodeName == "priority": | |
b4d7e94a | 79 | self.priority = int(text(c)) |
dfff8bd5 | 80 | elif c.nodeName == "time": |
b4d7e94a | 81 | self.time = int(text(c)) |
b3c8d962 | 82 | elif c.nodeName == "maxjobs": |
b4d7e94a | 83 | self.max_jobs = int(text(c)) |
dfff8bd5 MM |
84 | else: |
85 | log.panic("xml: evil group child (%s)" % c.nodeName) | |
86 | # note that we also check that group is sorted WRT deps | |
87 | m = {} | |
88 | for b in self.batches: | |
89 | deps = [] | |
90 | m[b.b_id] = b | |
91 | for dep in b.depends_on: | |
92 | if m.has_key(dep): | |
93 | # avoid self-deps | |
94 | if id(m[dep]) != id(b): | |
95 | deps.append(m[dep]) | |
96 | else: | |
97 | log.panic("xml: dependency not found in group") | |
98 | b.depends_on = deps | |
99 | if self.requester_email == "" and self.requester != "": | |
100 | self.requester_email = acl.user(self.requester).mail_to() | |
51a6a3a6 | 101 | |
dfff8bd5 MM |
102 | def dump(self, f): |
103 | f.write("group: %d (id=%s pri=%d)\n" % (self.no, self.id, self.priority)) | |
104 | f.write(" from: %s\n" % self.requester) | |
105 | f.write(" flags: %s\n" % string.join(self.flags)) | |
106 | f.write(" time: %s\n" % time.asctime(time.localtime(self.time))) | |
107 | for b in self.batches: | |
108 | b.dump(f) | |
109 | f.write("\n") | |
cf1741af | 110 | |
dfff8bd5 | 111 | def dump_html(self, f): |
0d52c382 | 112 | f.write( |
76627b0c | 113 | "<div id=\"%(no)d\" class=\"%(flags)s\">\n" |
64c5a6cb | 114 | "<a href=\"#%(no)d\">%(no)d</a>. <span id=\"tz\">%(time)s</span> from <b>%(requester)s</b> " |
0d52c382 ER |
115 | "<small>%(id)s, prio=%(priority)d, jobs=%(max_jobs)d, %(flags)s</small>\n" |
116 | % { | |
51a8fa53 | 117 | 'no': self.no, |
dac6c47c | 118 | 'id': '<a href="srpms/%(id)s">%(id)s</a>' % {'id': self.id}, |
04ce7f54 | 119 | 'time': escape(tzdate(self.time)), |
0d52c382 ER |
120 | 'requester': escape(self.requester), |
121 | 'priority': self.priority, | |
122 | 'max_jobs': self.max_jobs, | |
123 | 'flags': string.join(self.flags) | |
124 | }) | |
dfff8bd5 MM |
125 | f.write("<ul>\n") |
126 | for b in self.batches: | |
eda57100 | 127 | b.dump_html(f, self.id) |
dfff8bd5 | 128 | f.write("</ul>\n") |
0d52c382 | 129 | f.write("</div>\n") |
0cdc1fef | 130 | |
dfff8bd5 MM |
131 | def write_to(self, f): |
132 | f.write(""" | |
0638381b | 133 | <group id="%s" no="%d" flags="%s"> |
e2cad913 | 134 | <requester email='%s'>%s</requester> |
cf1741af | 135 | <time>%d</time> |
b3c8d962 AM |
136 | <priority>%d</priority> |
137 | <maxjobs>%d</maxjobs>\n""" % (self.id, self.no, string.join(self.flags), | |
0d52c382 | 138 | escape(self.requester_email), escape(self.requester), |
b3c8d962 | 139 | self.time, self.priority, self.max_jobs)) |
dfff8bd5 MM |
140 | for b in self.batches: |
141 | b.write_to(f) | |
142 | f.write(" </group>\n\n") | |
51a6a3a6 | 143 | |
dfff8bd5 MM |
144 | def is_done(self): |
145 | ok = 1 | |
146 | for b in self.batches: | |
147 | if not b.is_done(): | |
148 | ok = 0 | |
149 | return ok | |
59ce7cd6 | 150 | |
51a6a3a6 | 151 | class Batch: |
dfff8bd5 MM |
152 | def __init__(self, e): |
153 | self.bconds_with = [] | |
154 | self.bconds_without = [] | |
155 | self.builders = [] | |
156 | self.builders_status = {} | |
1432ffd5 | 157 | self.builders_status_time = {} |
b4d7e94a | 158 | self.builders_status_buildtime = {} |
aab485ec | 159 | self.kernel = "" |
d6139a25 | 160 | self.defines = {} |
be264f26 | 161 | self.target = [] |
dfff8bd5 MM |
162 | self.branch = "" |
163 | self.src_rpm = "" | |
164 | self.info = "" | |
165 | self.spec = "" | |
166 | self.command = "" | |
167 | self.command_flags = [] | |
db286098 | 168 | self.skip = [] |
dfff8bd5 MM |
169 | self.gb_id = "" |
170 | self.b_id = attr(e, "id") | |
171 | self.depends_on = string.split(attr(e, "depends-on")) | |
be44c85d | 172 | self.upgraded = True |
266325ca ER |
173 | |
174 | self.parse_xml(e) | |
175 | ||
a73fab54 | 176 | self._topdir = '/tmp/B.%s' % self.b_id |
266325ca ER |
177 | |
178 | def parse_xml(self, e): | |
dfff8bd5 MM |
179 | for c in e.childNodes: |
180 | if is_blank(c): continue | |
b4d7e94a | 181 | |
dfff8bd5 MM |
182 | if c.nodeType != Element.ELEMENT_NODE: |
183 | log.panic("xml: evil batch child %d" % c.nodeType) | |
184 | if c.nodeName == "src-rpm": | |
b4d7e94a | 185 | self.src_rpm = text(c) |
dfff8bd5 | 186 | elif c.nodeName == "spec": |
8ecc8666 ER |
187 | # normalize specname, specname is used as buildlog and we don't |
188 | # want to be exposed to directory traversal attacks | |
b4d7e94a | 189 | self.spec = text(c).split('/')[-1] |
dfff8bd5 MM |
190 | elif c.nodeName == "command": |
191 | self.spec = "COMMAND" | |
b4d7e94a | 192 | self.command = text(c).strip() |
dfff8bd5 MM |
193 | self.command_flags = string.split(attr(c, "flags", "")) |
194 | elif c.nodeName == "info": | |
b4d7e94a | 195 | self.info = text(c) |
aab485ec | 196 | elif c.nodeName == "kernel": |
b4d7e94a | 197 | self.kernel = text(c) |
d6139a25 ER |
198 | elif c.nodeName == "define": |
199 | define = attr(c, "name") | |
200 | self.defines[define] = text(c) | |
be264f26 | 201 | elif c.nodeName == "target": |
b4d7e94a | 202 | self.target.append(text(c)) |
db286098 | 203 | elif c.nodeName == "skip": |
b4d7e94a | 204 | self.skip.append(text(c)) |
dfff8bd5 | 205 | elif c.nodeName == "branch": |
b4d7e94a | 206 | self.branch = text(c) |
dfff8bd5 | 207 | elif c.nodeName == "builder": |
b4d7e94a | 208 | key = text(c) |
b051f064 ER |
209 | self.builders.append(key) |
210 | self.builders_status[key] = attr(c, "status", "?") | |
211 | self.builders_status_time[key] = attr(c, "time", "0") | |
b4d7e94a | 212 | self.builders_status_buildtime[key] = "0" #attr(c, "buildtime", "0") |
dfff8bd5 | 213 | elif c.nodeName == "with": |
b4d7e94a | 214 | self.bconds_with.append(text(c)) |
dfff8bd5 | 215 | elif c.nodeName == "without": |
b4d7e94a | 216 | self.bconds_without.append(text(c)) |
dfff8bd5 MM |
217 | else: |
218 | log.panic("xml: evil batch child (%s)" % c.nodeName) | |
0d52c382 | 219 | |
266325ca ER |
220 | def get_package_name(self): |
221 | if len(self.spec) <= 5: | |
222 | return None | |
223 | return self.spec[:-5] | |
224 | ||
225 | def tmpdir(self): | |
226 | """ | |
227 | return tmpdir for this batch job building | |
228 | """ | |
229 | # it's better to have TMPDIR and BUILD dir on same partition: | |
230 | # + /usr/bin/bzip2 -dc /home/services/builder/rpm/packages/kernel/patch-2.6.27.61.bz2 | |
231 | # patch: **** Can't rename file /tmp/B.a1b1d3/poKWwRlp to drivers/scsi/hosts.c : No such file or directory | |
232 | path = os.path.join(self._topdir, 'BUILD', 'tmp') | |
233 | return path | |
234 | ||
dfff8bd5 MM |
235 | def is_done(self): |
236 | ok = 1 | |
237 | for b in self.builders: | |
238 | s = self.builders_status[b] | |
61af514e | 239 | if not s.startswith("OK") and not s.startswith("SKIP") and not s.startswith("UNSUPP") and not s.startswith("FAIL"): |
dfff8bd5 MM |
240 | ok = 0 |
241 | return ok | |
0d52c382 | 242 | |
dfff8bd5 MM |
243 | def dump(self, f): |
244 | f.write(" batch: %s/%s\n" % (self.src_rpm, self.spec)) | |
245 | f.write(" info: %s\n" % self.info) | |
aab485ec | 246 | f.write(" kernel: %s\n" % self.kernel) |
d6139a25 | 247 | f.write(" defines: %s\n" % self.defines_string()) |
be264f26 | 248 | f.write(" target: %s\n" % self.target_string()) |
dfff8bd5 MM |
249 | f.write(" branch: %s\n" % self.branch) |
250 | f.write(" bconds: %s\n" % self.bconds_string()) | |
251 | builders = [] | |
252 | for b in self.builders: | |
253 | builders.append("%s:%s" % (b, self.builders_status[b])) | |
254 | f.write(" builders: %s\n" % string.join(builders)) | |
51a6a3a6 | 255 | |
dfff8bd5 MM |
256 | def is_command(self): |
257 | return self.command != "" | |
6953ce5d | 258 | |
eda57100 | 259 | def dump_html(self, f, rid): |
dfff8bd5 | 260 | f.write("<li>\n") |
bd080018 | 261 | if self.is_command(): |
0c2e0afa | 262 | desc = "SH: <pre>%s</pre> flags: [%s]" % (self.command, ' '.join(self.command_flags)) |
dfff8bd5 | 263 | else: |
64c5a6cb | 264 | package_url = "http://git.pld-linux.org/gitweb.cgi?p=packages/%(package)s.git;f=%(spec)s;h=%(branch)s;a=shortlog" % { |
59b3448a ER |
265 | 'spec': self.spec, |
266 | 'branch': self.branch, | |
267 | 'package': self.spec[:-5], | |
268 | } | |
d6139a25 | 269 | desc = "%(src_rpm)s (<a href=\"%(package_url)s\">%(spec)s -r %(branch)s</a>%(rpmopts)s)" % { |
59b3448a ER |
270 | 'src_rpm': self.src_rpm, |
271 | 'spec': self.spec, | |
272 | 'branch': self.branch, | |
d6139a25 | 273 | 'rpmopts': self.bconds_string() + self.kernel_string() + self.target_string() + self.defines_string(), |
59b3448a ER |
274 | 'package_url': package_url, |
275 | } | |
dfff8bd5 MM |
276 | f.write("%s <small>[" % desc) |
277 | builders = [] | |
dfff8bd5 MM |
278 | for b in self.builders: |
279 | s = self.builders_status[b] | |
2fec103c | 280 | if s.startswith("OK"): |
dfff8bd5 | 281 | c = "green" |
2b9e7381 | 282 | elif s.startswith("FAIL"): |
dfff8bd5 | 283 | c = "red" |
2fec103c | 284 | elif s.startswith("SKIP"): |
dfff8bd5 | 285 | c = "blue" |
2fec103c | 286 | elif s.startswith("UNSUPP"): |
769856bc | 287 | c = "fuchsia" |
dfff8bd5 MM |
288 | else: |
289 | c = "black" | |
290 | link_pre = "" | |
291 | link_post = "" | |
61af514e | 292 | if (s.startswith("OK") or s.startswith("SKIP") or s.startswith("UNSUPP") or s.startswith("FAIL")) and len(self.spec) > 5: |
dfff8bd5 MM |
293 | if self.is_command(): |
294 | bl_name = "command" | |
295 | else: | |
296 | bl_name = self.spec[:len(self.spec)-5] | |
7169155e | 297 | lin_ar = b.replace('noauto-','') |
eda57100 | 298 | path = "/%s/%s/%s,%s.bz2" % (lin_ar.replace('-','/'), s, bl_name, rid) |
dfff8bd5 | 299 | is_ok = 0 |
2fec103c | 300 | if s.startswith("OK"): |
428b18a2 | 301 | is_ok = 1 |
7169155e | 302 | bld = lin_ar.split('-') |
e40ffefe | 303 | tree_name = '-'.join(bld[:-1]) |
7edf20a9 | 304 | tree_arch = '-'.join(bld[-1:]) |
7a8e28a8 JR |
305 | link_pre = "<a href=\"%s/index.php?dist=%s&arch=%s&ok=%d&name=%s&id=%s&action=tail\">" \ |
306 | % (config.buildlogs, urllib.quote(tree_name), urllib.quote(tree_arch), is_ok, urllib.quote(bl_name), urllib.quote(rid)) | |
dfff8bd5 | 307 | link_post = "</a>" |
b4d7e94a ER |
308 | |
309 | def ftime(s): | |
310 | t = float(s) | |
311 | if t > 0: | |
312 | return time.asctime(time.localtime(t)) | |
313 | else: | |
314 | return 'N/A' | |
315 | ||
316 | tooltip = "last update: %(time)s\nbuild time: %(buildtime)s" % { | |
317 | 'time' : ftime(self.builders_status_time[b]), | |
318 | 'buildtime' : ftime(self.builders_status_buildtime[b]), | |
7d73f518 ER |
319 | } |
320 | builders.append(link_pre + | |
321 | "<font color='%(color)s'><b title=\"%(tooltip)s\">%(builder)s:%(status)s</b></font>" % { | |
322 | 'color' : c, | |
323 | 'builder' : b, | |
324 | 'status' : s, | |
325 | 'tooltip' : cgi.escape(tooltip, True), | |
326 | } | |
327 | + link_post) | |
dfff8bd5 | 328 | f.write("%s]</small></li>\n" % string.join(builders)) |
0cdc1fef | 329 | |
4e14a9bc ER |
330 | def rpmbuild_opts(self): |
331 | """ | |
332 | return all rpmbuild options related to this build | |
333 | """ | |
5c4d43c0 | 334 | rpmopts = self.bconds_string() + self.kernel_string() + self.target_string() + self.defines_string() |
4e14a9bc | 335 | rpmdefs = \ |
266325ca ER |
336 | "--define '_topdir %s' " % self._topdir + \ |
337 | "--define '_specdir %{_topdir}' " \ | |
4e14a9bc | 338 | "--define '_sourcedir %{_specdir}' " \ |
266325ca | 339 | "--define '_rpmdir %{_topdir}/RPMS' " \ |
b9b4ac17 | 340 | "--define '_builddir %{_topdir}/BUILD' " |
d6139a25 | 341 | return rpmdefs + rpmopts |
4e14a9bc | 342 | |
aab485ec | 343 | def kernel_string(self): |
344 | r = "" | |
345 | if self.kernel != "": | |
346 | r = " --define 'alt_kernel " + self.kernel + "'" | |
347 | return r | |
348 | ||
be264f26 ER |
349 | def target_string(self): |
350 | if len(self.target) > 0: | |
351 | return " --target " + ",".join(self.target) | |
352 | else: | |
353 | return "" | |
354 | ||
dfff8bd5 MM |
355 | def bconds_string(self): |
356 | r = "" | |
357 | for b in self.bconds_with: | |
358 | r = r + " --with " + b | |
359 | for b in self.bconds_without: | |
360 | r = r + " --without " + b | |
361 | return r | |
0d52c382 | 362 | |
d6139a25 ER |
363 | def defines_string(self): |
364 | r = "" | |
365 | for key,value in self.defines.items(): | |
366 | r += " --define '%s %s'" % (key, value) | |
367 | return r | |
368 | ||
369 | def defines_xml(self): | |
370 | r = "" | |
371 | for key,value in self.defines.items(): | |
372 | r += "<define name='%s'>%s</define>\n" % (escape(key), escape(value)) | |
373 | return r | |
374 | ||
4e14a9bc ER |
375 | def default_target(self, arch): |
376 | self.target.append("%s-pld-linux" % arch) | |
377 | ||
dfff8bd5 MM |
378 | def write_to(self, f): |
379 | f.write(""" | |
30dbf6a3 | 380 | <batch id='%s' depends-on='%s'> |
cf1741af | 381 | <src-rpm>%s</src-rpm> |
6953ce5d | 382 | <command flags="%s">%s</command> |
cf1741af | 383 | <spec>%s</spec> |
57b6e61d | 384 | <branch>%s</branch> |
0d52c382 | 385 | <info>%s</info>\n""" % (self.b_id, |
dfff8bd5 | 386 | string.join(map(lambda (b): b.b_id, self.depends_on)), |
0d52c382 | 387 | escape(self.src_rpm), |
dfff8bd5 | 388 | escape(' '.join(self.command_flags)), escape(self.command), |
655fbfb2 | 389 | escape(self.spec), escape(self.branch), escape(self.info))) |
390 | if self.kernel != "": | |
98ff6b42 | 391 | f.write(" <kernel>%s</kernel>\n" % escape(self.kernel)) |
dfff8bd5 MM |
392 | for b in self.bconds_with: |
393 | f.write(" <with>%s</with>\n" % escape(b)) | |
be264f26 ER |
394 | for b in self.target: |
395 | f.write(" <target>%s</target>\n" % escape(b)) | |
dfff8bd5 MM |
396 | for b in self.bconds_without: |
397 | f.write(" <without>%s</without>\n" % escape(b)) | |
d6139a25 ER |
398 | if self.defines: |
399 | f.write(" %s\n" % self.defines_xml()) | |
dfff8bd5 | 400 | for b in self.builders: |
b4d7e94a ER |
401 | if self.builders_status_buildtime.has_key(b): |
402 | t = self.builders_status_buildtime[b] | |
403 | else: | |
404 | t = "0" | |
405 | f.write(" <builder status='%s' time='%s' buildtime='%s'>%s</builder>\n" % \ | |
406 | (escape(self.builders_status[b]), self.builders_status_time[b], t, escape(b))) | |
dfff8bd5 | 407 | f.write(" </batch>\n") |
0d52c382 | 408 | |
dfff8bd5 MM |
409 | def log_line(self, l): |
410 | log.notice(l) | |
411 | if self.logfile != None: | |
412 | util.append_to(self.logfile, l) | |
cf1741af | 413 | |
dfff8bd5 MM |
414 | def expand_builders(batch, all_builders): |
415 | all = [] | |
416 | for bld in batch.builders: | |
417 | res = [] | |
418 | for my_bld in all_builders: | |
419 | if fnmatch.fnmatch(my_bld, bld): | |
420 | res.append(my_bld) | |
421 | if res != []: | |
422 | all.extend(res) | |
423 | else: | |
424 | all.append(bld) | |
425 | batch.builders = all | |
1089bec4 | 426 | |
59ce7cd6 | 427 | class Notification: |
dfff8bd5 MM |
428 | def __init__(self, e): |
429 | self.batches = [] | |
430 | self.kind = 'notification' | |
431 | self.group_id = attr(e, "group-id") | |
432 | self.builder = attr(e, "builder") | |
433 | self.batches = {} | |
b4d7e94a | 434 | self.batches_buildtime = {} |
dfff8bd5 MM |
435 | for c in e.childNodes: |
436 | if is_blank(c): continue | |
437 | if c.nodeType != Element.ELEMENT_NODE: | |
438 | log.panic("xml: evil notification child %d" % c.nodeType) | |
439 | if c.nodeName == "batch": | |
440 | id = attr(c, "id") | |
441 | status = attr(c, "status") | |
b4d7e94a | 442 | buildtime = attr(c, "buildtime", "0") |
2fec103c | 443 | if not status.startswith("OK") and not status.startswith("SKIP") and not status.startswith("UNSUPP") and not status.startswith("FAIL"): |
b6c5ef3e | 444 | log.panic("xml notification: bad status: %s" % status) |
dfff8bd5 | 445 | self.batches[id] = status |
b4d7e94a | 446 | self.batches_buildtime[id] = buildtime |
dfff8bd5 MM |
447 | else: |
448 | log.panic("xml: evil notification child (%s)" % c.nodeName) | |
59ce7cd6 | 449 | |
dfff8bd5 MM |
450 | def apply_to(self, q): |
451 | for r in q.requests: | |
452 | if r.kind == "group": | |
453 | for b in r.batches: | |
454 | if self.batches.has_key(b.b_id): | |
455 | b.builders_status[self.builder] = self.batches[b.b_id] | |
1432ffd5 | 456 | b.builders_status_time[self.builder] = time.time() |
b4d7e94a | 457 | b.builders_status_buildtime[self.builder] = "0" #self.batches_buildtime[b.b_id] |
59ce7cd6 | 458 | |
51a6a3a6 | 459 | def build_request(e): |
dfff8bd5 MM |
460 | if e.nodeType != Element.ELEMENT_NODE: |
461 | log.panic("xml: evil request element") | |
462 | if e.nodeName == "group": | |
463 | return Group(e) | |
464 | elif e.nodeName == "notification": | |
465 | return Notification(e) | |
466 | elif e.nodeName == "command": | |
467 | # FIXME | |
468 | return Command(e) | |
469 | else: | |
9ef8e784 | 470 | log.panic("xml: evil request [%s]" % e.nodeName) |
51a6a3a6 | 471 | |
94169186 | 472 | def parse_request(f): |
5180bf1f | 473 | d = parseString(f) |
dfff8bd5 | 474 | return build_request(d.documentElement) |
0d52c382 | 475 | |
94169186 | 476 | def parse_requests(f): |
5180bf1f | 477 | d = parseString(f) |
dfff8bd5 MM |
478 | res = [] |
479 | for r in d.documentElement.childNodes: | |
480 | if is_blank(r): continue | |
481 | res.append(build_request(r)) | |
482 | return res |