Index: trac/scripts/admin.py =================================================================== --- trac/scripts/admin.py (revision 1976) +++ trac/scripts/admin.py (working copy) @@ -39,7 +39,11 @@ from trac.Milestone import Milestone from trac.perm import PermissionSystem from trac.ticket.model import * +from trac.core import ComponentManager, ExtensionPoint, Interface +from trac.loader import load_components +__all__ = [ 'IAdminConsoleProvider' ] + try: sum except NameError: @@ -50,7 +54,40 @@ tot += item return tot +class IAdminConsoleProvider(Interface): + """ + Extension point interface for components to provide an administrative + interface from within trac-admin. + """ + def get_console_commands(tracadm): + """ + Return an iterable of (name, help, callable, completer) tuples. + + tracadm is a TracAdmin instance. + + completer can be null. help is in the same format that trac-admin + uses. + """ + +class AdminCommands(trac.core.Component): + """ + Component end-point for IAdminConsoleProvider extensions + """ + admin_providers = ExtensionPoint(IAdminConsoleProvider) + + def import_providers(self, env, tracadm): + load_components(env) + for provider in self.admin_providers: + for command in provider.get_console_commands(tracadm): + name, help, callback, completer = command + if hasattr(tracadm.__class__, 'do_' + name): + raise Exception("Can't use IAdminConsoleProvider %s, console command '%s' already exists" % (provider.__class__.__name__, name)) + setattr(tracadm.__class__, 'do_' + name, callback) + setattr(tracadm.__class__, '_help_' + name, help) + if completer: + setattr(tracadm.__class__, 'complete_' + name, completer) + class TracAdmin(cmd.Cmd): intro = '' license = trac.__license_long__ @@ -64,6 +101,7 @@ _date_format = '%Y-%m-%d' _datetime_format = '%Y-%m-%d %H:%M:%S' _date_format_hint = 'YYYY-MM-DD' + _admin_commands = None def __init__(self, envdir=None): cmd.Cmd.__init__(self) @@ -72,6 +110,7 @@ self.env_set(os.path.abspath(envdir)) def docmd(self, cmd='help'): + self.env_check() self.onecmd(cmd) def emptyline(self): @@ -84,6 +123,7 @@ '%(copy)s\n\n' \ "Type: '?' or 'help' for help on commands.\n" % \ {'ver':trac.__version__,'copy':__copyright__} + self.env_check() self.cmdloop() ## @@ -99,6 +139,12 @@ def env_check(self): try: self.__env = Environment(self.envname) + try: + self._admin_commands = AdminCommands(self.__env) + self._admin_commands.import_providers(self.__env, self) + except Exception, e: + print "Failed to initialise extension points.", e + raise except: return 0 return 1 @@ -117,6 +163,8 @@ try: if not self.__env: self.__env = Environment(self.envname) + self._admin_commands = AdminCommands(self.__env) + self._admin_commands.import_providers(self.__env, self) return self.__env except Exception, e: print 'Failed to open environment.', e @@ -209,6 +257,8 @@ xrange(0, (1 + len(sep)) * cnum + sum(colw))]) print + + def print_doc(self, doc, decor=False): if not doc: return self.print_listing(['Command', 'Description'], doc, ' --', decor) @@ -299,15 +349,13 @@ except AttributeError: print "No documentation found for '%s'" % arg[0] else: - docs = (self._help_about + self._help_help + - self._help_initenv + self._help_hotcopy + - self._help_resync + self._help_upgrade + - self._help_wiki + -# self._help_config + self._help_wiki + - self._help_permission + self._help_component + - self._help_ticket_type + self._help_priority + - self._help_severity + self._help_version + - self._help_milestone) + # Extract documentation from all _help_* members + docs = [] + doc_strings = [doc for doc in dir(self) if doc.startswith('_help_') and doc[6:] not in ('EOF', 'exit', 'quit')] + for doc in doc_strings: + docs.extend(getattr(self, doc)) + docs.sort(lambda a, b: cmp(a[0], b[0])) + print 'trac-admin - The Trac Administration Console %s' % trac.__version__ if not self.interactive: print