git: don't fail import when pygit2 is not install
`test-duplicateoptions.py` was failing on py2 for be because I didn't
have pygit2 installed. It failed because we depend on pygit2 at import
time. This patch makes it so we successfully load the git extension
even if pygit2 doesn't exist -- we just won't be able to use it in
that case.
Differential Revision: https://phab.mercurial-scm.org/D8268
--- a/hgext/git/__init__.py Mon Mar 09 12:53:21 2020 -0700
+++ b/hgext/git/__init__.py Mon Mar 09 11:18:33 2020 -0700
@@ -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
--- a/hgext/git/dirstate.py Mon Mar 09 12:53:21 2020 -0700
+++ b/hgext/git/dirstate.py Mon Mar 09 11:18:33 2020 -0700
@@ -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)
--- a/hgext/git/gitlog.py Mon Mar 09 12:53:21 2020 -0700
+++ b/hgext/git/gitlog.py Mon Mar 09 11:18:33 2020 -0700
@@ -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."""
--- a/hgext/git/gitutil.py Mon Mar 09 12:53:21 2020 -0700
+++ b/hgext/git/gitutil.py Mon Mar 09 11:18:33 2020 -0700
@@ -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.
--- a/hgext/git/index.py Mon Mar 09 12:53:21 2020 -0700
+++ b/hgext/git/index.py Mon Mar 09 11:18:33 2020 -0700
@@ -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
--- a/hgext/git/manifest.py Mon Mar 09 12:53:21 2020 -0700
+++ b/hgext/git/manifest.py Mon Mar 09 11:18:33 2020 -0700
@@ -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.