Mercurial > hg
changeset 36269:4088e568a411
extensions: reject any unicode strings in tables before loading
This allows us to test hg on Python 3 without disabling third-party
extensions which could pollute cmdtable for example.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 17 Feb 2018 17:24:29 +0900 |
parents | be5a6fe3643a |
children | 2d513ab7ce94 |
files | mercurial/extensions.py tests/test-extension.t |
diffstat | 2 files changed, 26 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/extensions.py Sat Feb 17 18:20:15 2018 +0900 +++ b/mercurial/extensions.py Sat Feb 17 17:24:29 2018 +0900 @@ -122,6 +122,18 @@ if ui.debugflag: ui.traceback() +def _rejectunicode(name, xs): + if isinstance(xs, (list, set, tuple)): + for x in xs: + _rejectunicode(name, x) + elif isinstance(xs, dict): + for k, v in xs.items(): + _rejectunicode(name, k) + _rejectunicode(b'%s.%s' % (name, util.forcebytestr(k)), v) + elif isinstance(xs, type(u'')): + raise error.ProgrammingError(b"unicode %r found in %s" % (xs, name), + hint="use b'' to make it byte string") + # attributes set by registrar.command _cmdfuncattrs = ('norepo', 'optionalrepo', 'inferrepo') @@ -134,19 +146,22 @@ "registrar.command to register '%s'" % c, '4.6') missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)] if not missing: - for option in e[1]: - default = option[2] - if isinstance(default, type(u'')): - raise error.ProgrammingError( - "option '%s.%s' has a unicode default value" - % (c, option[1]), - hint=("change the %s.%s default value to a " - "non-unicode string" % (c, option[1]))) continue raise error.ProgrammingError( 'missing attributes: %s' % ', '.join(missing), hint="use @command decorator to register '%s'" % c) +def _validatetables(ui, mod): + """Sanity check for loadable tables provided by extension module""" + for t in ['cmdtable', 'colortable', 'configtable']: + _rejectunicode(t, getattr(mod, t, {})) + for t in ['filesetpredicate', 'internalmerge', 'revsetpredicate', + 'templatefilter', 'templatefunc', 'templatekeyword']: + o = getattr(mod, t, None) + if o: + _rejectunicode(t, o._table) + _validatecmdtable(ui, getattr(mod, 'cmdtable', {})) + def load(ui, name, path): if name.startswith('hgext.') or name.startswith('hgext/'): shortname = name[6:] @@ -168,7 +183,7 @@ ui.warn(_('(third party extension %s requires version %s or newer ' 'of Mercurial; disabling)\n') % (shortname, minver)) return - _validatecmdtable(ui, getattr(mod, 'cmdtable', {})) + _validatetables(ui, mod) _extensions[shortname] = mod _order.append(shortname)
--- a/tests/test-extension.t Sat Feb 17 18:20:15 2018 +0900 +++ b/tests/test-extension.t Sat Feb 17 17:24:29 2018 +0900 @@ -1707,8 +1707,8 @@ > test_unicode_default_value = $TESTTMP/test_unicode_default_value.py > EOF $ hg -R $TESTTMP/opt-unicode-default dummy - *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: option 'dummy.opt' has a unicode default value - *** (change the dummy.opt default value to a non-unicode string) + *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: unicode u'value' found in cmdtable.dummy + *** (use b'' to make it byte string) hg: unknown command 'dummy' (did you mean summary?) [255]