#!/usr/bin/env python3 # # piglit results.json visualizer over history and hosts # # Originally by Tomi Sarvela for Intel OTC lab # import os import argparse from mako.lookup import TemplateLookup from mako import exceptions from visutils import * from common import * def parse_args(): ap = argparse.ArgumentParser(description="Visualize set of piglit json results") ap.add_argument('-n','--new', help="Newest build marked", type=str, default='') ap.add_argument('-o','--output', help="Output HTML file", type=str, default='') ap.add_argument('-j','--json', help="Output JSON file for vis.js", type=str, default='') ap.add_argument('-p','--path', help="HTML links' path", type=str, default='') ap.add_argument('-b','--bugs', help="CIBuglog known bugs json file", type=str, default='') ap.add_argument('--testsort', default=False, action='store_true', help="Sort tests in alphabetical order") ap.add_argument('--groupbybuild', default=False, action='store_true', help="Group results by build, not by host") ap.add_argument('-d', '--depth', type=int, default=0, help="Relative dir depth of html files, added to links") ap.add_argument('-c','--collate', type=str, default=None, help="Collate these results, example: -c notrun,pass") ap.add_argument('--combine', type=str, default=None, help="Deprecated| Combine results for similar hosts") ap.add_argument('--buildorder', type=str, default=None, help="Filename for build order information") ap.add_argument('--builddesc', type=str, default=None, help="Filename for build descriptions") ap.add_argument('-C','--change', default=False, action='store_true', help="Create html page with only changed results within test/host") ap.add_argument('files', metavar='files', nargs='+', type=str, help="Piglit json files to be visualized") ap.add_argument('-a','--hostalias-file', type=str, default=None, help="Combine results for similiar hosts based on RegEx file") return ap.parse_args() # Truncate and remove single test result as much as we can for size def truncate_test(jsons, build, host, test): orig = jsons[(build,host)]["tests"][test] new = { 'result': orig['result'] } if ttip(orig)[1]: new['tooltip'] = htmlttip(ttip(orig)[1]) if 'hostname' in orig: new['hostname']=orig['hostname'] return new def main(): args = parse_args() if args.path: path = args.path else: path = "../"*args.depth if args.groupbybuild: sortkey=groupbuilds templatename = 'view-bybuild.mako' else: sortkey=grouphosts templatename = 'view-byhost.mako' if args.buildorder: readbuildorder(args.buildorder) if args.hostalias_file: try: read_hostalias_file(args.hostalias_file) except Exception as e: print("Err:",e) exit(1) else: try: read_hostalias_file(os.path.join(os.path.dirname(os.path.realpath(__file__)), "hostaliases.rx")) except: pass # Build a dict for extra information in html # builddesc file format: # builddescription desc = {} if args.builddesc: try: with open(args.builddesc, "r") as f: for line in f: try: a=line.strip().split(" ",maxsplit=1) desc[a[0]]=a[1] except (KeyError,ValueError,IndexError): pass except: print("Failed to read file", args.builddesc) try: jsons = readfiles(args.files, combine=args.combine) # arranged by [(build,host)] except (KeyboardInterrupt) as e: print("ERROR: Keyboard interrupt while reading files") exit(1) collate=args.collate.split(',') if args.collate else None tests = parsetests(jsons, sort=args.testsort, collate=collate, change=args.change) # keep the order same on these two arrays hostcols = [host for _,host in sorted(jsons, key=sortkey)] buildcols = [build for build,_ in sorted(jsons, key=sortkey)] rootdir = os.path.dirname(os.path.abspath(__file__)) mako = TemplateLookup([os.path.join(rootdir, "templates"), rootdir]) try: template = mako.get_template(templatename) except: print(exceptions.text_error_template().render()) exit(1) if args.output: with open(args.output, 'w') as f: try: page = template.render(path=path, builds=buildcols, tests=tests, hosts=hostcols, jsons=jsons, new=args.new, desc=desc) f.write(page) except: print(exceptions.text_error_template().render()) exit(1) if args.json: # Load the bugs but only if we're going to use them bugs = {} if args.bugs: try: with open(args.bugs, 'r') as f: bugs = json.load(f) except: pass data = { "name": args.new, "data": {} } if bugs: data['hasknownbugs'] = 1 # remove duplicates, keep order with python 3.6+ # seems that we assume being called without groupbybuild hosts=list(dict.fromkeys(hostcols)) builds=sorted(dict.fromkeys(buildcols), key=parsebuildstr, reverse=True) if args.new: builds.remove(args.new) builds.insert(0, args.new) data['index'] = { 'hosts': hosts, 'builds': builds, 'tests': tests } if desc: data['desc']={} for b in builds: if b in desc: data['desc'][b]=desc[b] for h in hosts: if b in desc: data['desc'][b]=desc[b] if not data['desc']: del data['desc'] for host in hosts: for build in builds: for test in tests: key=','.join([build,host,test]) try: data['data'][key]=truncate_test(jsons, build, host, test) except (TypeError,KeyError): continue try: hostname = data['data'][key]['hostname'] except KeyError: hostname = host try: data['data'][key]['bugs'] = bugs[build][hostname][test] except KeyError: # no bug pass # Add hints for creating header URL refs data['refs'] = {} for host in hosts: data['refs'][host] = "%s.html" % host for build in builds: data['refs'][build] = "%s/filelist.html" % build for test in tests: data['refs'][test] = "%s.html" % test with open(args.json, 'w') as f: f.write(json.dumps(data)) return if __name__ == "__main__": main()