diff --git a/helpers/check-abi.py b/helpers/check-abi.py --- a/helpers/check-abi.py +++ b/helpers/check-abi.py @@ -29,6 +29,13 @@ 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,21 +53,53 @@ 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']: return None 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 @@ 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 @@ 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 @@ retval = 0 # the dictonary that will be written to abi-compatibility-results.yaml -resultsYamlFile = {} +resultsYamlFile = ABICompatibilityResults() for l in libraries: library = l.library @@ -216,51 +262,45 @@ 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, ] logging.debug(" ".join(cmd)) 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']: