From 8a129c6c402e0569664d8b745f41f41115d031f7 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Fri, 28 Feb 2020 14:33:21 +0100 Subject: ci: Add ABI check --- .ci/check-abi | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .gitlab-ci.yml | 5 +++ 2 files changed, 126 insertions(+) create mode 100755 .ci/check-abi diff --git a/.ci/check-abi b/.ci/check-abi new file mode 100755 index 0000000..8d3e0e9 --- /dev/null +++ b/.ci/check-abi @@ -0,0 +1,121 @@ +#!/usr/bin/python3 + + +import argparse +import contextlib +import os +import shutil +import subprocess +import sys + + +def format_title(title): + box = { + 'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║', + } + hline = box['h'] * (len(title) + 2) + + return '\n'.join([ + f"{box['tl']}{hline}{box['tr']}", + f"{box['v']} {title} {box['v']}", + f"{box['bl']}{hline}{box['br']}", + ]) + + +def rm_rf(path): + try: + shutil.rmtree(path) + except FileNotFoundError: + pass + + +def sanitize_path(name): + return name.replace('/', '-') + + +def get_current_revision(): + revision = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], + encoding='utf-8').strip() + + if revision == 'HEAD': + # This is a detached HEAD, get the commit hash + revision = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8') + + return revision + + +@contextlib.contextmanager +def checkout_git_revision(revision): + current_revision = get_current_revision() + subprocess.check_call(['git', 'checkout', '-q', revision]) + + try: + yield + finally: + subprocess.check_call(['git', 'checkout', '-q', current_revision]) + + +def build_install(revision): + build_dir = '_build' + dest_dir = os.path.abspath(sanitize_path(revision)) + print(format_title(f'# Building and installing {revision} in {dest_dir}'), + end='\n\n', flush=True) + + with checkout_git_revision(revision): + rm_rf(build_dir) + rm_rf(revision) + + subprocess.check_call(['meson', build_dir, + '--prefix=/usr', '--libdir=lib', + '-Db_coverage=false', '-Dgtkdoc=false', '-Dtests=false']) + subprocess.check_call(['ninja', '-v', '-C', build_dir]) + subprocess.check_call(['ninja', '-v', '-C', build_dir, 'install'], + env={'DESTDIR': dest_dir}) + + return dest_dir + + +def compare(old_tree, new_tree): + print(format_title(f'# Comparing the two ABIs'), end='\n\n', flush=True) + + old_headers = os.path.join(old_tree, 'usr', 'include') + old_lib = os.path.join(old_tree, 'usr', 'lib', 'libtotem-plparser.so') + + new_headers = os.path.join(new_tree, 'usr', 'include') + new_lib = os.path.join(new_tree, 'usr', 'lib', 'libtotem-plparser.so') + + subprocess.check_call([ + 'abidiff', '--headers-dir1', old_headers, '--headers-dir2', new_headers, + '--drop-private-types', '--fail-no-debug-info', '--no-added-syms', old_lib, new_lib]) + + old_lib = os.path.join(old_tree, 'usr', 'lib', 'libtotem-plparser-mini.so') + new_lib = os.path.join(new_tree, 'usr', 'lib', 'libtotem-plparser-mini.so') + + subprocess.check_call([ + 'abidiff', '--headers-dir1', old_headers, '--headers-dir2', new_headers, + '--drop-private-types', '--fail-no-debug-info', '--no-added-syms', old_lib, new_lib]) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument('old', help='the previous revision, considered the reference') + parser.add_argument('new', help='the new revision, to compare to the reference') + + args = parser.parse_args() + + if args.old == args.new: + print("Let's not waste time comparing something to itself") + sys.exit(0) + + old_tree = build_install(args.old) + new_tree = build_install(args.new) + + try: + compare(old_tree, new_tree) + + except Exception as e: + print ('ABI comparison failed: '+ str(e)) + sys.exit(1) + + print(f'Hurray! {args.old} and {args.new} are ABI-compatible!') diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cbab405..73146aa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,9 @@ variables: DEPENDENCIES: redhat-rpm-config meson git gettext gtk-doc meson glib2-devel libxml2-devel gobject-introspection-devel libgcrypt-devel libarchive-devel DEPS_QUVI: libquvi-devel + DEPS_ABI_CHECK: libabigail libsoup-devel gmime-devel TEST_DEPS: gvfs dbus-daemon + LAST_ABI_BREAK: "9ccc3c78a5a41b86bdd2c9fb63ad4963e65e4f63" build-fedora: image: fedora:latest @@ -19,3 +21,6 @@ build-fedora: - meson _build - GIO_USE_VOLUME_MONITOR=unix dbus-run-session ninja -C _build test - ninja -C _build install + # ABI check + - dnf install -y $DEPS_ABI_CHECK + - ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD) -- cgit v1.2.1