#!/usr/pkg/bin/python3.11

from __future__ import print_function
import sys
import re
import anita
import os
import optparse
import pexpect

class Usage(Exception):
    def __init__(self, msg):
        self.msg = msg

def main(argv = None):
    if argv is None:
        argv = sys.argv

    dtb_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
                            'share', 'dtb', 'arm', 'vexpress-v2p-ca15-tc1.dtb')
    parser = optparse.OptionParser(
        usage = "usage: %prog [options] install|boot|interact distribution")
    parser.add_option("--workdir",
                      help="store work files in DIR", metavar="DIR")
    parser.add_option("--vmm",
                      help="use VMM (qemu/xl/xm/gxemul/simh) as the virtual machine monitor",
                      metavar="VMM")
    parser.add_option("--vmm-args",
                      help="pass ARGS as extra arguments to virtual machine monitor",
                      metavar="ARGS", default="")
    # Deprecated
    parser.add_option("--qemu-args",
                      help=optparse.SUPPRESS_HELP, default="")
    parser.add_option("--disk-size",
                      help="use a virtual disk of SIZE bytes (k/M/G/T suffix accepted)",
                      metavar="SIZE")
    parser.add_option("--memory-size",
                      help="use a virtual RAM size of SIZE bytes (k/M/G/T suffix accepted)",
                      metavar="SIZE")
    parser.add_option("--run",
                      help="run COMMAND on the virtual machine after boot", metavar="COMMAND")
    parser.add_option("--sets",
                      help="install the distribution SETS (e.g., base,games)",
                      metavar="SETS")
    parser.add_option("--test-timeout",
                      help="allow TIMEOUT seconds for each ATF test", metavar="TIMEOUT",
                      type="int", default=10800)
    parser.add_option("--run-timeout",
                      help="allow TIMEOUT seconds for command run using the --run option", metavar="TIMEOUT",
                      type="int", default=3600)
    parser.add_option("--persist",
                      help="make changes to disk contents persistent", action="store_true")
    parser.add_option("--boot-from",
                      help="boot from MEDIA (floppy/cdrom)", metavar="MEDIA")
    parser.add_option("--structured-log", action="store_true",
                      help="log console traffic in a structured format, to stdout")
    parser.add_option("--structured-log-file", metavar="FILE",
                      help="log console traffic in a structured format, to FILE")
    parser.add_option("--no-install", action="store_true",
                      help="in boot/test/interact mode, assume system is already installed", default=False)
    parser.add_option("--version", action="store_true",
                      help="print the anita version number and exit")
    parser.add_option("--tests", help='select the tests to run in test mode: "atf" or "kyua"',
                      type="string", default="atf")
    parser.add_option("--dtb", help='use the Device Tree Blob (.dtb) PATH_TO_DTB',
                      type="string", metavar="PATH_TO_DTB", default=dtb_path)
    parser.add_option("--xen-type", help='select the Xen guest type: "pv", "pvshim", "hvm", or "pvh"',
                      type="string", metavar="TYPE", default='pv')
    parser.add_option("--image-format", help='select the guest disk image format: "dense" or "sparse"',
                      type="string", metavar='FORMAT', default='dense')
    parser.add_option("--machine", help='select the emulated machine type, e.g., ' \
                      '"vexpress-a15" or "virt"',
                      type="string", metavar='MACHINE')
    parser.add_option("--network-config", help='load network configuration from FILE',
                      type="string", metavar='FILE')
    parser.add_option("--partitioning-scheme", help='prefer partitioning scheme SCHEME',
                      type="string", metavar='SCHEME')
    parser.add_option("--no-entropy", help='do not seed the installed system with entropy',
                      action="store_true")

    (options, args) = parser.parse_args()

    if options.version:
        print(anita.__version__)
        sys.exit(0)

    if len(args) < 2:
        raise Usage("not enough arguments")

    distarg = args[1]

    vmm_args = options.vmm_args.split() + options.qemu_args.split()

    if options.sets:
        sets = options.sets.split(",")
    else:
        sets = None

    dist = anita.distribution(distarg, sets = sets)

    if dist.arch() == 'evbarm-earmv7hf':
        if not os.path.exists(options.dtb):
            raise IOError("The Device Tree Blob %s does not exist." % options.dtb)

    with anita.Anita(dist,
        workdir = options.workdir,
        vmm = options.vmm,
        vmm_args = vmm_args,
        disk_size = options.disk_size,
        memory_size = options.memory_size,
        persist = options.persist,
        boot_from = options.boot_from,
        structured_log = options.structured_log,
        structured_log_file = options.structured_log_file,
        no_install = options.no_install,
        tests = options.tests,
        dtb = options.dtb,
        xen_type = options.xen_type,
        image_format = options.image_format,
        machine = options.machine,
        network_config = options.network_config,
        partitioning_scheme = options.partitioning_scheme,
        no_entropy = options.no_entropy
        ) as a:

        status = 0
        mode = args[0]

        if mode != 'print-workdir':
            print("This is anita version", anita.__version__)
            print("Using pexpect version", pexpect.__version__)
            print(anita.quote_shell_command(sys.argv))
            sys.stdout.flush()

        if mode == 'install':
            a.install()
        elif mode == 'boot':
            a.boot()
            if options.run:
                status = a.shell_cmd(options.run, options.run_timeout)
            a.halt()
        elif mode == 'interact':
            if options.run:
                a.boot()
                status = a.shell_cmd(options.run, options.run_timeout)
                if status != 0:
                    a.halt()
                    return status
            else:
                # Allow interaction with boot process
                a.start_boot()
            a.console_interaction()
        elif mode == 'test':
            status = a.run_tests(timeout = options.test_timeout)
        elif mode == 'print-workdir':
            print(a.workdir)
        else:
            raise Usage("unknown mode: " + mode)
        return status

if __name__ == "__main__":
    try:
        status = main()
        sys.exit(status)
    except Usage as err:
        print("%s: %s" % (os.path.basename(sys.argv[0]), err.msg), file=sys.stderr)
        print("for help use --help", file=sys.stderr)
        sys.exit(1)
