***SPAM*** [PATCH 2 of 2] dispatch: provide help for disabled extensions and commands
Brodie Rao
dackze at gmail.com
Fri Jan 1 19:35:51 CST 2010
# HG changeset patch
# User Brodie Rao <me+hg at dackz.net>
# Date 1262392257 18000
# Node ID ce028f4fb4652458edfc1f72979c7d0eff9093e4
# Parent 5860c37448413fa927468923576f285ac9e3dcbe
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.
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1446,7 +1446,7 @@ def heads(ui, repo, *branchrevs, **opts)
displayer.show(repo[n])
displayer.close()
-def help_(ui, name=None, with_version=False):
+def help_(ui, name=None, with_version=False, unknowncmd=False):
"""show help for a given topic or a help overview
With no arguments, print a list of commands with short help messages.
@@ -1479,7 +1479,7 @@ def help_(ui, name=None, with_version=Fa
ui.write('\n')
try:
- aliases, entry = cmdutil.findcmd(name, table, False)
+ aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
except error.AmbiguousCommand, inst:
# py3k fix: except vars can't be used outside the scope of the
# except block, nor can be used inside a lambda. python issue4617
@@ -1490,7 +1490,8 @@ def help_(ui, name=None, with_version=Fa
# check if it's an invalid alias and display its error if it is
if getattr(entry[0], 'badalias', False):
- entry[0](ui)
+ if not unknowncmd:
+ entry[0](ui)
return
# synopsis
@@ -1581,10 +1582,13 @@ def help_(ui, name=None, with_version=Fa
def helpext(name):
try:
mod = extensions.find(name)
+ doc = gettext(mod.__doc__) or _('no help text available')
except KeyError:
- raise error.UnknownCommand(name)
-
- doc = gettext(mod.__doc__) or _('no help text available')
+ mod = None
+ doc = extensions.disabledext(name)
+ if not doc:
+ raise error.UnknownCommand(name)
+
if '\n' not in doc:
head, tail = doc, ""
else:
@@ -1594,17 +1598,36 @@ def help_(ui, name=None, with_version=Fa
ui.write(minirst.format(tail, textwidth))
ui.status('\n\n')
- try:
- ct = mod.cmdtable
- except AttributeError:
- ct = {}
-
- modcmds = set([c.split('|', 1)[0] for c in ct])
- helplist(_('list of commands:\n\n'), modcmds.__contains__)
+ if mod:
+ try:
+ ct = mod.cmdtable
+ except AttributeError:
+ ct = {}
+ modcmds = set([c.split('|', 1)[0] for c in ct])
+ helplist(_('list of commands:\n\n'), modcmds.__contains__)
+ else:
+ ui.write(_('use "hg help extensions" for information on enabling '
+ 'extensions\n'))
+
+ def helpextcmd(name):
+ cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
+ doc = gettext(mod.__doc__).splitlines()[0]
+
+ msg = help.listexts(_("'%s' is provided by the following "
+ "extension:") % cmd, {ext: doc}, len(ext),
+ indent=4)
+ ui.write(minirst.format(msg, textwidth))
+ ui.write('\n\n')
+ ui.write(_('use "hg help extensions" for information on enabling '
+ 'extensions\n'))
if name and name != 'shortlist':
i = None
- for f in (helptopic, helpcmd, helpext):
+ if unknowncmd:
+ queries = (helptopic, helpcmd, helpextcmd)
+ else:
+ queries = (helptopic, helpcmd, helpext, helpextcmd)
+ for f in queries:
try:
f(name)
i = None
diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -92,7 +92,12 @@ def _runcatch(ui, args):
ui.warn(_("killed!\n"))
except error.UnknownCommand, inst:
ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
- commands.help_(ui, 'shortlist')
+ try:
+ # check if the command is in a disabled extension
+ # (but don't check for extensions themselves)
+ commands.help_(ui, inst.args[0], unknowncmd=True)
+ except error.UnknownCommand:
+ commands.help_(ui, 'shortlist')
except util.Abort, inst:
ui.warn(_("abort: %s\n") % inst)
except ImportError, inst:
@@ -217,6 +222,11 @@ class cmdalias(object):
def fn(ui, *args):
ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
% (self.name, cmd))
+ try:
+ # check if the command is in a disabled extension
+ commands.help_(ui, cmd, unknowncmd=True)
+ except error.UnknownCommand:
+ pass
return 1
self.fn = fn
self.badalias = True
diff --git a/mercurial/extensions.py b/mercurial/extensions.py
--- a/mercurial/extensions.py
+++ b/mercurial/extensions.py
@@ -6,7 +6,7 @@
# GNU General Public License version 2, incorporated herein by reference.
import imp, os
-import util, cmdutil, help
+import util, cmdutil, help, error
from i18n import _, gettext
_extensions = {}
@@ -131,8 +131,9 @@ def wrapfunction(container, funcname, wr
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 @@ def _disabledpaths():
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,50 @@ def disabled():
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):
+ mod = loadpath(path, 'hgext.%s' % name)
+ 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 = {}
diff --git a/mercurial/help.py b/mercurial/help.py
--- a/mercurial/help.py
+++ b/mercurial/help.py
@@ -40,13 +40,14 @@ def moduledoc(file):
return ''.join(result)
-def listexts(header, exts, maxlength):
+def listexts(header, exts, maxlength, indent=1):
'''return a text listing of the given extensions'''
if not exts:
return ''
result = '\n%s\n\n' % header
for name, desc in sorted(exts.iteritems()):
- result += ' %-*s %s\n' % (maxlength + 2, ':%s:' % name, desc)
+ result += '%s%-*s %s\n' % (' ' * indent, maxlength + 2,
+ ':%s:' % name, desc)
return result
def extshelp():
diff --git a/tests/test-extension b/tests/test-extension
--- a/tests/test-extension
+++ b/tests/test-extension
@@ -153,3 +153,13 @@ echo "hgext/mq=" >> $HGRCPATH
echo % show extensions
hg debugextensions
+
+echo '% disabled extension commands'
+HGRCPATH=
+hg help inserve
+hg qdel
+hg churn
+echo '% disabled extensions'
+hg help churn
+hg help inotify
+exit 0
diff --git a/tests/test-extension.out b/tests/test-extension.out
--- a/tests/test-extension.out
+++ b/tests/test-extension.out
@@ -96,3 +96,28 @@ global options:
% show extensions
debugissue811
mq
+% disabled extension commands
+'inserve' is provided by the following extension:
+
+ inotify accelerate status report using Linux's inotify service
+
+use "hg help extensions" for information on enabling extensions
+hg: unknown command 'qdel'
+'qdelete' is provided by the following extension:
+
+ mq manage a stack of patches
+
+use "hg help extensions" for information on enabling extensions
+hg: unknown command 'churn'
+'churn' is provided by the following extension:
+
+ churn command to display statistics about repository history
+
+use "hg help extensions" for information on enabling extensions
+% disabled extensions
+churn extension - command to display statistics about repository history
+
+use "hg help extensions" for information on enabling extensions
+inotify extension - accelerate status report using Linux's inotify service
+
+use "hg help extensions" for information on enabling extensions
More information about the Mercurial-devel
mailing list