#!/usr/bin/env python

"""This spawns a sub-shell (bash) and gives the user interactive control. The
entire shell session is logged to a file called script.log. This behaves much
like the classic BSD command 'script'.

./script.py [-a] [-c command] {logfilename}

    logfilename : This is the name of the log file. Default is script.log.
    -a : Append to log file. Default is to overwrite log file.
    -c : spawn command. Default is to spawn the sh shell.

Example:

    This will start a bash shell and append to the log named my_session.log:

        ./script.py -a -c bash my_session.log

"""

import os
import sys
import time
import getopt
import signal
import fcntl
import termios
import struct
import traceback
import pexpect

global_pexpect_instance = None  # Used by signal handler


def exit_with_usage():

    print globals()['__doc__']
    os._exit(1)


def main():

    ######################################################################
    # Parse the options, arguments, get ready, etc.
    ######################################################################
    try:
        optlist, args = getopt.getopt(
            sys.argv[
                1:], 'h?ac:', [
                'help', 'h', '?'])
    except Exception as e:
        print str(e)
        exit_with_usage()
    options = dict(optlist)
    if len(args) > 1:
        exit_with_usage()

    if [elem for elem in options if elem in [
            '-h', '--h', '-?', '--?', '--help']]:
        print "Help:"
        exit_with_usage()

    if len(args) == 1:
        script_filename = args[0]
    else:
        script_filename = "script.log"
    if '-a' in options:
        fout = file(script_filename, "ab")
    else:
        fout = file(script_filename, "wb")
    if '-c' in options:
        command = options['-c']
    else:
        command = "sh"

    # Begin log with date/time in the form CCCCyymm.hhmmss
    fout.write('# %4d%02d%02d.%02d%02d%02d \n' % time.localtime()[:-3])

    ######################################################################
    # Start the interactive session
    ######################################################################
    p = pexpect.spawn(command)
    p.logfile = fout
    global global_pexpect_instance
    global_pexpect_instance = p
    signal.signal(signal.SIGWINCH, sigwinch_passthrough)

    print "Script recording started. Type ^] (ASCII 29) to escape from the script shell."
    p.interact(chr(29))
    fout.close()
    return 0


def sigwinch_passthrough(sig, data):

    # Check for buggy platforms (see pexpect.setwinsize()).
    if 'TIOCGWINSZ' in dir(termios):
        TIOCGWINSZ = termios.TIOCGWINSZ
    else:
        TIOCGWINSZ = 1074295912  # assume
    s = struct.pack("HHHH", 0, 0, 0, 0)
    a = struct.unpack('HHHH', fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s))
    global global_pexpect_instance
    global_pexpect_instance.setwinsize(a[0], a[1])

if __name__ == "__main__":
    try:
        main()
    except SystemExit as e:
        raise e
    except Exception as e:
        print "ERROR"
        print str(e)
        traceback.print_exc()
        os._exit(1)
