1#!/usr/bin/env python3 2 3from __future__ import print_function 4import os 5import sys 6from argparse import ArgumentParser 7from xen_analysis.diff_tool.cppcheck_report import CppcheckReport 8from xen_analysis.diff_tool.debug import Debug 9from xen_analysis.diff_tool.report import ReportError 10from xen_analysis.diff_tool.unified_format_parser import \ 11 (UnifiedFormatParser, UnifiedFormatParseError) 12from xen_analysis.settings import repo_dir 13from xen_analysis.utils import invoke_command 14 15 16class DiffReportError(Exception): 17 pass 18 19 20def log_info(text, end='\n'): 21 # type: (str, str) -> None 22 global args 23 global file_out 24 25 if (args.verbose): 26 print(text, end=end, file=file_out) 27 28 29def main(argv): 30 # type: (list) -> None 31 global args 32 global file_out 33 34 parser = ArgumentParser(prog="diff-report.py") 35 parser.add_argument("-b", "--baseline", required=True, type=str, 36 help="Path to the baseline report.") 37 parser.add_argument("--debug", action='store_true', 38 help="Produce intermediate reports during operations.") 39 parser.add_argument("-o", "--out", default="stdout", type=str, 40 help="Where to print the tool output. Default is " 41 "stdout") 42 parser.add_argument("-r", "--report", required=True, type=str, 43 help="Path to the 'check report', the one checked " 44 "against the baseline.") 45 parser.add_argument("-v", "--verbose", action='store_true', 46 help="Print more informations during the run.") 47 parser.add_argument("--patch", type=str, 48 help="The patch file containing the changes to the " 49 "code, from the baseline analysis result to the " 50 "'check report' analysis result.\n" 51 "Do not use with --baseline-rev/--report-rev") 52 parser.add_argument("--baseline-rev", type=str, 53 help="Revision or SHA of the codebase analysed to " 54 "create the baseline report.\n" 55 "Use together with --report-rev") 56 parser.add_argument("--report-rev", type=str, 57 help="Revision or SHA of the codebase analysed to " 58 "create the 'check report'.\n" 59 "Use together with --baseline-rev") 60 61 args = parser.parse_args() 62 63 if args.patch and (args.baseline_rev or args.report_rev): 64 print("ERROR: '--patch' argument can't be used with '--baseline-rev'" 65 " or '--report-rev'.") 66 sys.exit(1) 67 68 if bool(args.baseline_rev) != bool(args.report_rev): 69 print("ERROR: '--baseline-rev' must be used together with " 70 "'--report-rev'.") 71 sys.exit(1) 72 73 if args.out == "stdout": 74 file_out = sys.stdout 75 else: 76 try: 77 file_out = open(args.out, "wt") 78 except OSError as e: 79 print("ERROR: Issue opening file {}: {}".format(args.out, e)) 80 sys.exit(1) 81 82 debug = Debug(args) 83 84 try: 85 baseline_path = os.path.realpath(args.baseline) 86 log_info("Loading baseline report {}".format(baseline_path), "") 87 baseline = CppcheckReport(baseline_path) 88 baseline.parse() 89 debug.debug_print_parsed_report(baseline) 90 log_info(" [OK]") 91 new_rep_path = os.path.realpath(args.report) 92 log_info("Loading check report {}".format(new_rep_path), "") 93 new_rep = CppcheckReport(new_rep_path) 94 new_rep.parse() 95 debug.debug_print_parsed_report(new_rep) 96 log_info(" [OK]") 97 diff_source = None 98 if args.patch: 99 diff_source = os.path.realpath(args.patch) 100 elif args.baseline_rev: 101 git_diff = invoke_command( 102 "git --git-dir={}/.git diff -C -C {}..{}" 103 .format(repo_dir, args.baseline_rev, args.report_rev), 104 True, DiffReportError, "Error occured invoking:\n{}\n\n{}" 105 ) 106 diff_source = git_diff.splitlines(keepends=True) 107 if diff_source: 108 log_info("Parsing changes...", "") 109 diffs = UnifiedFormatParser(diff_source) 110 debug.debug_print_parsed_diff(diffs) 111 log_info(" [OK]") 112 except (DiffReportError, ReportError, UnifiedFormatParseError) as e: 113 print("ERROR: {}".format(e)) 114 sys.exit(1) 115 116 if args.patch or args.baseline_rev: 117 log_info("Patching baseline...", "") 118 baseline_patched = baseline.patch(diffs) 119 debug.debug_print_patched_report(baseline_patched) 120 log_info(" [OK]") 121 output = new_rep - baseline_patched 122 else: 123 output = new_rep - baseline 124 125 print(output, end="", file=file_out) 126 127 if len(output) > 0: 128 sys.exit(1) 129 130 sys.exit(0) 131 132 133if __name__ == "__main__": 134 main(sys.argv[1:]) 135