diff --git a/helpers/check-abi.py b/helpers/check-abi.py --- a/helpers/check-abi.py +++ b/helpers/check-abi.py @@ -12,11 +12,14 @@ import argparse import collections +import decimal import logging import os +import re import subprocess import sys import time +import yaml from helperslib import Packages from helperslib.Version import Version @@ -59,6 +62,25 @@ return candidate +def parseACCOutputToDict(stdout): + """Parse output of abi-compliance-checker for further processing and returning a dict. + extract binary/source compatibility from acc + and calculate a simple bool for the compatibibility. + """ + checkBlock = re.compile(br"""^Binary compatibility: (?P[0-9.]+)%\s* +Source compatibility: (?P[0-9.]+)%\s*$""", re.M) + m = checkBlock.search(stdout).groupdict() + + m['binary'] = decimal.Decimal(m['binary'].decode()) + m['source'] = decimal.Decimal(m['source'].decode()) + compatibility = m['binary'] == 100 and m['source'] == 100 + + return { + 'binaryCompatibility': float(m['binary']), + 'sourceCompatibility': float(m['source']), + 'compatibility': compatibility, + } + # Make sure logging is ready to go logging.basicConfig(level=logging.DEBUG) @@ -181,17 +203,44 @@ logging.info("check %s(old) -> %s(new)", candidate['scmRevision'], library['scmRevision']) + reportPath = "compat_reports/{libname}_compat_report.html".format(libname=libname) + + yml = { + 'reportPath': reportPath, + 'libname': libname, + 'otherCommit': candidate['scmRevision'], + } + + if candidate['scmRevision'] in HASH2TAG: + yml['tag'] = HASH2TAG[candidate['scmRevision']].version + # check ABI and write compat reports - cmd = ["abi-compliance-checker", - "-report-path", "compat_reports/{libname}_compat_report.html".format(libname=libname), + cmd = [ + "abi-compliance-checker", + "-report-path", reportPath, "-l", libname, "--old", oldLibraryPath, - "--new", newLibraryPath] - ret = subprocess.call(cmd) - - if ret != 0: - logging.error("abi-compliance-checker exited with %s", ret) - retval = ret + "--new", newLibraryPath, + ] + logging.debug(" ".join(cmd)) + try: + prog = subprocess.run(cmd, check=True, capture_output=True) + except subprocess.CalledProcessError as e: + if e.returncode == 1: # that means that we are not compatible, but still valid output. + logging.warning("abi-compliance-checker exited with 1:\n%s", prog.stdout.decode()) + + yml.update(parseACCOutputToDict(e.stdout)) + else: + logging.error("abi-compliance-checker exited with %s:\nstdout:\n\ลง%s\nstderr:\n\t%s", e.returncode, e.stdout.decode(), e.stderr.decode()) + retval = e.returncode + yml['error'] = e.returncode + else: + logging.debug(prog.stdout.decode()) + yml.update(parseACCOutputToDict(prog.stdout)) + + print("---YAML START---\n") + print(yaml.dump(yml, default_flow_style=False)) + print("---YAML END---") # We had an issue with one of the ABIs if retval != 0: