/[qa]/trunk/pts/www/bin/other_to_xml.py
ViewVC logotype

Contents of /trunk/pts/www/bin/other_to_xml.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2156 - (hide annotations) (download) (as text)
Sat Feb 28 09:21:13 2009 UTC (4 years, 3 months ago) by zack
File MIME type: text/x-python
File size: 18945 byte(s)
switch to python-yaml for parsing transitions file (python-syck has gone for good)
1 jeroen 1154 #!/usr/bin/python
2 zack 2049 # -*- coding: utf-8 -*-
3 hertzog 344
4     # Make sure tabs expand to 8 spaces in vim
5     # vim: expandtab
6    
7 jeroen 1154 # Copyright 2002 Raphaƫl Hertzog
8 jeroen 947 # Copyright 2005 Jeroen van Wolffelaar
9 zack 1820 # Copyright 2007-2008 Stefano Zacchiroli
10 hertzog 351 # This file is distributed under the terms of the General Public License
11     # version 2 or (at your option) any later version.
12    
13 zack 2156 import os.path, rfc822, sys, string, re, email, common, cPickle, yaml
14 hertzog 344 from xml.dom import implementation, ext
15    
16     from config import dir, odir, root
17 zack 2049 from common import hash_name
18 hertzog 344
19 zack 2155 # sources <-> binaries correspondances, kind of global variables
20 zack 1939 source2binaries = {} # maps a source package to its binaries
21     binary2source = {} # maps a binary package to its source
22 hertzog 344
23 zack 1951 def read_shortdesc(fname):
24     global binary2source
25     source_descs = {} # source package -> (binary package -> short description)
26     for line in open(fname):
27     pkg, shortdesc = line.strip().split("\t", 1)
28     if not binary2source.has_key(pkg):
29     continue
30     src = binary2source[pkg]
31     if not source_descs.has_key(src):
32     source_descs[src] = {}
33     source_descs[src][pkg] = shortdesc
34     return source_descs
35    
36 zack 1939 def read_bug_summary(fname):
37     global binary2source
38 zack 1951 summary = {} # source package -> bug count
39 zack 1939 for line in open(fname):
40     pkg, count = line.split()
41     if not binary2source.has_key(pkg):
42     continue
43     src = binary2source[pkg]
44     if not summary.has_key(src):
45     summary[src] = 0
46     summary[src] += int(count)
47     return summary
48    
49 zack 2155 def read_low_threshold_nmu(fname):
50     """read low threshold NMU info"""
51     emails = []
52     if os.path.exists(fname):
53     f = open(fname)
54     devel_php_RE = \
55     re.compile(r'http://qa\.debian\.org/developer\.php\?login=([^\s&]+)')
56     word_RE = re.compile(r'^\w+$')
57     for line in f.readlines():
58     match = devel_php_RE.search(line)
59     while match: # look for several matches on the same line
60     email = None
61     login = match.group(1)
62     if word_RE.match(login):
63     email = login + '@debian.org'
64     elif login.find('@') >= 0:
65     email = login
66     if email:
67     emails.append(email)
68     line = line[match.end():]
69     match = devel_php_RE.search(line)
70     f.close()
71     return emails
72    
73     def read_transitions(fname):
74 zack 2156 y = yaml.load(file(fname))
75 zack 2155 packages = {} # maps pkg to the _list_ of transitions they are involved in
76 zack 2156 for id, transition in y.iteritems():
77 zack 2155 for pkg in transition['packages']:
78     if not packages.has_key(pkg):
79     packages[pkg] = []
80     packages[pkg].append(id)
81     return packages
82    
83     def read_piuparts(fname):
84     failures = {}
85     if os.path.exists(fname):
86     f = open(fname)
87     for line in f.readlines():
88     try:
89     src, outcome, log = line.rstrip().split(None, 2)
90     if outcome == "fail":
91     failures[src] = log
92     except ValueError:
93     pass
94     f.close()
95     return failures
96    
97     def read_lintian_info(fname):
98     lintian = {} # maps source pkg names to pairs <errors_no, warnings_no>
99     for line in open(fname).readlines():
100     try:
101     (pkg, errors_no, warnings_no) = line.split()
102     lintian[pkg] = (int(errors_no), int(warnings_no))
103     except ValueError:
104     continue
105     return lintian
106    
107     # DEHS textual file are line oriented with lines like "field: value"
108     def read_dehs(fname):
109     f = open(fname)
110     for line in f.readlines():
111     yield map(string.strip, line.split(':'))
112     f.close()
113    
114    
115     # Initialization: fill binary <-> source maps
116     f = open(dir + "/sources.map", "r")
117     while 1:
118     line = f.readline();
119     if not line: break #eof
120     line = line.strip()
121     (binary, source) = line.split(None, 1)
122     if not source2binaries.has_key(source):
123     source2binaries[source] = []
124     source2binaries[source].append(binary)
125     binary2source[binary] = source
126     f.close()
127    
128 hertzog 344 # Read all the bugs stats
129     bugs = {}
130     f = open(dir + "/bugs.txt")
131     while 1:
132     line = f.readline()
133     if not line: break #eof
134     line = line.strip()
135     (binary, stats) = line.split(None, 1)
136 hertzog 1911 bugs[binary] = [ string.atoi(i) for i in stats.split() ]
137 hertzog 344 f.close()
138    
139 hertzog 1911 srcbugs = {}
140     f = open(dir + "/bugs-src.txt")
141     while 1:
142     line = f.readline()
143     if not line: break #eof
144     line = line.strip()
145     (pkg, stats) = line.split(":", 1)
146 hertzog 1988 try:
147     srcbugs[pkg] = [ string.atoi(i) for i in stats.replace("(", " ").replace(")", " ").split() ]
148     except:
149     sys.stderr.write("Failed to parse bugs-src.txt stats for %s: %s" % (pkg, stats))
150 hertzog 1911 f.close()
151    
152 zack 1939 gift_bugs = read_bug_summary(os.path.join(dir, 'bugs.gift.txt'))
153     help_bugs = read_bug_summary(os.path.join(dir, 'bugs.help.txt'))
154    
155 hertzog 344 # Read all the PTS stats
156     pts = {}
157     f = open(dir + "/count.txt")
158     while 1:
159     line = f.readline()
160     if not line: break #eof
161     line = line.strip()
162     (binary, stats) = line.split(None, 1)
163     pts[binary] = stats
164     f.close()
165    
166 hertzog 372 # Read the lisf of packages with debcheck problems
167     debcheck = {}
168 luk 2124 for dist in ("oldstable", "stable", "testing", "unstable"):
169 hertzog 372 debcheck[dist] = {}
170     f = open(dir + "/debcheck-" + dist)
171     while 1:
172     line = f.readline()
173     if not line: break #eof
174     debcheck[dist][line.strip()] = 1
175     f.close()
176    
177 jeroen 947 # Read the list of packages with override disparities
178     override = {}
179     for dist in ("unstable", "experimental"):
180     override[dist] = {}
181     f = open(dir + "/override-disparities." + dist)
182     for line in f:
183     if line[0] != '-':
184     source = line.strip()[:-1]
185     override[dist][source] = []
186     else:
187     override[dist][source].append(line.strip()[2:])
188     f.close()
189    
190 hertzog 479 # Read the list of source packages with debconf templates
191     debconf = {}
192 hertzog 692 # DISABLED until ddtp.debian.org is setup again
193     #f = open(dir + "/debconf-list")
194     #while 1:
195     # line = f.readline()
196     # if not line: break #eof
197     # line = line.strip()
198     # debconf[line] = 1;
199     #f.close()
200 hertzog 479
201 hertzog 357 # Read the current signature of other.xml files
202     sigs = {}
203     if os.path.exists(odir + "/other.sigs"):
204     f = open(odir + "/other.sigs", "r")
205     sigs = cPickle.load(f)
206     f.close()
207    
208 hertzog 560 # Read the wnpp information. [PvR]
209     wnpp = {}
210 jeroen 912 if os.path.exists(dir + "/wnpp_rm"):
211     f = open(dir + "/wnpp_rm")
212 hertzog 560 while 1:
213     line = f.readline()
214     if not line: break # eof
215 hertzog 1843 line = line.strip()
216     try:
217     (package, type, number) = line.split("|")[0].split()
218     except:
219 hertzog 1882 #too many badly formatted ITP... disable warning. --RH
220     #sys.stderr.write("Ignoring bad line '%s' in wnpp_rm\n" % line)
221 hertzog 1843 pass
222 jeroen 912 wnpp[package[:-1]] = (type, number)
223 hertzog 560 f.close()
224    
225 hertzog 1049 # Read patches information [FG]
226 hertzog 1887 ubuntu_patches = {}
227 hertzog 1049 # this can be easily inserted into a new update_patches.py if it becomes too
228     # heavy to parse the file
229     if os.path.exists(dir + "/patches.ubuntu"):
230     f = open(dir + "/patches.ubuntu")
231     for line in f.readlines():
232     (package, rel_url) = line.split(' ', 2)
233     rel_url = rel_url.strip()
234     r = re.search("_(\S+).patch", line)
235     if not r:
236     continue
237     version = r.group(1)
238 hertzog 1887 ubuntu_patches[package] = (version, "http://patches.ubuntu.com/" + rel_url)
239 zack 1749 f.close()
240 hertzog 1049
241 hertzog 1887 ubuntu_versions = {}
242     if os.path.exists(dir + "/versions.ubuntu"):
243     f = open(dir + "/versions.ubuntu")
244     for line in f.readlines():
245     (package, version) = line.split(' ', 2)
246     version = version.strip()
247     ubuntu_versions[package] = (version, "https://launchpad.net/ubuntu/+source/" + package)
248     f.close()
249    
250     ubuntu_bugs = {}
251     if os.path.exists(dir + "/bugs.ubuntu"):
252     f = open(dir + "/bugs.ubuntu")
253     for line in f.readlines():
254     (package, count) = line.split('|', 2)
255     count = count.strip()
256     ubuntu_bugs[package] = (count, "https://bugs.launchpad.net/ubuntu/+source/" + package)
257     f.close()
258    
259 zack 1773 # write lowThresholdNmu info to a (global, i.e. not per-package) file
260 zack 1800 #
261     # XXX this is sub-optimal, as the XSLT rendering of each package page will have
262     # to read the whole XML file each time. However, this can't be fixed here
263     # unless we have somewhere an additional map (in the spirit of sources.map)
264     # mapping source package names to maintainer emails
265 zack 1773 low_nmu_emails = read_low_threshold_nmu(dir + "/low_threshold_nmu.txt")
266     f = open(odir + "/low_threshold_nmu.emails.xml", 'w')
267     f.write("<emails>\n");
268     f.writelines(map(lambda s: " <email>%s</email>\n" % s, low_nmu_emails))
269     f.write("</emails>\n");
270     f.close()
271    
272 zack 1866 # read the list of packages involved in transitions
273     transitions = read_transitions(os.path.join(dir, "transitions.yaml"))
274    
275 zack 2048 piuparts = read_piuparts(os.path.join(dir, "piuparts.txt"))
276    
277 zack 1927 # read QA lintian info
278     lintian = read_lintian_info(os.path.join(dir, "lintian.qa-list.txt"))
279    
280 zack 1800 # read the list of packages indexed by svnbuildstat.debian.net
281     svnbuildstat = {}
282     f = open(os.path.join(dir, "svnbuildstat_list.txt"))
283     for pkgname in map(string.rstrip, f.readlines()):
284     svnbuildstat[pkgname] = True
285     f.close()
286    
287 zack 1823 # read info gathered from dehs.alioth.debian.org
288     dehs = {}
289     for pkgname, version in read_dehs(os.path.join(dir, "dehs_out_of_date.txt")):
290     if not dehs.has_key(pkgname):
291     dehs[pkgname] = {}
292     dehs[pkgname]['newer'] = version
293     for pkgname, msg in read_dehs(os.path.join(dir, "dehs_error.txt")):
294     if not dehs.has_key(pkgname):
295     dehs[pkgname] = {}
296     dehs[pkgname]['error'] = msg
297    
298 zack 1951 # read short descriptions
299     shortdescs = read_shortdesc(os.path.join(dir, "shortdesc.txt"))
300    
301 hertzog 344 # Create the XML documents
302     while 1:
303     line = sys.stdin.readline()
304     if not line: break #eof
305     pkg = line.strip()
306    
307     doc = implementation.createDocument(None, "other", None)
308     root_elt = doc.documentElement
309 zack 2049 hash = hash_name(pkg)
310 hertzog 344
311 hertzog 372 # Add debcheck availability info
312     dc_sig = ""
313     elt = doc.createElement("debcheck")
314 luk 2124 for dist in ("oldstable", "stable", "testing", "unstable"):
315 hertzog 372 if debcheck[dist].has_key(pkg):
316     elt.setAttribute(dist, "yes")
317     dc_sig += "y"
318     else:
319     elt.setAttribute(dist, "no")
320     dc_sig += "n"
321     root_elt.appendChild(elt)
322    
323 hertzog 479 # Add debconf templates availibilty info
324     if debconf.has_key(pkg):
325     root_elt.setAttribute("debconf", "yes")
326     dc_sig += "y"
327     else:
328     root_elt.setAttribute("debconf", "no")
329     dc_sig += "n"
330    
331 hertzog 344 # Get PTS stats
332     elt = doc.createElement("pts")
333     elt.setAttribute("count", pts.get(pkg, "0"))
334     root_elt.appendChild(elt)
335    
336     # Get BTS stats
337     elt = doc.createElement("bugs")
338 zack 1939 (s_rc, s_rc_m, s_normal, s_normal_m, s_wishlist, s_wishlist_m, s_fixed,
339     s_fixed_m, s_patch, s_patch_m) = \
340     srcbugs.get(pkg, [0,0,0,0,0,0,0,0,0,0])
341     binlist = source2binaries.get(pkg, [])
342 hertzog 357 binlist.sort()
343     subsig = ""
344     for binary in binlist:
345 hertzog 344 sub_elt = doc.createElement("item")
346     sub_elt.setAttribute("name", binary)
347 hertzog 1911 (rc, normal, wishlist, fixed, patch) = bugs.get(binary, [0,0,0,0,0])
348     sub_elt.setAttribute("rc", "%d" % rc)
349     sub_elt.setAttribute("normal", "%d" % normal)
350     sub_elt.setAttribute("wishlist", "%d" % wishlist)
351     sub_elt.setAttribute("fixed", "%d" % fixed)
352     sub_elt.setAttribute("patch", "%d" % patch)
353 hertzog 344 all = rc + normal + wishlist + fixed
354     sub_elt.setAttribute("all", "%d" % all)
355     elt.appendChild(sub_elt)
356 hertzog 357 if len(subsig):
357 hertzog 1047 subsig = "%s|%d|%d" % (subsig, all, patch)
358 hertzog 357 else:
359 hertzog 1047 subsig = "%d|%d" % (all, patch)
360 hertzog 1911
361 hertzog 344 elt.setAttribute("rc", "%d" % s_rc)
362 hertzog 1911 if s_rc != s_rc_m:
363     elt.setAttribute("rc_m", "%d" % s_rc_m)
364 hertzog 344 elt.setAttribute("normal", "%d" % s_normal)
365 hertzog 1911 if s_normal != s_normal_m:
366     elt.setAttribute("normal_m", "%d" % s_normal_m)
367 hertzog 344 elt.setAttribute("wishlist", "%d" % s_wishlist)
368 hertzog 1911 if s_wishlist != s_wishlist_m:
369     elt.setAttribute("wishlist_m", "%d" % s_wishlist_m)
370 hertzog 344 elt.setAttribute("fixed", "%d" % s_fixed)
371 hertzog 1911 if s_fixed != s_fixed_m:
372     elt.setAttribute("fixed_m", "%d" % s_fixed_m)
373 hertzog 1047 elt.setAttribute("patch", "%d" % s_patch)
374 hertzog 1911 if s_patch != s_patch_m:
375     elt.setAttribute("patch_m", "%d" % s_patch_m)
376     s_all = s_fixed + s_wishlist + s_normal + s_rc
377     s_all_m = s_fixed_m + s_wishlist_m + s_normal_m + s_rc_m
378     elt.setAttribute("all", "%d" % s_all)
379     if s_all != s_all_m:
380     elt.setAttribute("all_m", "%d" % s_all_m)
381 hertzog 344 root_elt.appendChild(elt)
382 zack 1939 if gift_bugs.has_key(pkg):
383     s_gift = gift_bugs[pkg]
384     else:
385     s_gift = 0
386     elt.setAttribute("gift", str(s_gift))
387     if help_bugs.has_key(pkg):
388     s_help = help_bugs[pkg]
389     else:
390     s_help = 0
391     elt.setAttribute("help", str(s_help))
392 hertzog 344
393 hertzog 560 # Get WNPP information. [PvR]
394     if wnpp.has_key(pkg):
395     (type, number) = wnpp[pkg]
396     elt = doc.createElement("wnpp")
397     elt.setAttribute("type", type)
398     elt.setAttribute("bugnumber", number)
399     root_elt.appendChild(elt)
400     root_elt.setAttribute("wnpp", "yes")
401     wnpp_sig = "%s%s" % (type,number)
402     else:
403     root_elt.setAttribute("wnpp", "no")
404     wnpp_sig = "n"
405 hertzog 643
406 jeroen 947 # Get override info [JvW]
407     override_elt = None
408     override_sig = []
409     for dist in [ 'unstable', 'experimental' ]:
410     if override[dist].has_key(pkg):
411     if not override_elt: override_elt = doc.createElement("override")
412     disparities = override[dist][pkg]
413     override_sig.append(disparities)
414     elt_g = doc.createElement("group")
415     elt_g.setAttribute("suite", dist)
416     for disp in disparities:
417     elt = doc.createTextNode(disp)
418     elt_disp = doc.createElement("disparity")
419     elt_disp.appendChild(elt)
420     elt_g.appendChild(elt_disp)
421 jeroen 950 override_elt.appendChild(elt_g)
422 jeroen 947
423     if override_elt:
424     root_elt.appendChild(override_elt)
425     root_elt.setAttribute("override", "yes")
426     else:
427     root_elt.setAttribute("override", "no")
428    
429 hertzog 1887 # Add Ubuntu information
430     if ubuntu_versions.has_key(pkg):
431     elt = doc.createElement("ubuntu")
432     (version, url) = ubuntu_versions[pkg]
433     ubuntu_sig = "ubuntu/ " + version
434     elt.setAttribute("version", unicode(version, 'UTF8', 'replace'))
435     elt.setAttribute("url", unicode(url, 'UTF8', 'replace'))
436     if ubuntu_bugs.has_key(pkg):
437     elt.setAttribute("bugs", "yes")
438     elt_bugs = doc.createElement("bugs")
439     (count, url) = ubuntu_bugs[pkg]
440     ubuntu_sig += "ubuntubugs/" + count
441     elt_bugs.setAttribute("count", unicode(count, 'UTF8', 'replace'))
442     elt_bugs.setAttribute("url", unicode(url, 'UTF8', 'replace'))
443     elt.appendChild(elt_bugs)
444     if ubuntu_patches.has_key(pkg):
445     elt.setAttribute("patch", "yes")
446     elt_patch = doc.createElement("patch")
447     (version, url) = ubuntu_patches[pkg]
448     ubuntu_sig += "ubuntupatch/" + version
449     elt_patch.setAttribute("version", unicode(version, 'UTF8', 'replace'))
450     elt_patch.setAttribute("url", unicode(url, 'UTF8', 'replace'))
451     elt.appendChild(elt_patch)
452 hertzog 1049 root_elt.appendChild(elt)
453 hertzog 1887 root_elt.setAttribute("ubuntu", "yes")
454 hertzog 1049 else:
455 hertzog 1887 root_elt.setAttribute("ubuntu", "no")
456     ubuntu_sig = "n"
457 hertzog 560
458 zack 1823 # Get DEHS information
459     if dehs.has_key(pkg):
460     elt = doc.createElement('dehs')
461     root_elt.appendChild(elt)
462     root_elt.setAttribute('dehs', 'yes')
463     if dehs[pkg].has_key('newer'):
464     elt.setAttribute('newer', dehs[pkg]['newer'])
465     if dehs[pkg].has_key('error'):
466     elt.setAttribute('error', 'yes')
467     dehs_sig = 'y'
468     else:
469     root_elt.setAttribute('dehs', 'no')
470     dehs_sig = 'n'
471    
472 zack 1800 # add svnbuildstat info
473     if svnbuildstat.has_key(pkg):
474     elt = doc.createElement("svnbuildstat")
475     root_elt.setAttribute("svnbuildstat", "yes")
476     root_elt.appendChild(elt)
477     svnbuildstat_sig = "y"
478     else:
479     root_elt.setAttribute("svnbuildstat", "no")
480     svnbuildstat_sig = "n"
481    
482 zack 2048 # add piuparts info
483     if piuparts.has_key(pkg):
484     #elt = doc.createElement("piuparts")
485     #root_elt.appendChild(elt)
486     root_elt.setAttribute("piuparts", "yes")
487     piuparts_sig = "y"
488     else:
489     root_elt.setAttribute("piuparts", "no")
490     piuparts_sig = "n"
491    
492 zack 1866 # add transitions info
493     if transitions.has_key(pkg):
494     elt = doc.createElement("transitions")
495     for id in transitions[pkg]:
496     trans_elt = doc.createElement("transition")
497     trans_elt.setAttribute("name", id)
498     elt.appendChild(trans_elt)
499     root_elt.setAttribute("transitions", "yes")
500     root_elt.appendChild(elt)
501     transitions_sig = "y"
502     else:
503     root_elt.setAttribute("transitions", "no")
504     transitions_sig = "n"
505    
506 zack 1927 # add lintian QA info
507     if lintian.has_key(pkg):
508     (errs, warns) = lintian[pkg]
509     elt = doc.createElement("lintian")
510     elt.setAttribute("errors", str(errs))
511     elt.setAttribute("warnings", str(warns))
512     root_elt.appendChild(elt)
513     root_elt.setAttribute("lintian", "yes")
514     lintian_sig = (errs, warns)
515     else:
516     root_elt.setAttribute("lintian", "no")
517     lintian_sig = (0, 0)
518    
519 zack 1951 # add short descriptions
520     elt = doc.createElement("descriptions")
521     root_elt.appendChild(elt)
522     if shortdescs.has_key(pkg):
523     for package, shortdesc in shortdescs[pkg].iteritems():
524     desc_elt = doc.createElement("shortdesc")
525     elt.appendChild(desc_elt)
526     desc_elt.setAttribute("package", package)
527     desc_text = doc.createTextNode(shortdesc)
528     desc_elt.appendChild(desc_text)
529     shortdesc_sig = str(shortdescs[pkg]).__hash__()
530     # XXX hash(str(...)) does not work: WTF?
531     else:
532 zack 1952 shortdesc_sig = ''.__hash__()
533 zack 1951
534 hertzog 357 # TODO: try to do that signature checking before the creation of XML DOM
535     # Build the sig and check if anything changed
536 zack 1823 sig = (pts.get(pkg, "0"), dc_sig, wnpp_sig, override_sig, dehs_sig,
537 zack 1939 ubuntu_sig, s_rc, s_normal, s_wishlist, s_fixed, s_gift, s_help,
538 zack 1951 subsig, svnbuildstat_sig, transitions_sig, lintian_sig,
539 zack 2048 shortdesc_sig, piuparts_sig)
540 jeroen 1033 if sigs.has_key(pkg) and sig == sigs[pkg] and \
541     os.path.isfile("%s/%s/%s/other.xml" % (odir, hash, pkg)):
542 hertzog 357 continue
543     sigs[pkg] = sig
544 hertzog 560
545 hertzog 344 # Output the data to the XML file
546 hertzog 812 try:
547     f = open("%s/%s/%s/other.xml" % (odir, hash, pkg), "w")
548 zack 1982 ext.PrettyPrint(doc, f, "utf-8")
549 hertzog 812 f.close()
550 zack 1982 except Exception, msg:
551     sys.stderr.write("Output problem for " + pkg + "/other.xml (%s)\n" %
552     msg);
553 hertzog 344
554 hertzog 357 # Store the signatures
555     f = open(odir + "/other.sigs", "w")
556     cPickle.dump(sigs, f, 0)
557     f.close()
558    

Properties

Name Value
svn:eol-style native
svn:executable *
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5