#!/usr/bin/env python
import argparse
import pexpect
import serial
import sys
import time
from pexpect import fdpexpect, TIMEOUT

parser = argparse.ArgumentParser(description='Connect to serial console ' +
                                 'to execute stuff')
parser.add_argument('--port', required=True,
                    help='serial console device to connect ' +
                    'to (e.g. /dev/pts/X)')
parser.add_argument('--hostname', default="buster",
                    help='hostname of the system for login process ' +
                    '(default: buster)')
parser.add_argument('--user', default="root",
                    help='user name to use for login (default: root)')
parser.add_argument('--password', default="grml",
                    help='password for login (default: grml)')
parser.add_argument('--tries', default="12", type=int,
                    help='Number of retries for finding the login prompt')
parser.add_argument('--poweroff', action="store_true", default=False,
                    help='send "poweroff" command after all other commands')
parser.add_argument('command', nargs='+',
                    help='command to execute after logging in')



def print_ser_lines(ser):
    for line in ser.readlines():
        print("<<", line)  # line will be a binary string


def write_ser_line(ser, text):
    print(">>", text)
    ser.write(("%s\n" % text).encode())
    ser.flush()


def login(ser, hostname, user, password, timeout=5):

    child = fdpexpect.fdspawn(ser.fileno())
    child.sendline("\n")

    try:
        child.expect("%s@%s" % (user, hostname), timeout=timeout)
        return
    except:
        pass

    print("Waiting for login prompt...")
    child.expect("%s login:" % hostname, timeout=timeout)
    print("Logging in...")
    write_ser_line(ser, user)
    time.sleep(1)
    write_ser_line(ser, password)
    time.sleep(1)

    print("Waiting for shell prompt...")
    child.expect("%s@%s" % (user, hostname), timeout=timeout)


def main():
    args = parser.parse_args()
    hostname = args.hostname
    password = args.password
    port = args.port
    user = args.user
    commands = args.command

    ser = serial.Serial(port, 115200)
    ser.flushInput()
    ser.flushOutput()

    success = False
    for i in range(args.tries):
        try:
            print("Logging into %s via serial console [try %s]" % (port, i))
            login(ser, hostname, user, password)
            success = True
            break
        except Exception as except_inst:
            print("Login failure (try %s):" % (i, ), except_inst, file=sys.stderr)
            time.sleep(5)

    if success:
        write_ser_line(ser, "")
        ser.timeout = 5
        print_ser_lines(ser)
        print("Running commands...")
        for command in commands:
            write_ser_line(ser, command)
            print_ser_lines(ser)
        if args.poweroff:
            print("Sending final poweroff command...")
            write_ser_line(ser, "poweroff")
            ser.flush()
            # after poweroff, the serial device will probably vanish. do not attempt reading from it anymore.

    if not success:
        sys.exit(1)

if __name__ == "__main__":
    main()
