#!/usr/bin/env python3
# -------------------------------------------------------------------------
#
#  Part of the CodeChecker project, under the Apache License v2.0 with
#  LLVM Exceptions. See LICENSE for license information.
#  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# -------------------------------------------------------------------------
"""
Used to kickstart CodeChecker.
Save original environment without modifications.
Used to run the logging in the same env.
"""

import os
import pickle
import shutil
import signal
import subprocess
import sys
import tempfile

proc_pid = None


def run_codechecker(checker_env, subcommand=None):
    """
    Run the CodeChecker.
        * checker_env - CodeChecker will be run in the checker env.
        * subcommand - CodeChecker will run the given subcommand by default,
                       if specified. If not, the main script will run and parse
                       all the commands.
    """
    package_bin = os.path.dirname(os.path.realpath(__file__))
    package_root = os.path.dirname(package_bin)
    lib_dir_path = os.path.join(package_root, 'lib', 'python3')

    checker_env['PYTHONPATH'] = lib_dir_path
    checker_env['CC_BIN_DIR'] = package_bin

    python3 = os.path.join('python3')
    codechecker_main = \
        os.path.join(lib_dir_path, 'codechecker_common', 'cli.py')

    checker_cmd = [python3, codechecker_main]

    if subcommand:
        # If a subcommand is specified (script is executed from a
        # wrapper entry point, add it to the command list).
        # E.g. 'codechecker-log ...' is the same as 'CodeChecker log ...'.
        checker_cmd.append(subcommand)

    checker_cmd.extend(sys.argv[1:])

    proc = subprocess.Popen(checker_cmd,
                            encoding="utf=8",
                            errors="ignore",
                            env=checker_env)
    global proc_pid
    proc_pid = proc.pid

    proc.wait()
    sys.exit(proc.returncode)


def main(subcommand=None):
    original_env = os.environ.copy()
    checker_env = original_env

    tmp_dir = tempfile.mkdtemp()

    original_env_file = os.path.join(tmp_dir, 'original_env.pickle')

    def _remove_tmp():
        # Remove temporary directory.
        try:
            shutil.rmtree(tmp_dir)
        except Exception as ex:
            if not isinstance(ex, OSError):
                print('Failed to remove temporary directory: ' + tmp_dir)
                print('Manual cleanup is required.')
                print(ex)

    try:
        with open(original_env_file, 'wb') as env_save:
            pickle.dump(original_env, env_save)

        checker_env['CODECHECKER_ORIGINAL_BUILD_ENV'] = original_env_file
    except Exception as ex:
        print('Saving original build environment failed.')
        print(ex)

    def signal_term_handler(signum, frame):
        global proc_pid
        if proc_pid and not sys.platform == "win32":
            os.kill(proc_pid, signal.SIGINT)

        _remove_tmp()
        sys.exit(128 + signum)

    signal.signal(signal.SIGTERM, signal_term_handler)
    signal.signal(signal.SIGINT, signal_term_handler)

    def signal_reload_handler(sig, frame):
        global proc_pid
        if proc_pid:
            os.kill(proc_pid, signal.SIGHUP)

    if not sys.platform == "win32":
        signal.signal(signal.SIGHUP, signal_reload_handler)

    try:
        run_codechecker(checker_env, subcommand)
    finally:
        _remove_tmp()


if __name__ == "__main__":
    main(None)
