#!/usr/bin/env python
#
# Copyright (C) 2017 Igalia S.L.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
import sys
import signal
import os
import argparse
import subprocess
import tempfile
import shutil
import socket
import json
import traceback
import multiprocessing
from time import sleep

test_buildbot_master_tac = """
import os
from twisted.application import service
try:
    from buildbot.master.bot import BuildMaster
except:
    from buildbot.master import BuildMaster

basedir = os.path.dirname(os.path.realpath(__file__))
configfile = r'master.cfg'

application = service.Application('buildmaster')
BuildMaster(basedir, configfile).setServiceParent(application)
"""

worker_buildbot_master_tac = """
import os
from twisted.application import service
from buildslave.bot import BuildSlave

basedir = os.path.dirname(os.path.realpath(__file__))
buildmaster_host = 'localhost'
port = 17000
slavename = '%(worker)s'
passwd = '1234'
keepalive = 600
usepty = 1

application = service.Application('buildslave')
BuildSlave(buildmaster_host, port, slavename, passwd, basedir, keepalive, usepty).setServiceParent(application)
"""


def check_tcp_port_open(address, port):
    s = socket.socket()
    try:
        s.connect((address, port))
        return True
    except:
        return False


def upgrade_db_needed(log):
    try:
        with open(log) as f:
            for l in f:
                if 'upgrade the database' in l:
                    return True
    except:
        return False
    return False


def create_tempdir(tmpdir=None):
    if tmpdir is not None:
        if not os.path.isdir(tmpdir):
            raise ValueError('%s is not a directory' % tmpdir)
        return tempfile.mkdtemp(prefix=os.path.join(os.path.abspath(tmpdir), 'tmp'))
    return tempfile.mkdtemp()


def print_if_error_stdout_stderr(cmd, retcode, stdout=None, stderr=None, extramsg=None):
    if retcode != 0:
        if type(cmd) == type([]):
            cmd = ' '.join(cmd)
        print('WARNING: "%s" returned %s status code' % (cmd, retcode))
        if stdout is not None:
            print(stdout)
        if stderr is not None:
            print(stderr)
        if extramsg is not None:
            print(extramsg)


def setup_master_workdir(configdir, base_workdir):
    master_workdir = os.path.join(base_workdir, 'master')
    print('Copying files from %s to %s ...' % (configdir, master_workdir))
    shutil.copytree(configdir, master_workdir)
    print('Generating buildbot files at %s ...' % master_workdir)
    with open(os.path.join(master_workdir, 'buildbot.tac'), 'w') as f:
        f.write(test_buildbot_master_tac)
    mkpwd_cmd = ['./make_passwords_json.py']
    mkpwd_process = subprocess.Popen(mkpwd_cmd, cwd=master_workdir,
                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    stdout, stderr = mkpwd_process.communicate()
    print_if_error_stdout_stderr(mkpwd_cmd, mkpwd_process.returncode, stdout, stderr)
    return master_workdir


def wait_for_master_ready(master_workdir):
    master_ready_check_counter = 0
    while True:
        if os.path.isfile(os.path.join(master_workdir, '.master-is-ready')):
            return
        if master_ready_check_counter > 60:
            raise RuntimeError('ERROR: Aborting after waiting 60 seconds for the master to start.')
        sleep(1)
        master_ready_check_counter += 1


def start_master(master_workdir):
    # This is started via multiprocessing. We set a new process group here
    # to be able to reliably kill this subprocess and all of its child on clean.
    os.setsid()
    buildmasterlog = os.path.join(master_workdir, 'buildmaster.log')
    dbupgraded = False
    retry = True
    if check_tcp_port_open('localhost', 8710):
        print('ERROR: There is some process already listening in port 8170')
        return 1
    while retry:
        retry = False
        print('Starting the twistd process ...')
        twistd_cmd = ['twistd', '-l', buildmasterlog, '-noy', 'buildbot.tac']
        twistd_process = subprocess.Popen(twistd_cmd, cwd=master_workdir,
                    stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        while twistd_process.poll() is None:
            if check_tcp_port_open('localhost', 8710):
                print('Test buildmaster ready!.\n\n'
                     + ' - See buildmaster log:\n'
                     + '     tail -f %s\n' % buildmasterlog
                     + ' - Open a browser to:\n'
                     + '     http://localhost:8710\n'
                     + ' - Credentials for triggering manual builds:\n'
                     + '     login:     committer@webkit.org\n'
                     + '     password:  committerpassword\n')
                with open(os.path.join(master_workdir, '.master-is-ready'), 'w') as f:
                    f.write('ready')
                twistd_process.wait()
                return 0
            sleep(1)
        stdout, stderr = twistd_process.communicate()
        if twistd_process.returncode == 0 and upgrade_db_needed(buildmasterlog) and not dbupgraded:
            retry = True
            dbupgraded = True
            print('Upgrading the database ...')
            upgrade_cmd = ['buildbot', 'upgrade-master', master_workdir]
            upgrade_process = subprocess.Popen(upgrade_cmd, cwd=master_workdir,
                    stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            stdout, stderr = upgrade_process.communicate()
            print_if_error_stdout_stderr(upgrade_cmd, upgrade_process.returncode, stdout, stderr)
        else:
            print_if_error_stdout_stderr(twistd_cmd, twistd_process.returncode, stdout, stderr,
                                         'Check the log at %s' % buildmasterlog)
    return 0


def get_list_workers(master_workdir):
    password_list = os.path.join(master_workdir, 'passwords.json')
    with open(password_list) as f:
        passwords = json.load(f)
    list_workers = []
    for worker in passwords.keys():
        list_workers.append(str(worker))
    return list_workers


def start_worker(base_workdir, worker):
    # This is started via multiprocessing. We set a new process group here
    # to be able to reliably kill this subprocess and all of its child on clean.
    os.setsid()
    worker_workdir = os.path.join(base_workdir, worker)
    os.mkdir(worker_workdir)
    with open(os.path.join(worker_workdir, 'buildbot.tac'), 'w') as f:
        f.write(worker_buildbot_master_tac % {'worker': worker})
    twistd_cmd = ['twistd', '-l', 'worker.log', '-noy', 'buildbot.tac']
    twistd_worker_process = subprocess.Popen(twistd_cmd, cwd=worker_workdir,
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    try:
        stdout, stderr = twistd_worker_process.communicate()
    except:
        twistd_worker_process.kill()
        return
    print_if_error_stdout_stderr(twistd_cmd, twistd_worker_process.returncode, stdout, stderr,
                                 'Check the log at %s' % os.path.join(worker_workdir, 'worker.log'))


def clean(temp_dir):
    if os.path.isdir(temp_dir):
        print('\n\nCleaning %s ... \n' % (temp_dir))
        # shutil.rmtree can fail if we hold an open file descriptor on temp_dir
        # (which is very likely when cleaning) or if temp_dir is a NFS mount.
        # Use rm instead that always works.
        rm = subprocess.Popen(['rm', '-fr', temp_dir])
        rm.wait()


def cmd_exists(cmd):
    return any(os.access(os.path.join(path, cmd), os.X_OK)
               for path in os.environ['PATH'].split(os.pathsep))


def check_buildbot_installed():
    if cmd_exists('twistd') and cmd_exists('buildbot'):
        return
    raise RuntimeError('Buildbot is not installed.')


def setup_virtualenv(base_workdir_temp):
    if cmd_exists('virtualenv'):
        print('Setting up virtualenv at %s ... ' % base_workdir_temp)
        virtualenv_cmd = ['virtualenv', '-p', 'python2', 'venv']
        virtualenv_process = subprocess.Popen(virtualenv_cmd, cwd=base_workdir_temp,
                                                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, stderr = virtualenv_process.communicate()
        print_if_error_stdout_stderr(virtualenv_cmd, virtualenv_process.returncode, stdout, stderr)
        virtualenv_bindir = os.path.join(base_workdir_temp, 'venv', 'bin')
        virtualenv_pip = os.path.join(virtualenv_bindir, 'pip')
        if not os.access(virtualenv_pip, os.X_OK):
            print('Something went wrong setting up virtualenv'
                  'Trying to continue using the system version of buildbot')
            return
        print('Setting up buildbot dependencies on the virtualenv ... ')
        # The idea is to install the very same version of buildbot and its
        # dependencies than the ones used for running https://build.webkit.org/about
        pip_cmd = [virtualenv_pip, 'install',
                    'buildbot==0.8.6p1',
                    'buildbot-slave==0.8.6p1',
                    'twisted==12.1.0',
                    'jinja2==2.6',
                    'sqlalchemy==0.7.8',
                    'sqlalchemy-migrate==0.12.0']
        pip_process = subprocess.Popen(pip_cmd, cwd=base_workdir_temp,
                                       stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, stderr = pip_process.communicate()
        print_if_error_stdout_stderr(pip_cmd, pip_process.returncode, stdout, stderr)
        os.environ['PATH'] = virtualenv_bindir + ':' + os.environ['PATH']
        return
    print('WARNING: virtualenv not installed. '
          'Trying to continue using the system version of buildbot')


def configdir_is_valid(configdir):
    return(os.path.isdir(configdir) and
           os.path.isfile(os.path.join(configdir, 'config.json')) and
           os.path.isfile(os.path.join(configdir, 'master.cfg')) and
           os.access(os.path.join(configdir, 'make_passwords_json.py'), os.X_OK))


def main(configdir, basetempdir=None, no_clean=False, no_workers=False, use_system_version=False):
    configdir = os.path.abspath(os.path.realpath(configdir))
    if not configdir_is_valid(configdir):
        raise ValueError('The configdir %s dont contains the buildmaster files expected by this script' % configdir)
    base_workdir_temp = os.path.abspath(os.path.realpath(create_tempdir(basetempdir)))
    if base_workdir_temp.startswith(configdir):
        raise ValueError('The temporal working directory %s cant be located inside configdir %s' % (base_workdir_temp, configdir))
    try:
        if not use_system_version:
            setup_virtualenv(base_workdir_temp)
        check_buildbot_installed()
        master_workdir = setup_master_workdir(configdir, base_workdir_temp)
        master_runner = multiprocessing.Process(target=start_master, args=(master_workdir,))
        master_runner.start()
        wait_for_master_ready(master_workdir)
        if no_workers:
            print(' - To manually attach a build worker use this info:\n'
                 + '     TCP port for the worker-to-master connection: 17000\n'
                 + '     worker-id: the one defined at %s\n' % os.path.join(master_workdir, 'passwords.json')
                 + '     password:  1234\n')
        else:
            worker_runners = []
            for worker in get_list_workers(master_workdir):
                worker_runner = multiprocessing.Process(target=start_worker, args=(base_workdir_temp, worker,))
                worker_runner.start()
                worker_runners.append(worker_runner)
            print(' - Workers started!.\n'
                 + '     Check the log for each one at %s/${worker-name-id}/worker.log\n' % base_workdir_temp
                 + '     tail -f %s/*/worker.log\n' % base_workdir_temp)
            for worker_runner in worker_runners:
                worker_runner.join()
        master_runner.join()
    except:
        traceback.print_exc()
    finally:
        try:
            # The children may exit between the check and the kill call.
            # Ignore any exception raised here.
            for c in multiprocessing.active_children():
                # Send the signal to the whole process group.
                # Otherwise some twistd sub-childs can remain alive.
                os.killpg(os.getpgid(c.pid), signal.SIGKILL)
        except:
            pass
        if not no_clean:
            clean(base_workdir_temp)
        sys.exit(0)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--config-dir', help='Path to the directory of the build master config files. '
                        'Defauls to the directory where this script is located.',
                        dest='configdir', type=str,
                        default=os.path.dirname(__file__))
    parser.add_argument('--base-temp-dir', help='Path where the temporal working directory will be created. '
                        'Note: To trigger test builds with the test workers you need enough free space on that path.',
                        dest='basetempdir', default=None, type=str)
    parser.add_argument('--no-clean', help='Do not clean the temporal working dir on exit.',
                        dest='no_clean', action='store_true')
    parser.add_argument('--no-workers', help='Do not start the test workers.',
                        dest='no_workers', action='store_true')
    parser.add_argument('--use-system-version', help='Instead of setting up a virtualenv with the buildbot version '
                        'used by build.webkit.org, use the buildbot version installed on this system.',
                        dest='use_system_version', action='store_true')
    args = parser.parse_args()
    main(args.configdir, args.basetempdir, args.no_clean, args.no_workers, args.use_system_version)
