#! /usr/bin/env python

#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2022 Chris Johns (Contemporary Software)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. 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.
#

from __future__ import print_function

import argparse
import os.path
import re
import sys
import threading

re_imp = re.compile(r'^(#)*?([^#=]*?)\ =\ (.*?)$', re.M)

lockfile = '.lock-waf_%s_build' % sys.platform

class command:
    def __init__(self, cmd, cwd=os.path.abspath(os.getcwd())):
        self.capture_output = False
        self.exit_code = 0
        self.thread = None
        self.output = None
        self.cmd = cmd
        self.cwd = cwd
        self.result = None

    def runner(self):
        import datetime
        import subprocess
        #
        # Support Python 2.6
        #
        if "check_output" not in dir(subprocess):
            def f(*popenargs, **kwargs):
                if 'stdout' in kwargs:
                    raise ValueError('stdout argument not allowed, it will be overridden.')
                process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
                output, unused_err = process.communicate()
                retcode = process.poll()
                if retcode:
                    cmd = kwargs.get("args")
                    if cmd is None:
                        cmd = popenargs[0]
                    raise subprocess.CalledProcessError(retcode, cmd)
                return output
            subprocess.check_output = f
        self.start_time = datetime.datetime.now()
        self.exit_code = 0
        try:
            try:
                if os.name == 'nt':
                    cmd = ['sh', '-c'] + self.cmd
                else:
                    cmd = self.cmd
                if self.capture_output:
                    self.output = subprocess.check_output(cmd, cwd = self.cwd)
                else:
                    self.output = subprocess.call(cmd, cwd = self.cwd)
            except subprocess.CalledProcessError as cpe:
                self.exit_code = cpe.returncode
                self.output = cpe.output
            except OSError as ose:
                raise general_error('bootstrap failed: %s in %s: %s' % \
                                        (' '.join(cmd), self.cwd, (str(ose))))
            except KeyboardInterrupt:
                pass
            except:
                raise
        except:
            self.result = sys.exc_info()
        self.end_time = datetime.datetime.now()

    def run(self):
        self.thread = threading.Thread(target = self.runner)
        self.thread.start()

    def is_alive(self):
        return self.thread and self.thread.is_alive()

    def reraise(self):
        if self.result is not None:
            raise self.result[0](self.result[1])

def lockfile_load(name):
    try:
        data = {}
        for l in re_imp.finditer(open(name).read()):
            data[l.group(2)] = eval(l.group(3))
        return data
    except OSError as e:
        print('error: lockfile: %s' % (e), file=sys.stderr)
    except IOError as e:
        print('error: lockfile: %s' % (e), file=sys.stderr)
    except:
        print('error: lockfile: cannot read: %s' % (name), file=sys.stderr)
    sys.exit(1)

def waf_configure_command(name):
    data = lockfile_load(name)
    if 'argv' not in data:
        print('error: lockfile: no argv found', file=sys.stderr)
        sys.exit(1)
    return data['argv']

def run(args=sys.argv, command_path=None):
    description  = 'Reconfigure a waf build'
    argsp = argparse.ArgumentParser(prog='waf-reconfig', description=description)

    argsp.add_argument('-l', '--lockfile',
                       help = 'lock file (default: %(default)s).',
                       type = str, default = lockfile)
    argsp.add_argument('-n', '--dry-run',
                       help = 'dry run (default: %(default)s).',
                       action='store_true')
    argopts = argsp.parse_args(args[1:])

    reconf_cmds = waf_configure_command(argopts.lockfile)
    print(' '.join(reconf_cmds))
    if not argopts.dry_run:
        cmd = command(reconf_cmds)
        cmd.run()

    sys.exit(0)

if __name__ == "__main__":
    run()
