|
| 1 | +#!/usr/bin/env python |
| 2 | +""" |
| 3 | +""" |
| 4 | + |
| 5 | +# pylint: disable=invalid-name, broad-except |
| 6 | + |
| 7 | +import argparse |
| 8 | +import tempfile |
| 9 | +import subprocess |
| 10 | +import sys |
| 11 | +import os |
| 12 | +import webbrowser |
| 13 | + |
| 14 | +from os.path import exists, isfile |
| 15 | + |
| 16 | +_ERR_PREFIX = '\033[31merror: ' |
| 17 | + |
| 18 | +def exec_string(string): |
| 19 | + 'execute the string in a subprocess.' |
| 20 | + try: |
| 21 | + subprocess.check_call(string, shell=True) |
| 22 | + except KeyboardInterrupt: |
| 23 | + sys.exit('\033[31m\nKilled!\033[0m') |
| 24 | + except (subprocess.CalledProcessError, OSError): |
| 25 | + sys.exit(_ERR_PREFIX + 'executing:\n' + string + '\n failed!\033[0m') |
| 26 | + |
| 27 | +_PARSER = argparse.ArgumentParser(prog='code-coverage-test-c.py', |
| 28 | + usage='%(prog)s [options]') |
| 29 | +_PARSER.add_argument('files', nargs='+', type=str, |
| 30 | + help='the test files you want to check code coverage for' |
| 31 | + + '(must be at least one)') |
| 32 | +_PARSER.add_argument('--gap-root', nargs='?', type=str, |
| 33 | + help='the gap root directory (default: ~/gap)', |
| 34 | + default='~/gap/') |
| 35 | +_PARSER.add_argument('--pkg', nargs='?', type=str, |
| 36 | + help='the package to profile (default: None)', |
| 37 | + default=None) |
| 38 | +_PARSER.add_argument('--build', dest='build', action='store_true', |
| 39 | + help='rebuild GAP (default: False)') |
| 40 | +_PARSER.set_defaults(build=False) |
| 41 | +_PARSER.add_argument('--open', nargs='?', type=str, |
| 42 | + help=('open the lcov html page for this file ' + |
| 43 | + '(default: None)'), |
| 44 | + default=None) |
| 45 | +_PARSER.add_argument('--line', nargs='?', type=str, |
| 46 | + help=('open the html page for the file specified by --open' + |
| 47 | + ' at this line (default: None)'), |
| 48 | + default=None) |
| 49 | +_ARGS = _PARSER.parse_args() |
| 50 | + |
| 51 | +if not _ARGS.gap_root[-1] == '/': |
| 52 | + _ARGS.gap_root += '/' |
| 53 | + |
| 54 | +_ARGS.gap_root = os.path.expanduser(_ARGS.gap_root) |
| 55 | +if _ARGS.pkg != None: |
| 56 | + _ARGS.pkg = _ARGS.gap_root + '/pkg/' + _ARGS.pkg |
| 57 | + |
| 58 | +if not (os.path.exists(_ARGS.gap_root) and os.path.isdir(_ARGS.gap_root)): |
| 59 | + sys.exit('\033[31mcode-coverage-test-c.py: error: can\'t find gap root' + |
| 60 | + ' directory!\033[0m') |
| 61 | +if (_ARGS.pkg != None and not (os.path.exists(_ARGS.pkg) and |
| 62 | + os.path.isdir(_ARGS.pkg))): |
| 63 | + sys.exit('\033[31mcode-coverage-test-c.py: error: can\'t find the pkg' + |
| 64 | + ' directory %s\033[0m' % _ARGS.pkg) |
| 65 | +for f in _ARGS.files: |
| 66 | + if not (os.path.exists(f) and os.path.isfile(f)): |
| 67 | + sys.exit('\033[31mcode-coverage-test-c.py: error: ' + f + |
| 68 | + ' does not exist!\033[0m') |
| 69 | + |
| 70 | +_DIR = tempfile.mkdtemp() |
| 71 | +print('\033[35musing temporary directory: ' + _DIR + '\033[0m') |
| 72 | + |
| 73 | +_COMMANDS = 'echo "' |
| 74 | +for f in _ARGS.files: |
| 75 | + _COMMANDS += 'Test(\\"' + f + '\\");;' |
| 76 | +_COMMANDS += '"' |
| 77 | + |
| 78 | +# TODO build if files changed since last build or built with the wrong flags, |
| 79 | +# by looking in config.log |
| 80 | + |
| 81 | +# for source in : |
| 82 | +# if time.ctime(os.path.getmtime(file)) |
| 83 | + |
| 84 | +if _ARGS.build: |
| 85 | + cwd = os.getcwd() |
| 86 | + os.chdir(_ARGS.gap_root) |
| 87 | + exec_string('''rm -rf bin/ && \ |
| 88 | + make clean && \ |
| 89 | + ./configure CFLAGS="-O0 -g --coverage" \ |
| 90 | + CXXFLAGS="-O0 -g --coverage" \ |
| 91 | + LDFLAGS="-O0 -g --coverage" && \ |
| 92 | + make -j8''') |
| 93 | + if _ARGS.pkg != None: |
| 94 | + os.chdir(_ARGS.pkg) |
| 95 | + exec_string('rm -rf bin/ && \ |
| 96 | + make clean && \ |
| 97 | + ./configure CFLAGS="-O0 -g --coverage" \ |
| 98 | + CXXFLAGS="-O0 -g --coverage" \ |
| 99 | + LDFLAGS="-O0 -g --coverage" && \ |
| 100 | + make -j8''') |
| 101 | + os.chdir(cwd) |
| 102 | + |
| 103 | +pro1 = subprocess.Popen(_COMMANDS, stdout=subprocess.PIPE, shell=True) |
| 104 | +_RUN_GAP = _ARGS.gap_root + 'bin/gap.sh -A -m 1g -T' |
| 105 | + |
| 106 | +try: |
| 107 | + pro2 = subprocess.Popen(_RUN_GAP, |
| 108 | + stdin=pro1.stdout, |
| 109 | + shell=True) |
| 110 | + pro2.wait() |
| 111 | + print('') |
| 112 | +except KeyboardInterrupt: |
| 113 | + pro1.terminate() |
| 114 | + pro1.wait() |
| 115 | + pro2.terminate() |
| 116 | + pro2.wait() |
| 117 | + print('\033[31mKilled!\033[0m') |
| 118 | + sys.exit(1) |
| 119 | +except Exception: |
| 120 | + sys.exit('\033[31mcode-coverage-test-c.py: error: something went wrong ' |
| 121 | + + 'calling GAP!\033[0m''') |
| 122 | +if _ARGS.pkg != None: |
| 123 | + exec_string('lcov --capture --directory ' + _ARGS.pkg + |
| 124 | + '/src --output-file ' + _DIR + '/lcov.info') |
| 125 | +else: |
| 126 | + exec_string('lcov --capture --directory ' + _ARGS.gap_root + |
| 127 | + '/src --output-file ' + _DIR + '/lcov.info') |
| 128 | + |
| 129 | +exec_string('genhtml ' + _DIR + '/lcov.info --output-directory ' + _DIR + |
| 130 | + '/lcov-out') |
| 131 | + |
| 132 | +filename = _DIR + '/lcov-out/' |
| 133 | +if _ARGS.open: |
| 134 | + filename += _ARGS.open + '.gcov.html' |
| 135 | +else: |
| 136 | + filename += '/index.html' |
| 137 | + |
| 138 | +if exists(filename) and isfile(filename): |
| 139 | + if _ARGS.open and _ARGS.line: |
| 140 | + filename += '#' + _ARGS.line |
| 141 | + print('file://' + filename) |
| 142 | + try: |
| 143 | + webbrowser.get('chrome').open('file://' + filename, new=2) |
| 144 | + except Exception: |
| 145 | + webbrowser.open('file://' + filename, new=2) |
| 146 | +else: |
| 147 | + sys.exit('\n' + _ERR_PREFIX + 'Failed to open file://' + filename + |
| 148 | + '\033[0m') |
| 149 | + |
| 150 | +print('\n\033[32mSUCCESS!\033[0m') |
| 151 | +sys.exit(0) |
0 commit comments