diff mercurial/extensions.py @ 10364:de1e7099d100

dispatch: provide help for disabled extensions and commands Before a command is declared unknown, each extension in hgext is searched, starting with hgext.<cmdname>. If there's a matching command, a help message suggests the appropriate extension and how to enable it. Every extension could potentially be imported, but for cases like rebase, relink, etc. only one extension is imported. For the case of "hg help disabledext", if the extension is in hgext, the extension description is read and a similar help suggestion is printed. No extension import occurs.
author Brodie Rao <me+hg@dackz.net>
date Sun, 07 Feb 2010 14:01:43 +0100
parents c07974215b3d
children 367ce8514da0
line wrap: on
line diff
--- a/mercurial/extensions.py	Sun Feb 07 11:32:08 2010 +0100
+++ b/mercurial/extensions.py	Sun Feb 07 14:01:43 2010 +0100
@@ -6,7 +6,7 @@
 # GNU General Public License version 2 or any later version.
 
 import imp, os
-import util, cmdutil, help
+import util, cmdutil, help, error
 from i18n import _, gettext
 
 _extensions = {}
@@ -131,8 +131,9 @@
     setattr(container, funcname, wrap)
     return origfn
 
-def _disabledpaths():
-    '''find paths of disabled extensions. returns a dict of {name: path}'''
+def _disabledpaths(strip_init=False):
+    '''find paths of disabled extensions. returns a dict of {name: path}
+    removes /__init__.py from packages if strip_init is True'''
     import hgext
     extpath = os.path.dirname(os.path.abspath(hgext.__file__))
     try: # might not be a filesystem path
@@ -150,6 +151,8 @@
             path = os.path.join(extpath, e, '__init__.py')
             if not os.path.exists(path):
                 continue
+            if strip_init:
+                path = os.path.dirname(path)
         if name in exts or name in _order or name == '__init__':
             continue
         exts[name] = path
@@ -191,6 +194,53 @@
 
     return exts, maxlength
 
+def disabledext(name):
+    '''find a specific disabled extension from hgext. returns desc'''
+    paths = _disabledpaths()
+    if name in paths:
+        return _disabledhelp(paths[name])
+
+def disabledcmd(cmd, strict=False):
+    '''import disabled extensions until cmd is found.
+    returns (cmdname, extname, doc)'''
+
+    paths = _disabledpaths(strip_init=True)
+    if not paths:
+        raise error.UnknownCommand(cmd)
+
+    def findcmd(cmd, name, path):
+        try:
+            mod = loadpath(path, 'hgext.%s' % name)
+        except Exception:
+            return
+        try:
+            aliases, entry = cmdutil.findcmd(cmd,
+                getattr(mod, 'cmdtable', {}), strict)
+        except (error.AmbiguousCommand, error.UnknownCommand):
+            return
+        for c in aliases:
+            if c.startswith(cmd):
+                cmd = c
+                break
+        else:
+            cmd = aliases[0]
+        return (cmd, name, mod)
+
+    # first, search for an extension with the same name as the command
+    path = paths.pop(cmd, None)
+    if path:
+        ext = findcmd(cmd, cmd, path)
+        if ext:
+            return ext
+
+    # otherwise, interrogate each extension until there's a match
+    for name, path in paths.iteritems():
+        ext = findcmd(cmd, name, path)
+        if ext:
+            return ext
+
+    raise error.UnknownCommand(cmd)
+
 def enabled():
     '''return a dict of {name: desc} of extensions, and the max name length'''
     exts = {}