#!/usr/bin/env python

# devtool stress tester
#
# Written by: Paul Eggleton <paul.eggleton@linux.intel.com>
#
# Copyright 2015 Intel Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# 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.
#

import sys
import os
import os.path
import subprocess
import re
import argparse
import logging
import tempfile
import shutil
import signal
import fnmatch

scripts_lib_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'lib'))
sys.path.insert(0, scripts_lib_path)
import scriptutils
logger = scriptutils.logger_create('devtool-stress')

def select_recipes(args):
    import bb.tinfoil
    tinfoil = bb.tinfoil.Tinfoil()
    tinfoil.prepare(False)

    pkg_pn = tinfoil.cooker.recipecache.pkg_pn
    (latest_versions, preferred_versions) = bb.providers.findProviders(tinfoil.config_data, tinfoil.cooker.recipecache, pkg_pn)

    skip_classes = args.skip_classes.split(',')

    recipelist = []
    for pn in sorted(pkg_pn):
        pref = preferred_versions[pn]
        inherits = [os.path.splitext(os.path.basename(f))[0] for f in tinfoil.cooker.recipecache.inherits[pref[1]]]
        for cls in skip_classes:
            if cls in inherits:
                break
        else:
            recipelist.append(pn)

    tinfoil.shutdown()

    resume_from = args.resume_from
    if resume_from:
        if not resume_from in recipelist:
            print('%s is not a testable recipe' % resume_from)
            return 1
    if args.only:
        only = args.only.split(',')
        for onlyitem in only:
            for pn in recipelist:
                if fnmatch.fnmatch(pn, onlyitem):
                    break
            else:
                print('%s does not match any testable recipe' % onlyitem)
                return 1
    else:
        only = None
    if args.skip:
        skip = args.skip.split(',')
    else:
        skip = []

    recipes = []
    for pn in recipelist:
        if resume_from:
            if pn == resume_from:
                resume_from = None
            else:
                continue

        if args.only:
            for item in only:
                if fnmatch.fnmatch(pn, item):
                    break
            else:
                continue

        skipit = False
        for item in skip:
            if fnmatch.fnmatch(pn, item):
                skipit = True
        if skipit:
            continue

        recipes.append(pn)

    return recipes


def stress_extract(args):
    import bb.process

    recipes = select_recipes(args)

    failures = 0
    tmpdir = tempfile.mkdtemp()
    os.setpgrp()
    try:
        for pn in recipes:
            sys.stdout.write('Testing %s ' % (pn + ' ').ljust(40, '.'))
            sys.stdout.flush()
            failed = False

            srctree = os.path.join(tmpdir, pn)
            try:
                bb.process.run('devtool extract %s %s' % (pn, srctree))
            except bb.process.CmdError as exc:
                failed = True
                with open('stress_%s_extract.log' % pn, 'w') as f:
                    f.write(str(exc))

            if os.path.exists(srctree):
                shutil.rmtree(srctree)

            if failed:
                print('failed')
                failures += 1
            else:
                print('ok')
    except KeyboardInterrupt:
        # We want any child processes killed. This is crude, but effective.
        os.killpg(0, signal.SIGTERM)

    if failures:
        return 1
    else:
        return 0


def stress_modify(args):
    import bb.process

    recipes = select_recipes(args)

    failures = 0
    tmpdir = tempfile.mkdtemp()
    os.setpgrp()
    try:
        for pn in recipes:
            sys.stdout.write('Testing %s ' % (pn + ' ').ljust(40, '.'))
            sys.stdout.flush()
            failed = False
            reset = True

            srctree = os.path.join(tmpdir, pn)
            try:
                bb.process.run('devtool modify -x %s %s' % (pn, srctree))
            except bb.process.CmdError as exc:
                with open('stress_%s_modify.log' % pn, 'w') as f:
                    f.write(str(exc))
                failed = 'modify'
                reset = False

            if not failed:
                try:
                    bb.process.run('bitbake -c install %s' % pn)
                except bb.process.CmdError as exc:
                    with open('stress_%s_install.log' % pn, 'w') as f:
                        f.write(str(exc))
                    failed = 'build'
            if reset:
                try:
                    bb.process.run('devtool reset %s' % pn)
                except bb.process.CmdError as exc:
                    print('devtool reset failed: %s' % str(exc))
                    break

            if os.path.exists(srctree):
                shutil.rmtree(srctree)

            if failed:
                print('failed (%s)' % failed)
                failures += 1
            else:
                print('ok')
    except KeyboardInterrupt:
        # We want any child processes killed. This is crude, but effective.
        os.killpg(0, signal.SIGTERM)

    if failures:
        return 1
    else:
        return 0


def main():
    parser = argparse.ArgumentParser(description="devtool stress tester",
                                     epilog="Use %(prog)s <subcommand> --help to get help on a specific command")
    parser.add_argument('-d', '--debug', help='Enable debug output', action='store_true')
    parser.add_argument('-r', '--resume-from', help='Resume from specified recipe', metavar='PN')
    parser.add_argument('-o', '--only', help='Only test specified recipes (comma-separated without spaces, wildcards allowed)', metavar='PNLIST')
    parser.add_argument('-s', '--skip', help='Skip specified recipes (comma-separated without spaces, wildcards allowed)', metavar='PNLIST')
    parser.add_argument('-c', '--skip-classes', help='Skip recipes inheriting specified classes (comma-separated) - default %(default)s', metavar='CLASSLIST', default='native,nativesdk,cross,cross-canadian,image,populate_sdk,meta,packagegroup')
    subparsers = parser.add_subparsers(title='subcommands', metavar='<subcommand>')

    parser_modify = subparsers.add_parser('modify',
                                          help='Run "devtool modify" followed by a build with bitbake on matching recipes',
                                          description='Runs "devtool modify" followed by a build with bitbake on matching recipes')
    parser_modify.set_defaults(func=stress_modify)

    parser_extract = subparsers.add_parser('extract',
                                           help='Run "devtool extract" on matching recipes',
                                           description='Runs "devtool extract" on matching recipes')
    parser_extract.set_defaults(func=stress_extract)

    args = parser.parse_args()

    if args.debug:
        logger.setLevel(logging.DEBUG)

    import scriptpath
    bitbakepath = scriptpath.add_bitbake_lib_path()
    if not bitbakepath:
        logger.error("Unable to find bitbake by searching parent directory of this script or PATH")
        return 1
    logger.debug('Found bitbake path: %s' % bitbakepath)

    ret = args.func(args)

if __name__ == "__main__":
    main()
