vis.py 6.67 KB
Newer Older
Tomi Sarvela's avatar
Tomi Sarvela committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#!/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 *

16
def parse_args():
Tomi Sarvela's avatar
Tomi Sarvela committed
17 18 19 20 21
    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='')
22
    ap.add_argument('-b','--bugs', help="CIBuglog known bugs json file", type=str, default='')
Tomi Sarvela's avatar
Tomi Sarvela committed
23 24 25 26 27 28 29 30 31 32

    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,
33
        help="Deprecated| Combine results for similar hosts")
Tomi Sarvela's avatar
Tomi Sarvela committed
34 35 36 37 38 39 40 41
    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")
42 43
    ap.add_argument('-a','--hostalias-file', type=str, default=None,
        help="Combine results for similiar hosts based on RegEx file")
44 45 46 47 48 49 50 51 52
    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])
53
    if 'hostname' in orig: new['hostname']=orig['hostname']
54 55 56 57
    return new

def main():
    args = parse_args()
Tomi Sarvela's avatar
Tomi Sarvela committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

    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)

74 75 76 77 78 79 80 81 82 83 84
    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

Tomi Sarvela's avatar
Tomi Sarvela committed
85 86 87
    # Build a dict for extra information in html
    # builddesc file format:
    # build<space>description
88
    desc = {}
Tomi Sarvela's avatar
Tomi Sarvela committed
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    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:
130 131 132 133 134 135 136 137 138
        # 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

Tomi Sarvela's avatar
Tomi Sarvela committed
139
        data = { "name": args.new, "data": {} }
140
        if bugs: data['hasknownbugs'] = 1
141

Tomi Sarvela's avatar
Tomi Sarvela committed
142 143 144 145
        # 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)
146 147 148
        if args.new:
            builds.remove(args.new)
            builds.insert(0, args.new)
Tomi Sarvela's avatar
Tomi Sarvela committed
149 150 151 152 153 154 155 156 157
        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']

158 159 160 161 162
        for host in hosts:
            for build in builds:
                for test in tests:
                    key=','.join([build,host,test])
                    try:
163 164
                        data['data'][key]=truncate_test(jsons, build, host, test)
                    except (TypeError,KeyError): continue
165 166
                    try: hostname = data['data'][key]['hostname']
                    except KeyError: hostname = host
167 168 169
                    try: data['data'][key]['bugs'] = bugs[build][hostname][test]
                    except KeyError: # no bug
                        pass
Tomi Sarvela's avatar
Tomi Sarvela committed
170

171 172 173 174 175 176
        # 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

Tomi Sarvela's avatar
Tomi Sarvela committed
177 178 179
        with open(args.json, 'w') as f:
            f.write(json.dumps(data))

180
    return
Tomi Sarvela's avatar
Tomi Sarvela committed
181

182 183
if __name__ == "__main__":
    main()
Tomi Sarvela's avatar
Tomi Sarvela committed
184