Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
poky.py 3.89 KiB

import os
import time
import tempfile
import shutil
import tarfile
import glob
from binaryaudit import util
from binaryaudit import abicheck
from binaryaudit.db import VERSION_NOT_AVAILABLE


def retrieve_baseline(db_conn, prod_id):
    ''' Fetch buildhistory baseline data from the db and extract for the further usage.

        Parameters:

        Returns:
            baseline_id (int): Baseline ID from DB.
            baseline_dir (str): Path to the extracted buildhistory baseline directory.
    '''
    baseline_id, baseline_data = db_conn.get_ba_latest_baseline(prod_id)
    if not baseline_id:
        util.error("Couldn't find a matching product ID.")
        return None, None
    util.debug("baseline_id: '{}'\n".format(baseline_id))

    data_fl = tempfile.NamedTemporaryFile(delete=False)
    data_fl.write(baseline_data)
    data_fl.flush()
    data_fl.close()

    # TODO Perhaps use a better random path.
    extractdir = "/tmp/binaryaudit_base"
    if os.path.isdir(extractdir):
        shutil.rmtree(extractdir)
    os.makedirs(extractdir)

    with tarfile.open(data_fl.name, "r:gz") as tgz:
        tgz.extractall(extractdir)
        tgz.close()
    os.unlink(data_fl.name)
    # Depends on how we pack, but the first sibling named "buildhistory" should be it.
    buildhistory_baseline_dir = None
    for root, dirs, files in os.walk(extractdir):
        if "buildhistory" in dirs:
            buildhistory_baseline_dir = os.path.join(root, "buildhistory")
            break
    if not buildhistory_baseline_dir and not os.path.isdir(buildhistory_baseline_dir):
        util.error("Couldn't setup buildhistory baseline.")

    return baseline_id, buildhistory_baseline_dir


def _get_dump_duration(recipe_binaudit_path):
    ret = .0
    fl = recipe_binaudit_path + "/abixml.duration"
    try:
        with open(fl, "r") as f:
            ret = float(f.read())
            f.close()
    except Exception:
        pass
    return ret


def _get_version_from_buildhistory(d):
    latest_fl = os.path.join(d, "latest")
    version = VERSION_NOT_AVAILABLE
    try:
        with open(latest_fl, "r") as f:
            for ln in f.readlines():
                a = ln.split("=")
                if "PV" == a[0].rstrip().lstrip():
                    version = a[1].rstrip().lstrip()
    except Exception:
        pass
    return version


def recipe_abicheck(recipe_binaudit_path, buildhistory_baseline_dir, bulidhistory_current_dir, suppressions):
    t0 = time.monotonic()
    ret_acc = abicheck.DIFF_OK
    dump_duration = _get_dump_duration(recipe_binaudit_path)

    for cur_xml_fl in glob.glob(recipe_binaudit_path + "/abixml/*.xml", recursive=False):
        with open(cur_xml_fl) as f:
            xml = f.read()
            f.close()

        # Care only about DSO for now
        sn = abicheck.get_soname_from_xml(xml)
        # XXX Handle error cases, eg xml file was garbage, etc.
        if len(sn) > 0:
            ref_xml_fl = cur_xml_fl.replace(bulidhistory_current_dir, buildhistory_baseline_dir)
            if not os.path.isfile(ref_xml_fl):
                continue
            ret, out, cmd = abicheck.compare(ref_xml_fl, cur_xml_fl, suppressions)
            if ret > ret_acc:
                # just get the highest score
                ret_acc = ret

    t1 = time.monotonic()

    new_base = os.path.dirname(recipe_binaudit_path)
    old_base = new_base.replace(bulidhistory_current_dir, buildhistory_baseline_dir)

    item_name = os.path.basename(new_base)

    new_version = _get_version_from_buildhistory(new_base)
    base_version = _get_version_from_buildhistory(old_base)

    # Take into account the time spent for serialization during the build, too.
    exec_time = int(dump_duration + (t1-t0)*1000000)  # usec

    result = abicheck.diff_get_bit(ret_acc)
    if 0 == ret_acc:
        res_details = ""
    else:
        res_details = out

    return item_name, base_version, new_version, exec_time, result, res_details, ret_acc