Read about our upcoming Code of Conduct on this issue

Commit c07a5cb1 authored by Matt Harbison's avatar Matt Harbison
Browse files

Report the extension and keyring module versions in `hg version -v`

Given the history of compatibility issues between the extension and the keyring
module, as well as compatibility issues between the keyring module and the OS
(or some behavior differences depending on the version of the keyring module),
it's a good idea to have the information available for bug reports.  This is
similar to how the built in git extension reports its `pygit2` dependency.

The mechanism used to figure out the version value was originally how the
keyring module filled in a `__version__` attribute[1], but was subsequently
removed due to overhead.[2]  Since this method is only called on demand instead
of on load, I think the overhead is worth having the info.  Even if a manually
maintained `__version__` attribute is added, this mechanism would be needed to
get the keyring module version.

There appears to be a demandimport issue with py3 prior to 3.8:

    $ ../hg version
    Mercurial Distributed SCM (version 5.7.1+hg562.1afb49f11377local20210415)
    (see https://mercurial-scm.org for more information)

    Copyright (C) 2005-2021 Olivia Mackall and others
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    Traceback (most recent call last):
      File "/mnt/c/Users/Matt/projects/foss/mercurial/mercurial_keyring/mercurial_keyring.py", line 899, in _getversion
        dist = pkg_resources.get_distribution(mod)
      File "/usr/lib/python3.6/importlib/util.py", line 233, in __getattribute__
        self.__spec__.loader.exec_module(self)
      File "<frozen importlib._bootstrap_external>", line 678, in exec_module
      File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
      File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 74, in <module>
        from pkg_resources.extern import packaging
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
      File "<frozen importlib._bootstrap>", line 629, in _load_backward_compatible
      File "/usr/lib/python3.6/importlib/util.py", line 238, in __getattribute__
        raise ValueError(f"module object for {original_name!r} "
    ValueError: module object for 'pkg_resources._vendor.packaging' substituted in sys.modules during a lazy load

I was unable to fix it by comparing the modules loaded with and without
demandimport enabled and adding the differences to the disable list, so
demandimport is temporarily toggled off.  (I've seen this done in TortoiseHg,
which gave me the idea to try it.)  Since this is only called with `version -v`
and to generate bug reports, I think it's fine.

This has been tested in WSL with py2.7.15, py3.6.9, py3.7.5 and py3.8.0, the
TortoiseHg package on Windows (py2.7.18), py3.8.1 in a venv on Windows, and
py3.9.0 on Windows from a Mercurial source based installation.

[1] https://github.com/jaraco/keyring/blob/9066fbf0abee465bbe230e0e76d2598a9f08569c/keyring/__init__.py#L9
[2] https://github.com/jaraco/keyring/blob/main/CHANGES.rst#1100
parent 0be78039cb40
......@@ -891,4 +891,35 @@ def cmd_keyring_clear(ui, repo, path, **opts): # pylint: disable=unused-argumen
user, final_url))
def getversion():
"""Fetches the extension version and keyring module version for
``hg version -v`` and bug reports."""
def _getversion(mod):
try:
dist = pkg_resources.get_distribution(mod)
if dist and getattr(dist, 'version', None):
return dist.version.encode("utf-8")
return b'unknown'
except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict):
return b'unknown'
# Avoid confusing pkg_resources internals
from hgdemandimport import demandimport
demandimport.disable()
try:
import pkg_resources
keyring = _getversion('keyring')
hgkeyring = _getversion('mercurial_keyring')
return b'%s (keyring %s)' % (hgkeyring, keyring)
except (ImportError, ModuleNotFoundError):
# PyOxidizer 0.11.0-pre fails with ModuleNotFoundError. See
# https://github.com/indygreg/PyOxidizer/issues/236#issuecomment-782734290
return b'unknown'
finally:
demandimport.enable()
buglink = b'https://foss.heptapod.net/mercurial/mercurial_keyring/issues'
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment