Patchwork D8268: git: don't fail import when pygit2 is not install

login
register
mail settings
Submitter phabricator
Date March 9, 2020, 10:38 p.m.
Message ID <193839384c711c1dfd68f8054cc3cf5b@localhost.localdomain>
Download mbox | patch
Permalink /patch/45644/
State Not Applicable
Headers show

Comments

phabricator - March 9, 2020, 10:38 p.m.
martinvonz updated this revision to Diff 20646.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8268?vs=20645&id=20646

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8268/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8268

AFFECTED FILES
  hgext/git/__init__.py
  hgext/git/dirstate.py
  hgext/git/gitlog.py
  hgext/git/gitutil.py
  hgext/git/index.py
  hgext/git/manifest.py

CHANGE DETAILS




To: martinvonz, #hg-reviewers
Cc: mharbison72, mercurial-devel

Patch

diff --git a/hgext/git/manifest.py b/hgext/git/manifest.py
--- a/hgext/git/manifest.py
+++ b/hgext/git/manifest.py
@@ -1,7 +1,5 @@ 
 from __future__ import absolute_import
 
-import pygit2
-
 from mercurial import (
     match as matchmod,
     pathutil,
@@ -15,6 +13,9 @@ 
 from . import gitutil
 
 
+pygit2 = gitutil.get_pygit2()
+
+
 @interfaceutil.implementer(repository.imanifestdict)
 class gittreemanifest(object):
     """Expose git trees (and optionally a builder's overlay) as a manifestdict.
diff --git a/hgext/git/index.py b/hgext/git/index.py
--- a/hgext/git/index.py
+++ b/hgext/git/index.py
@@ -4,8 +4,6 @@ 
 import os
 import sqlite3
 
-import pygit2
-
 from mercurial.i18n import _
 
 from mercurial import (
@@ -18,6 +16,8 @@ 
 from . import gitutil
 
 
+pygit2 = gitutil.get_pygit2()
+
 _CURRENT_SCHEMA_VERSION = 1
 _SCHEMA = (
     """
@@ -101,9 +101,13 @@ 
     return db
 
 
-_OUR_ORDER = (
-    pygit2.GIT_SORT_TOPOLOGICAL | pygit2.GIT_SORT_TIME | pygit2.GIT_SORT_REVERSE
-)
+_OUR_ORDER = ()
+if pygit2:
+    _OUR_ORDER = (
+        pygit2.GIT_SORT_TOPOLOGICAL
+        | pygit2.GIT_SORT_TIME
+        | pygit2.GIT_SORT_REVERSE
+    )
 
 _DIFF_FLAGS = 1 << 21  # GIT_DIFF_FORCE_BINARY, which isn't exposed by pygit2
 
diff --git a/hgext/git/gitutil.py b/hgext/git/gitutil.py
--- a/hgext/git/gitutil.py
+++ b/hgext/git/gitutil.py
@@ -5,6 +5,20 @@ 
 
 from mercurial import pycompat
 
+pygit2_module = None
+
+
+def get_pygit2():
+    global pygit2_module
+    if pygit2_module is None:
+        try:
+            import pygit2 as pygit2_module
+
+            pygit2_module.InvalidSpecError
+        except (ImportError, AttributeError):
+            pass
+    return pygit2_module
+
 
 def togitnode(n):
     """Wrapper to convert a Mercurial binary node to a unicode hexlified node.
diff --git a/hgext/git/gitlog.py b/hgext/git/gitlog.py
--- a/hgext/git/gitlog.py
+++ b/hgext/git/gitlog.py
@@ -1,7 +1,5 @@ 
 from __future__ import absolute_import
 
-import pygit2
-
 from mercurial.i18n import _
 
 from mercurial import (
@@ -25,6 +23,8 @@ 
     manifest as gitmanifest,
 )
 
+pygit2 = gitutil.get_pygit2()
+
 
 class baselog(object):  # revlog.revlog):
     """Common implementations between changelog and manifestlog."""
diff --git a/hgext/git/dirstate.py b/hgext/git/dirstate.py
--- a/hgext/git/dirstate.py
+++ b/hgext/git/dirstate.py
@@ -4,8 +4,6 @@ 
 import errno
 import os
 
-import pygit2
-
 from mercurial import (
     error,
     extensions,
@@ -22,6 +20,8 @@ 
 
 from . import gitutil
 
+pygit2 = gitutil.get_pygit2()
+
 
 def readpatternfile(orig, filepath, warn, sourceinfo=False):
     if not (b'info/exclude' in filepath or filepath.endswith(b'.gitignore')):
@@ -46,23 +46,25 @@ 
 extensions.wrapfunction(matchmod, b'readpatternfile', readpatternfile)
 
 
-_STATUS_MAP = {
-    pygit2.GIT_STATUS_CONFLICTED: b'm',
-    pygit2.GIT_STATUS_CURRENT: b'n',
-    pygit2.GIT_STATUS_IGNORED: b'?',
-    pygit2.GIT_STATUS_INDEX_DELETED: b'r',
-    pygit2.GIT_STATUS_INDEX_MODIFIED: b'n',
-    pygit2.GIT_STATUS_INDEX_NEW: b'a',
-    pygit2.GIT_STATUS_INDEX_RENAMED: b'a',
-    pygit2.GIT_STATUS_INDEX_TYPECHANGE: b'n',
-    pygit2.GIT_STATUS_WT_DELETED: b'r',
-    pygit2.GIT_STATUS_WT_MODIFIED: b'n',
-    pygit2.GIT_STATUS_WT_NEW: b'?',
-    pygit2.GIT_STATUS_WT_RENAMED: b'a',
-    pygit2.GIT_STATUS_WT_TYPECHANGE: b'n',
-    pygit2.GIT_STATUS_WT_UNREADABLE: b'?',
-    pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_WT_MODIFIED: 'm',
-}
+_STATUS_MAP = {}
+if pygit2:
+    _STATUS_MAP = {
+        pygit2.GIT_STATUS_CONFLICTED: b'm',
+        pygit2.GIT_STATUS_CURRENT: b'n',
+        pygit2.GIT_STATUS_IGNORED: b'?',
+        pygit2.GIT_STATUS_INDEX_DELETED: b'r',
+        pygit2.GIT_STATUS_INDEX_MODIFIED: b'n',
+        pygit2.GIT_STATUS_INDEX_NEW: b'a',
+        pygit2.GIT_STATUS_INDEX_RENAMED: b'a',
+        pygit2.GIT_STATUS_INDEX_TYPECHANGE: b'n',
+        pygit2.GIT_STATUS_WT_DELETED: b'r',
+        pygit2.GIT_STATUS_WT_MODIFIED: b'n',
+        pygit2.GIT_STATUS_WT_NEW: b'?',
+        pygit2.GIT_STATUS_WT_RENAMED: b'a',
+        pygit2.GIT_STATUS_WT_TYPECHANGE: b'n',
+        pygit2.GIT_STATUS_WT_UNREADABLE: b'?',
+        pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_WT_MODIFIED: 'm',
+    }
 
 
 @interfaceutil.implementer(intdirstate.idirstate)
diff --git a/hgext/git/__init__.py b/hgext/git/__init__.py
--- a/hgext/git/__init__.py
+++ b/hgext/git/__init__.py
@@ -8,8 +8,6 @@ 
 
 import os
 
-import pygit2
-
 from mercurial.i18n import _
 
 from mercurial import (
@@ -29,7 +27,6 @@ 
     index,
 )
 
-
 # TODO: extract an interface for this in core
 class gitstore(object):  # store.basicstore):
     def __init__(self, path, vfstype):
@@ -39,7 +36,7 @@ 
         # above lines should go away in favor of:
         # super(gitstore, self).__init__(path, vfstype)
 
-        self.git = pygit2.Repository(
+        self.git = gitutil.get_pygit2().Repository(
             os.path.normpath(os.path.join(path, b'..', b'.git'))
         )
         self._progress_factory = lambda *args, **kwargs: None
@@ -89,6 +86,16 @@ 
 
 
 def _makestore(orig, requirements, storebasepath, vfstype):
+    # Check for presence of pygit2 only here. The assumption is that we'll
+    # run this code iff we'll later need pygit2.
+    if gitutil.get_pygit2() is None:
+        raise error.Abort(
+            _(
+                b'the git extension requires the Python '
+                b'pygit2 library to be installed'
+            )
+        )
+
     if os.path.exists(
         os.path.join(storebasepath, b'this-is-git')
     ) and os.path.exists(os.path.join(storebasepath, b'..', b'.git')):
@@ -156,7 +163,7 @@ 
             if k in self:
                 return self[k]
             return default
-        except pygit2.InvalidSpecError:
+        except gitutil.get_pygit2().InvalidSpecError:
             return default
 
     @property