#!/usr/bin/env python3
# Copyright 2019 Collabora Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# (See debian/copyright)

import fnmatch
import logging
import os
import subprocess
import sys

try:
    from typing import (
        List,
        Set,
    )
    # placate pyflakes
    List, Set
except ImportError:
    pass

from steamrt_abi import AbiData


logger = logging.getLogger('check-ld-library-path-runtime')


def main() -> None:
    abi = AbiData()
    failed = False

    runtime = sys.argv[1]
    multiarchs = sys.argv[2:] or abi.architectures.keys()
    expected_sonames = set()    # type: Set[str]

    for obj in abi.architectures.values():
        multiarch = obj.multiarch_tuple
        arch = obj.dpkg_name

        if multiarch not in multiarchs:
            continue

        for lib in abi.shared_libraries.values():
            expected_sonames.add(lib.soname)

            for libdir in (
                os.path.join(runtime, arch, 'lib', multiarch),
                os.path.join(runtime, arch, 'usr', 'lib', multiarch),
            ):
                if os.path.exists(os.path.join(libdir, lib.soname)):
                    break
            else:
                if not lib.from_host_system:
                    logger.error('%s/%s not found', multiarch, lib.soname)
                    failed = True

            for alias in lib.aliases:
                for libdir in (
                    os.path.join(runtime, arch, 'lib', multiarch),
                    os.path.join(runtime, arch, 'usr', 'lib', multiarch),
                ):
                    if os.path.exists(os.path.join(libdir, alias)):
                        break
                else:
                    logger.error(
                        '%s/%s not found (should be symlink to %s)',
                        multiarch, alias, lib.soname,
                    )
                    failed = True

    libdirs = []    # type: List[str]

    for obj in abi.architectures.values():
        multiarch = obj.multiarch_tuple
        arch = obj.dpkg_name

        if multiarch in multiarchs:
            for prefix in (
                os.path.join(runtime, arch, 'lib'),
                os.path.join(runtime, arch, 'usr', 'lib'),
            ):
                libdirs.append(os.path.join(prefix, multiarch))

    sonames = set()     # type: Set[str]

    with subprocess.Popen([
        '/sbin/ldconfig', '-X', '-n', '-v',
    ] + libdirs, stdout=subprocess.PIPE, universal_newlines=True) as ldconfig:
        stdout = ldconfig.stdout
        assert stdout is not None
        for line in stdout:
            line = line.strip()

            if ' -> ' in line:
                soname, real_name = line.split(' -> ', 1)
                sonames.add(soname)

    for soname in sorted(sonames):
        if soname in expected_sonames:
            continue

        logger.info('%s', soname)

        for private_library_data in abi.data['private_libraries']:
            assert isinstance(private_library_data, dict)
            assert len(private_library_data) == 1
            pattern = next(iter(private_library_data))
            if fnmatch.fnmatchcase(soname, pattern):
                logger.info('%s matches %s', soname, pattern)
                break
        else:
            logger.error('Unexpected SONAME %s found', soname)
            failed = True

    if failed:
        sys.exit(1)


if __name__ == '__main__':
    logging.basicConfig()
    main()
