#!/usr/bin/env python
"""
Command-line interface to the Sumatra computational experiment management tool.
This is a developer tool which does exactly the same as the 'smt' command
except that it also outputs profiling information about Sumatra upon successful
completion of the run.
"""

import sys
import cProfile
import pstats
from textwrap import dedent
from argparse import ArgumentParser
from sumatra import commands, __version__
from sumatra.versioncontrol.base import VersionControlError
from sumatra.recordstore.base import RecordStoreAccessError

usage = "smt_profile [profiling_options] <subcommand> [cmd_options] [args]"

description = dedent("""
    Profile a Sumatra subcommand (run 'smt' for available commands).
    This runs the given command using cProfile and upon completion
    outputs a diagnostic message on the screen. It also dumps the raw
    profiling data into a file which can be analysed using Python's
    'pstats' module or a graphical user interface like 'RunSnakeRun'.
    Apart from the profiling options this should be the exact same
    command that would be used without 'smt' itself. Example:
    "smt_profile run -r 'Informative message.' defaults.param". Note
    that enabling profiling may considerably slow down execution.
    """)

parser = ArgumentParser(usage=usage, description=description)
parser.add_argument('-n', metavar='N', type=int, default=20,
                    help="number of lines to print in profiling stats. Default: 20.")
parser.add_argument('-s', '--sorting-method', metavar='METHOD', default='cumulative',
                    help="method used to sort the profiling stats. "
                         "This can be any of the methods accepted by "
                         "pstats.Stats.sort_stats(). Default: 'cumulative'")
parser.add_argument('-o', '--output-file', metavar='PATH',
                    default='profiling_stats.prof',
                    help="Filename for storing the generated profiling "
                          "data (in binary format, as generated by "
                          "cProfile). Default: 'profiling_stats.prof'")

# The parser should only parse options up to the first valid
# Sumatra subcommand; everything after that should not be
# interpreted as an option for the 'profile' command but should be
# passed on to the subcommand. We achieve this by finding the
# first valid subcommand and splitting the list of options into
# "before" and "after". Only the first half is processed here.
subcmds = [cmd for cmd in sys.argv if cmd in commands.modes]
i = sys.argv.index(subcmds[0]) if subcmds != [] else len(sys.argv)
argv_profile, argv_cmd = sys.argv[1:i], sys.argv[i+1:]

args = parser.parse_args(argv_profile)
if subcmds != []:
    cmd = subcmds[0]
else:
    parser.error('Please specify a command which you would like to profile.\n\n'
                 'Available commands:\n  {}'.format("\n  ".join(commands.modes)))

stats_file = args.output_file
cProfile.run("from sumatra import commands; "
             "commands.{}({})".format(cmd, argv_cmd), stats_file)
p = pstats.Stats(stats_file)
p.sort_stats(args.sorting_method).print_stats(args.n)


cmd = sys.argv[1]
try:
    main = getattr(commands, cmd)
except AttributeError:
    print(usage)
    sys.exit(1)

try:
    main(sys.argv[2:])
except (VersionControlError, RecordStoreAccessError) as err:
    print("Error: {}".format(err))
    sys.exit(1)
