diff --git a/mercurial/extensions.py b/mercurial/extensions.py --- a/mercurial/extensions.py +++ b/mercurial/extensions.py @@ -118,6 +118,20 @@ def _reportimporterror(ui, err, failed, if ui.debugflag: ui.traceback() +# attributes set by registrar.command +_cmdfuncattrs = ('norepo', 'optionalrepo', 'inferrepo') + +def _validatecmdtable(cmdtable): + """Check if extension commands have required attributes""" + for c, e in cmdtable.iteritems(): + f = e[0] + missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)] + if not missing: + continue + raise error.ProgrammingError( + 'missing attributes: %s' % ', '.join(missing), + hint="use @command decorator to register '%s'" % c) + def load(ui, name, path): if name.startswith('hgext.') or name.startswith('hgext/'): shortname = name[6:] @@ -139,6 +153,7 @@ def load(ui, name, path): ui.warn(_('(third party extension %s requires version %s or newer ' 'of Mercurial; disabling)\n') % (shortname, minver)) return + _validatecmdtable(getattr(mod, 'cmdtable', {})) _extensions[shortname] = mod _order.append(shortname) diff --git a/tests/test-extension.t b/tests/test-extension.t --- a/tests/test-extension.t +++ b/tests/test-extension.t @@ -1534,6 +1534,40 @@ disabling in command line overlays with $ cd .. +Prohibit registration of commands that don't use @command (issue5137) + + $ hg init deprecated + $ cd deprecated + + $ cat < deprecatedcmd.py + > def deprecatedcmd(repo, ui): + > pass + > cmdtable = { + > 'deprecatedcmd': (deprecatedcmd, [], ''), + > } + > EOF + $ cat < .hg/hgrc + > [extensions] + > deprecatedcmd = `pwd`/deprecatedcmd.py + > mq = ! + > hgext.mq = ! + > hgext/mq = ! + > EOF + + $ hg deprecatedcmd > /dev/null + *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo + *** (use @command decorator to register 'deprecatedcmd') + hg: unknown command 'deprecatedcmd' + [255] + + the extension shouldn't be loaded at all so the mq works: + + $ hg qseries --config extensions.mq= > /dev/null + *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo + *** (use @command decorator to register 'deprecatedcmd') + + $ cd .. + Test synopsis and docstring extending $ hg init exthelp