mercurial/policy.py
changeset 42451 810f66b468cd
parent 42343 d8e55c0c642c
child 43075 57875cf423c9
--- a/mercurial/policy.py	Thu Jun 13 23:28:31 2019 +0300
+++ b/mercurial/policy.py	Wed May 29 13:27:56 2019 +0200
@@ -13,6 +13,9 @@
 # Rules for how modules can be loaded. Values are:
 #
 #    c - require C extensions
+#    rust+c - require Rust and C extensions
+#    rust+c-allow - allow Rust and C extensions with fallback to pure Python
+#                   for each
 #    allow - allow pure Python implementation when C loading fails
 #    cffi - required cffi versions (implemented within pure module)
 #    cffi-allow - allow pure Python implementation if cffi version is missing
@@ -29,6 +32,9 @@
     b'cffi': (r'cffi', None),
     b'cffi-allow': (r'cffi', r'pure'),
     b'py': (None, r'pure'),
+    # For now, rust policies impact importrust only
+    b'rust+c': (r'cext', None),
+    b'rust+c-allow': (r'cext', r'pure'),
 }
 
 try:
@@ -107,3 +113,34 @@
                 raise
     pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
     return _importfrom(pn, mn)
+
+def _isrustpermissive():
+    """Assuming the policy is a Rust one, tell if it's permissive."""
+    return policy.endswith(b'-allow')
+
+def importrust(modname, member=None, default=None):
+    """Import Rust module according to policy and availability.
+
+    If policy isn't a Rust one, this returns `default`.
+
+    If either the module or its member is not available, this returns `default`
+    if policy is permissive and raises `ImportError` if not.
+    """
+    if not policy.startswith(b'rust'):
+        return default
+
+    try:
+        mod = _importfrom(r'rustext', modname)
+    except ImportError:
+        if _isrustpermissive():
+            return default
+        raise
+    if member is None:
+        return mod
+
+    try:
+        return getattr(mod, member)
+    except AttributeError:
+        if _isrustpermissive():
+            return default
+        raise ImportError(r"Cannot import name %s" % member)