#!/usr/local/bin/python2.7
"""Git subcommand to provide operations on CVS repositories."""

from glob import glob
import os
import re
import string
import sys
import traceback

from cvsgit.cmd import Cmd
from cvsgit.i18n import _
from cvsgit.error import Error
import cvsgit.command
import cvsgit.utils

class CLI(Cmd):
    """Operate on a CVS repository using Git.

    Usage: %prog <command> [options] [arguments]

    git-cvs is a conduit for changesets between CVS and Git.  It
    currently provides only a unidirectional flow of changes between
    a CVS repository and a Git repository.

    git-cvs can track the HEAD branch (aka the "trunk") in a CVS
    repository."""

    def initialize_options(self):
        self.add_option('--profile', action='store_true', help=\
            _("Enable profiling output for this command."))
        self.add_option('--detailed-errors', action='store_true', help=\
            _("Display full stack traces on error and display the "
              "documentation for exceptions, if available."))

    def finalize_options(self):
        pass

    def run(self):
        if len(self.args) > 0:
            self.run_command_with_exception_handling(self.args)
        else:
            self.print_available_commands()

    def run_command_with_exception_handling(self, argv):
        try:
            self.run_command(self.args)
        except Error as e:
            if self.options.detailed_errors:
                self.error(str(e) + ' (details follow)')

                (exc_type, exc_value, exc_traceback) = sys.exc_info()
                print 'Traceback (most recent call last):'
                traceback.print_tb(exc_traceback)

                if type(e).__doc__:
                    print '-'*72
                    print type(e).__name__ + ':',
                    print cvsgit.utils.dedent(type(e).__doc__).rstrip()
                    print '-'*72
            else:
                self.error(str(e) + ' (--detailed-errors for more information)')

            exit(1)

    def run_command(self, argv):
        command = argv[0]
        klass = self.get_command_class(command)
        if klass is None:
            self.usage_error(_('invalid command: %s') % command)
        else:
            if self.options.profile:
                import cProfile
                import pstats
                import tempfile
                with tempfile.NamedTemporaryFile() as tmp:
                    filename = tmp.name
                    cProfile.runctx('klass().main(argv)', globals(),
                                    {'klass':klass, 'argv':argv},
                                    filename)
                    stats = pstats.Stats(filename)
                    stats.sort_stats('cumulative')
                    stats.print_stats(10)
                    stats.sort_stats('time')
                    stats.print_stats(10)
            else:
                klass().main(argv)

    def print_available_commands(self):
        print _("Available commands:")
        for command in sorted(self.get_command_names()):
            print "  " + command

    def get_command_names(self):
        modules = {}
        for path in cvsgit.command.__path__:
            pattern = os.path.join(path, '[!_]*.py')
            for filename in glob(pattern):
                module_name = os.path.basename(filename)[:-3]
                modules[module_name] = True
        return modules.keys()

    def get_command_class(self, command):
        if not command in self.get_command_names():
            return None

        klass_name = re.sub('[^A-Za-z_]', '_', command)
        module_name = '%s.%s' % ('cvsgit.command', command)
        __import__(module_name)
        module = sys.modules[module_name]

        try:
            try:
                klass = getattr(module, klass_name)
            except AttributeError:
                alt_name = string.join(map(lambda s: s.title(),
                                           klass_name.split('_')), '')
                klass = getattr(module, alt_name)
        except AttributeError:
            raise RuntimeError(
                _("invalid command '%s' (no class '%s' in module '%s')") \
                % (command, klass_name, module_name))
        return klass

if __name__ == '__main__':
    CLI()
