Skip to content
Snippets Groups Projects
packaging-doc.py 4.65 KiB
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-3.0-or-later

import logging
import os.path
from pathlib import Path
import subprocess
import sys
import tempfile
import argparse


DISTROS_PATH = Path(os.path.realpath('scripts/distros'))
GEN_SCRIPT = Path(os.path.realpath('scripts/dockerfile_gen.py'))


def unpack(archive, targetdir):
    '''
    Prepare workdir for Docker build by unpacking fresh distribution tarball
    '''
    logging.debug('unpacking fresh tarball %s into %s', archive, targetdir)
    subprocess.check_call(['tar', '-C', targetdir, '-xf', archive])


def fresh_tarball():
    try:
        # make archive so we have clean state to test
        archive = subprocess.check_output('scripts/make-archive.sh')
    except subprocess.CalledProcessError as ex:
        logging.fatal('failed to generate fresh tarball: %s', ex.output)
        sys.exit(ex.returncode)
    return os.path.realpath(archive.strip())


def get_distro_vers(distro_root):
    '''
    return list of (distro, version) pairs found in distro_root
    '''
    # transform list of paths like TOP/debian/9 into (debian, 9)
    dist_ver = [p.parts[-2:] for p
                in Path(distro_root).glob('*/*') if p.is_dir()]
    return list(dist_ver)


def get_components(root):
    cmpl = [os.path.relpath(dirn, start=root)  # relative names only
            for dirn, _, _ in os.walk(root)
            if (os.path.basename(dirn) == 'packaging'  # path ends with
                and 'contrib' not in Path(dirn).parts)]  # ignore contrib libs
    return list(cmpl)


def test_combinations(distro_vers, components):
    tests = []
    for distro, ver in distro_vers:
        for comp in components:
            comps = ['scripts/distros', 'daemon/packaging']   # always include daemon
            if comp not in comps:
                comps.append(comp)
            tests.append([distro, ver, *comps])
    tests.sort()
    return tests


def gen_dockerfile(args, tmpdir, srcdir):
    subprocess.check_call([GEN_SCRIPT,
                          '--srcdir={}'.format(srcdir)]  # dir in tar
                          + args,
                          stdout=open(tmpdir / 'Dockerfile', 'w'))


def docker_build(tmpdir, delete):
    subprocess.check_call(
        ['docker',
         'build',
         '--rm={}'.format(str(delete).lower()),
         '--network',
         'host',
         tmpdir]
    )


def find_test(required_tests, test_combination):
    '''
    Find test in test_combination in required_tests list
    '''
    for test in required_tests:
        if test_combination[len(test_combination)-1] == test[0]:
            return True

    return False


def main():
    logging.basicConfig(level=logging.DEBUG)

    argparser = argparse.ArgumentParser(
        formatter_class=argparse.RawTextHelpFormatter,
        description='''Find all tests in current directory, generate Dockerfiles and run all Dockerfiles one by one.
'''.format(n=sys.argv[0])
        )
    argparser.add_argument(
        '-t', '--test', action='append', nargs=1, help='Select one test to run')
    argparser.add_argument(
        '-l', '--list', action='store_true', help='Show all available tests')

    params = argparser.parse_args()

    distro_vers = get_distro_vers(DISTROS_PATH)
    components = get_components('.')
    logging.info('generating fresh tarball')
    archive = fresh_tarball()
    logging.debug('generated tarball %s', archive)
    # transform knot-resolver-1.5.0-70-gf1dbebdc.tar.xz -> knot-resolver-1.5.0-70-gf1dbebdc
    srcdir = os.path.basename(archive).decode('ascii').rsplit('.', maxsplit=2)[0]
    logging.debug('expected dir name in tarball: %s', srcdir)

    with tempfile.TemporaryDirectory() as tmpdir:
        tmpdir = Path(tmpdir)
        unpack(archive, tmpdir)
        baseimg = True  # do not delete first image - it works as cache
        if params.list:
            print('Available tests: ')
        # all tests
        for args in test_combinations(distro_vers, components):
            if params.list:
                print('\t' + args[len(args)-1])
                continue
            if params.test:
                if not find_test(params.test, args):
                    logging.debug('skip test for %s', args)
                    continue

            logging.debug('generating Dockerfile for %s', args)
            gen_dockerfile(args, tmpdir, srcdir)
            from shutil import copyfile
            copyfile(os.path.join(tmpdir, "Dockerfile"),
                    "/tmp/Dockerfile_" + args[0] + args[1] + "_" + args[-1].replace('/', '-'))
            continue
            logging.info('testing combination %s', args)
            docker_build(tmpdir, delete=not baseimg)
            baseimg = False


if __name__ == '__main__':
    main()