[PATCH 3 of 3] extensions: refuse to load extensions if minimum hg version not met

Yuya Nishihara yuya at tcha.org
Fri Nov 27 07:47:41 CST 2015


On Tue, 24 Nov 2015 15:19:10 -0800, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1448406985 28800
> #      Tue Nov 24 15:16:25 2015 -0800
> # Node ID 7493ec7396d172cdbed8bc3b1aa300b2d2adc4df
> # Parent  ed2e8713d5f11c64bf9d5c9b6a0d802b5d534fbe
> extensions: refuse to load extensions if minimum hg version not met
> 
> As the author of several 3rd party extensions, I frequently see bug
> reports from users attempting to run my extension with an old version
> of Mercurial that I no longer support in my extension. Oftentimes, the
> extension will import just fine. But as soon as we run extsetup(),
> reposetup(), or get into the guts of a wrapped function, we encounter
> an exception and abort. Today, Mercurial will print a message about
> extensions that don't have a "testedwith" declaring explicit
> compatibility with the current version.
> 
> The existing mechanism is a good start. But it isn't as robust as I
> would like. Specifically, Mercurial assumes compatibility by default.
> This means extension authors must perform compatibility checking in
> their extsetup() or we wait and see if we encounter an abort at
> runtime. And, compatibility checking can involve a lot of code and
> lots of error checking. It's a lot of effort for extension authors.
> 
> Oftentimes, extension authors know which versions of Mercurial there
> extension works on and more importantly where it is broken.
> 
> This patch introduces a magic "minimumhgversion" attribute in
> extensions. When found, the extension loading mechanism will compare
> the declared version against the current Mercurial version. If the
> extension explicitly states we require a newer Mercurial version, a
> warning is printed and the extension isn't loaded beyond importing
> the Python module. This causes a graceful failure while alerting
> the user of the compatibility issue.
> 
> I would be receptive to the idea of making the failure more fatal.
> However, care would need to be taken to not criple every hg command.
> e.g. the user may use `hg config` to fix the hgrc and if we aborted
> trying to run that, the user would effectively be locked out of `hg`!
> 
> A potential future improvement to this functionality would be to catch
> ImportError for the extension/module and parse the source code for
> "minimumhgversion = 'XXX'" and do similar checking. This way we could
> give more information about why the extension failed to load.

I think this patch is good start, but I want to see others' opinion.

> diff --git a/mercurial/extensions.py b/mercurial/extensions.py
> --- a/mercurial/extensions.py
> +++ b/mercurial/extensions.py
> @@ -99,8 +99,19 @@ def load(ui, name, path):
>                       % (name, err, name))
>              if ui.debugflag:
>                  ui.traceback()
>              mod = importh(name)
> +
> +    # Before we do anything with the extension, check against minimum stated
> +    # compatibility. This gives extension authors a mechanism to have their
> +    # extensions short circuit when loaded with a known incompatible version
> +    # of Mercurial.
> +    minver = getattr(mod, 'minimumhgversion', None)
> +    if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
> +        ui.warn(_('(third party extension %s requires version %s or newer '
> +                  'of Mercurial; disabling)\n') % (shortname, minver))
> +        return

Nitpick: extension authors might want to specify the 3rd digit because we
sometimes change the internal API in stable releases.


More information about the Mercurial-devel mailing list