Commit 3eb3369b authored by Sandro Knauß's avatar Sandro Knauß Committed by Ben Cooksley

check-abi: refactor script.

move abi-compatibilty.yaml into own class and move some parts into Library class.

Differential Revision: https://phabricator.kde.org/D19377
parent c90b101d
Pipeline #1177 skipped with stage
......@@ -29,6 +29,13 @@ class Library:
self.library = library
self.candidates = []
def __getitem__(self, key):
return self.library[key]
@property
def reportPath(self):
return "compat_reports/{cmakePackage}_compat_report.html".format(cmakePackage=self['cmakePackage'])
def addCandidate(self, key, entry):
entry['packageName'] = key
self.candidates.append(entry)
......@@ -46,13 +53,12 @@ class Library:
if released:
# get the first released version, that is available
candidate = min(released, key=lambda i: HASH2TAG[i['scmRevision']])
logging.info("Found tag %s(%s) to check against.", HASH2TAG[candidate['scmRevision']].version, candidate['scmRevision'])
candidate['tag'] = HASH2TAG[candidate['scmRevision']]
else:
#TODO: we may want to return None, as the library was never released so far.
# get oldest candidate.
candidate = min(self.candidates, key=lambda e:e['timestamp'])
logging.warning("No released version was found, just use the oldest commit.")
# the candidate needs to be older than the current build.
if timestamp < candidate['timestamp']:
......@@ -61,6 +67,39 @@ class Library:
return candidate
class ABICompatibilityResults:
"""Representing the content of abi-compatibility-results.yaml.
- First add the library via addLibrary
- Afterwards you can extent the directory via __get__
- At the end, create the fia via write
"""
def __init__(self):
self.dict = {}
def __getitem__(self, library):
return self.dict[library]
def addLibrary(self, library):
self.dict[library] = {}
def write(self):
d = {}
for library in self.dict:
cantidate = library.candidate()
entry = {
'reportPath': library.reportPath,
'ownCommit': library['scmRevision'],
'otherCommit': candidate['scmRevision'],
}
if 'tag' in candidate:
entry['tag'] = candidate['tag'].version
entry.update(self[library])
d[library['cmakePackage']] = entry
with open('abi-compatibility-results.yaml', 'w') as f:
f.write(yaml.dump(d, default_flow_style=False))
def parseACCOutputToDict(stdout):
"""Parse output of abi-compliance-checker for further processing and returning a dict.
extract binary/source compatibility from acc
......@@ -139,6 +178,7 @@ def updateAccMetadataVersion1(entry):
entry["cmakePackage"] = entry["libname"]
entry["targets"] = {i:entry["SONAME"] for i in entry["targets"]}
# Find all libraries of current git hash.
for key, entry in ourArchive.serverManifest.items():
updateAccMetadataVersion(entry)
try:
......@@ -158,33 +198,39 @@ if not libraries:
logging.info("No libraries found.")
sys.exit(0)
# Find all availabe reference dumps
# Find all available reference dumps
# * same cmakePackage
# * same SONAME otherwise we have a ABI bump and than it is safe to break ABI
# * same SONAME, otherwise we have a ABI bump and than it is safe to break ABI
for key, entry in ourArchive.serverManifest.items():
if entry['platform'] != arguments.platform:
continue
for l in libraries:
cmakePackage = l.library["cmakePackage"]
targets = l.library["targets"]
soname = max(targets.values())
for key, entry in ourArchive.serverManifest.items():
# Ignore builds on other branches
if keepBuildGroup and entry["branchGroup"] != arguments.branchGroup:
continue
if entry["project"] != arguments.project:
continue
if entry["scmRevision"] == scmRevision:
continue
for l in libraries:
cmakePackage = l.library["cmakePackage"]
targets = l.library["targets"]
soname = max(targets.values())
if key == l.packageName:
continue
if entry['platform'] != arguments.platform:
continue
break
# We want to search for the cmakePackage
if entry["cmakePackage"] != cmakePackage:
continue
# Ignore builds on other branches
if keepBuildGroup and entry["branchGroup"] != arguments.branchGroup:
continue
# TODO: as we may have bundled multiple libraries in one cmakePackage,
# we properly need a smater way.
if max(entry["targets"].values()) == soname:
l.addCandidate(key, entry)
continue
break
sameSONAME = False
for name, target in targets.items():
......@@ -205,7 +251,7 @@ for l in libraries:
retval = 0
# the dictonary that will be written to abi-compatibility-results.yaml
resultsYamlFile = {}
resultsYamlFile = ABICompatibilityResults()
for l in libraries:
library = l.library
......@@ -216,29 +262,24 @@ for l in libraries:
logging.info("Did not found any older build for %s, nothing to check ABI against.", cmakePackage)
continue
logging.info("check %s(old) -> %s(new)", candidate['scmRevision'], library['scmRevision'])
if 'tag' in candidate:
logging.info("Found tag %s(%s) to check against.", candidate['tag'].version, candidate['scmRevision'])
else:
logging.warning("No released version was found.")
# get the packages, we want to test against each other
newLibraryPath, _ = ourArchive.retrievePackage(l.packageName)
oldLibraryPath, _ = ourArchive.retrievePackage(candidate['packageName'])
logging.info("check %s(old) -> %s(new)", candidate['scmRevision'], library['scmRevision'])
reportPath = "compat_reports/{cmakePackage}_compat_report.html".format(cmakePackage=cmakePackage)
# Basic result yml information
yml = {
'reportPath': reportPath,
'ownCommit': scmRevision,
'otherCommit': candidate['scmRevision'],
}
resultsYamlFile[cmakePackage] = yml
if candidate['scmRevision'] in HASH2TAG:
yml['tag'] = HASH2TAG[candidate['scmRevision']].version
# Add library to results yaml file
resultsYamlFile.addLibrary(l)
# check ABI and write compat reports
cmd = [
"abi-compliance-checker",
"-report-path", reportPath,
"-report-path", l.reportPath,
"-l", cmakePackage,
"--old", oldLibraryPath,
"--new", newLibraryPath,
......@@ -247,20 +288,19 @@ for l in libraries:
try:
prog = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
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", e.stdout.decode())
if e.returncode == 1: # ABI not compatible, but still valid output.
logging.warning("%s\nabi-compliance-checker exited with 1 (not compatible)", e.stdout.decode())
yml.update(parseACCOutputToDict(e.stdout))
resultsYamlFile[l].update(parseACCOutputToDict(e.stdout))
else:
logging.error("abi-compliance-checker exited with %s:\nstdout:\n\t%s\nstderr:\n\t%s", e.returncode, e.stdout.decode(), e.stderr.decode())
retval = e.returncode
yml['error'] = e.returncode
resultsYamlFile[l]['error'] = e.returncode
else:
logging.debug(prog.stdout.decode())
yml.update(parseACCOutputToDict(prog.stdout))
resultsYamlFile[l].update(parseACCOutputToDict(prog.stdout))
with open('abi-compatibility-results.yaml', 'w') as f:
f.write(yaml.dump(resultsYamlFile, default_flow_style=False))
resultsYamlFile.write()
# We had an issue with one of the ABIs
if retval != 0 and accSettings['checkABIDumpFailHard']:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment