import os, time, signal, sys from toolbox import check_label def load_config(): cfg = {} execfile('autotestconfig.py', cfg) return cfg DEFAULTS = { # title prefix, overridable in autotestconfig 'PREFIX': '', 'KEEP': 15 } class Summary(object): def __init__(self, html_dir, config): self.html_dir = html_dir self.config = config def gather_revisions(self): revisions = [] for fn in os.listdir(self.html_dir): try: if check_label(fn): revisions.append(fn) except ValueError: pass revisions.sort() return revisions def gather_outcomes(self, revisions): outcomes = {} failures = {} counts = {} for rev in revisions: dir = os.path.join(self.html_dir, str(rev), 'failed') if os.path.isdir(dir): for fn in os.listdir(dir): failures.setdefault(fn, {})[rev] = True try: f = open(os.path.join(self.html_dir, str(rev), 'outcome'), 'r') except IOError: pass else: c = 0 for line in f: line = line.strip() outcomes[line[2:], rev] = line[0] c += 1 f.close() counts[rev] = c failures = failures.items() failures.sort() skips = {} for (fn, rev), outcome in outcomes.items(): if outcome == 's': skips.setdefault(rev, []).append(fn) self.failures = failures self.outcomes = outcomes self.counts = counts self.skips = skips modmax = 0 testnames = [] for fn, revs in self.failures: if '.py.' in fn: mod, test = fn.split('.py.', 1) elif '.txt.' in fn: mod, test = fn.split('.txt.', 1) else: mod, test = fn, '' modmax = max(modmax, len(mod)) if test.endswith('.html'): test = test[:-5] testnames.append((mod, test)) self.modmax = modmax self.testnames = testnames def getoutcome(self, fn, rev, mod): while (fn, rev) not in self.outcomes: if not mod: return ' ' fn = mod + '.py..html' i = mod.rfind('.') if i < 0: mod = '' else: mod = mod[:i] else: return self.outcomes[fn, rev] def revision_complete(self, rev): try: f = open(os.path.join(self.html_dir, str(rev), 'index.html'), 'r') f.seek(-34, 2) # xxx adjust taildata = f.read() f.close() except IOError: return False return 'Done.' in taildata def revisiondate(self, rev): st = os.stat(os.path.join(self.html_dir, rev)) t = time.localtime(st.st_mtime) return time.strftime('%d %b', t) def dump(self, revisions, prefix, filename): if len(revisions) == 1: title = 'Summary of the failures in revision %s' % (revisions[0],) else: title = 'Summary of the failures in the latest %d revisions' % (len(revisions),) title = self.config['PREFIX'] + title f = open(filename, 'wb') print >> f, '
' print >> f, ''
lines = []
for rev in revisions:
count_failures = 0
for fn, revs in self.failures:
if rev in revs:
count_failures += 1
count_skips = len(self.skips.get(rev, []))
if prefix:
link_pre = ''
link_post = ''
else:
link_pre = '' % (prefix, rev)
link_post = ''
incomplete_note = ''
if not self.revision_complete(rev):
incomplete_note = ' (incomplete run)'
lines.append('%s %s (%s)'
'%s%s%d failures, %d skips%s%s' % (
' |' * len(lines),
prefix, rev, rev,
self.revisiondate(rev),
' ' * (2 * (len(revisions) - len(lines))
+ 10 - len(rev) - len(str(count_failures))),
link_pre, count_failures, count_skips, link_post,
incomplete_note))
lines.append(' |' * len(lines))
for line in lines:
print >> f, line
print >> f
for (fn, revs), (mod, test) in zip(self.failures, self.testnames):
line = ''
for rev in revisions:
if rev in revs:
if fn.startswith('(') and fn.endswith(')'):
url = '%s' % rev
else:
url = '%s/failed/%s' % (rev, fn)
line += (' F'
% (prefix, url))
else:
if prefix:
break
outcome = self.getoutcome(fn, rev, mod)
line += ' ' + outcome
else:
line += ' %s %s' % (mod.ljust(self.modmax), test)
print >> f, line
print >> f
for line in lines[::-1]:
print >> f, line
print >> f, ''
footer = ''
if not prefix:
footer = '%d tests listed.' % (len(self.failures),)
elif len(revisions) == 1:
this_rev = revisions[0]
skips = self.skips.get(this_rev)
if skips:
footer = '%d test%s skipped. ' % (len(skips), "s"[:len(skips)-1])
footer += '[%d outcomes] ' % self.counts[this_rev]
footer += 'See run record'
footer += ' or per-test outcome.'
if footer:
print >> f, '%s
' % (footer,) print >> f, '' f.close() def main(targetdir, user_config=None): assert os.path.isdir(targetdir) if user_config is None: user_config = load_config() config = DEFAULTS.copy() config.update(user_config) summary = Summary(targetdir, config) revisions = summary.gather_revisions() del revisions[:-config['KEEP']] summary.gather_outcomes(revisions) summary.dump(revisions, '', os.path.join(targetdir, 'summary.html')) for rev in revisions: summary.dump([rev], '../', os.path.join(targetdir, str(rev), 'summary.html')) if __name__ == '__main__': if len(sys.argv) > 1: targetdir = sys.argv[1] else: targetdir = 'html' main(targetdir)