#! /usr/bin/python

# Copyright (C) 2018 Red Hat, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

"""
Cancel the background copr-rpmbuild process

Attempt (best effort) to cancel the background running process group.  The
current implementation mimics the situation when 'copr-rpmbuild' is run in
foreground (no --detached flag specified) and CTRL+C is pressed in the attached
terminal.

The Copr backend code doesn't expect us to fail.
"""

import logging
import os
import signal
import time

from copr_rpmbuild.helpers import read_config

INTERRUPT_TIMEOUT = 30
INTERRUPT_SLEEP = 3


def _get_stderr_logger():
    log = logging.getLogger(__name__)
    log.setLevel(logging.INFO)
    handler = logging.StreamHandler()
    handler.setFormatter(logging.Formatter("%(message)s"))
    log.addHandler(handler)
    return log

LOG = _get_stderr_logger()

def _is_running(pgid):
    try:
        os.killpg(pgid, 0)
    except OSError:
        # no processes in this group found, already shut-down
        return False
    return True

def _send_signal(pgid, signum):
    try:
        os.killpg(pgid, signum)
    except OSError as err:
        LOG.warning("can't interrupt process group %s: %s (sig=%s)",
                    pgid, err, signum)

def _main():
    config = read_config()
    pidfile = config.get("main", "pidfile")
    with open(pidfile, "r") as pidfd:
        pid = int(pidfd.read().strip())

    start = time.time()
    LOG.debug("Trying to stop process group %s", pid)
    found = False
    while _is_running(pid):
        found = True
        _send_signal(pid, signal.SIGINT)
        time.sleep(INTERRUPT_SLEEP)
        if time.time() - start > INTERRUPT_TIMEOUT:
            # last resort
            _send_signal(pid, signal.SIGKILL)
    print("success" if found else "PID {} not found".format(pid))

if __name__ == "__main__":
    try:
        _main()
    except Exception:  # pylint: disable=broad-except
        LOG.exception("Unexpected exception")
