| """Filters LCOV tracefiles |
| |
| - Arguments are filepath prefixes to keep (or drop if prefixed with '-') |
| - A path is kept if it matches at least one include and no excludes |
| - If no includes are specified then everything not excluded is included |
| - Input tracefile comes from stdin |
| - Output tracefiles goes to stdout |
| """ |
| import sys |
| |
| def read_lcov(): |
| file_line_cov = {} # map[test][file][line] = covered |
| current_sf = None |
| current_tn = None |
| for line in sys.stdin: |
| line = line.strip() |
| if line[:3] == "TN:": |
| current_tn = line[3:] |
| if current_tn not in file_line_cov: |
| file_line_cov[current_tn] = {} |
| elif line[:3] == "SF:": |
| current_sf = line[3:] |
| file_line_cov[current_tn][current_sf] = {} |
| elif line[:3] == "DA:": |
| [num, hit] = line[3:].split(",") |
| file_line_cov[current_tn][current_sf][int(num)] = hit != "0" # convert to bool |
| else: |
| pass |
| |
| return file_line_cov |
| |
| def is_excluded(path, excludes): |
| # if no excludes are specified then this is skipped and nothing is excluded |
| for e in excludes: |
| if path.startswith(e): |
| # matched an excluded prefix so finished with excludes |
| return True |
| return False |
| |
| def is_included(path, includes): |
| for i in includes: |
| if path.startswith(i): |
| # matched an included prefix so finished with includes |
| return True |
| return False |
| |
| def write_lcov(filtered_cov): |
| for tn in sorted(filtered_cov): |
| for filepath in sorted(filtered_cov[tn]): |
| sys.stdout.write('TN:{}\n'.format(tn)) |
| sys.stdout.write('SF:{}\n'.format(filepath)) |
| for line in sorted(filtered_cov[tn][filepath]): |
| sys.stdout.write('DA:{},{}\n'.format(line, int(filtered_cov[tn][filepath][line]))) |
| sys.stdout.write('end_of_record\n') |
| |
| |
| def main(): |
| prefixes = sys.argv[1:] |
| includes = [x for x in prefixes if not x.startswith("-")] |
| excludes = [x[1:] for x in prefixes if x.startswith("-")] |
| |
| file_line_cov = read_lcov() |
| |
| after_excludes = {} |
| for tn in file_line_cov: |
| after_excludes[tn] = {f: file_line_cov[tn][f] for f in file_line_cov[tn] if not is_excluded(f, excludes)} |
| |
| filtered = after_excludes # by default include everything |
| if len(includes) > 0: # but if there are explicit includes then only include those |
| filtered = {} |
| for tn in after_excludes: |
| filtered[tn] = {f: after_excludes[tn][f] for f in after_excludes[tn] if is_included(f, includes)} |
| |
| write_lcov(filtered) |
| |
| if __name__ == '__main__': |
| main() |