comparison mercurial/extensions.py @ 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 646002338365
children 521f6c7e1756
comparison
equal deleted inserted replaced
36268:be5a6fe3643a 36269:4088e568a411
120 ui.debug('could not import %s (%s): trying %s\n' 120 ui.debug('could not import %s (%s): trying %s\n'
121 % (failed, util.forcebytestr(err), next)) 121 % (failed, util.forcebytestr(err), next))
122 if ui.debugflag: 122 if ui.debugflag:
123 ui.traceback() 123 ui.traceback()
124 124
125 def _rejectunicode(name, xs):
126 if isinstance(xs, (list, set, tuple)):
127 for x in xs:
128 _rejectunicode(name, x)
129 elif isinstance(xs, dict):
130 for k, v in xs.items():
131 _rejectunicode(name, k)
132 _rejectunicode(b'%s.%s' % (name, util.forcebytestr(k)), v)
133 elif isinstance(xs, type(u'')):
134 raise error.ProgrammingError(b"unicode %r found in %s" % (xs, name),
135 hint="use b'' to make it byte string")
136
125 # attributes set by registrar.command 137 # attributes set by registrar.command
126 _cmdfuncattrs = ('norepo', 'optionalrepo', 'inferrepo') 138 _cmdfuncattrs = ('norepo', 'optionalrepo', 'inferrepo')
127 139
128 def _validatecmdtable(ui, cmdtable): 140 def _validatecmdtable(ui, cmdtable):
129 """Check if extension commands have required attributes""" 141 """Check if extension commands have required attributes"""
132 if getattr(f, '_deprecatedregistrar', False): 144 if getattr(f, '_deprecatedregistrar', False):
133 ui.deprecwarn("cmdutil.command is deprecated, use " 145 ui.deprecwarn("cmdutil.command is deprecated, use "
134 "registrar.command to register '%s'" % c, '4.6') 146 "registrar.command to register '%s'" % c, '4.6')
135 missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)] 147 missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
136 if not missing: 148 if not missing:
137 for option in e[1]:
138 default = option[2]
139 if isinstance(default, type(u'')):
140 raise error.ProgrammingError(
141 "option '%s.%s' has a unicode default value"
142 % (c, option[1]),
143 hint=("change the %s.%s default value to a "
144 "non-unicode string" % (c, option[1])))
145 continue 149 continue
146 raise error.ProgrammingError( 150 raise error.ProgrammingError(
147 'missing attributes: %s' % ', '.join(missing), 151 'missing attributes: %s' % ', '.join(missing),
148 hint="use @command decorator to register '%s'" % c) 152 hint="use @command decorator to register '%s'" % c)
153
154 def _validatetables(ui, mod):
155 """Sanity check for loadable tables provided by extension module"""
156 for t in ['cmdtable', 'colortable', 'configtable']:
157 _rejectunicode(t, getattr(mod, t, {}))
158 for t in ['filesetpredicate', 'internalmerge', 'revsetpredicate',
159 'templatefilter', 'templatefunc', 'templatekeyword']:
160 o = getattr(mod, t, None)
161 if o:
162 _rejectunicode(t, o._table)
163 _validatecmdtable(ui, getattr(mod, 'cmdtable', {}))
149 164
150 def load(ui, name, path): 165 def load(ui, name, path):
151 if name.startswith('hgext.') or name.startswith('hgext/'): 166 if name.startswith('hgext.') or name.startswith('hgext/'):
152 shortname = name[6:] 167 shortname = name[6:]
153 else: 168 else:
166 minver = getattr(mod, 'minimumhgversion', None) 181 minver = getattr(mod, 'minimumhgversion', None)
167 if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2): 182 if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
168 ui.warn(_('(third party extension %s requires version %s or newer ' 183 ui.warn(_('(third party extension %s requires version %s or newer '
169 'of Mercurial; disabling)\n') % (shortname, minver)) 184 'of Mercurial; disabling)\n') % (shortname, minver))
170 return 185 return
171 _validatecmdtable(ui, getattr(mod, 'cmdtable', {})) 186 _validatetables(ui, mod)
172 187
173 _extensions[shortname] = mod 188 _extensions[shortname] = mod
174 _order.append(shortname) 189 _order.append(shortname)
175 for fn in _aftercallbacks.get(shortname, []): 190 for fn in _aftercallbacks.get(shortname, []):
176 fn(loaded=True) 191 fn(loaded=True)