Patchwork D8265: git: key off `git` in .hg/requirements rather than separate file

login
register
mail settings
Submitter phabricator
Date March 10, 2020, 4:59 p.m.
Message ID <ebd10197e2e22a0dbc1a21c20740ab65@localhost.localdomain>
Download mbox | patch
Permalink /patch/45666/
State Not Applicable
Headers show

Comments

phabricator - March 10, 2020, 4:59 p.m.
durin42 updated this revision to Diff 20667.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8265?vs=20666&id=20667

BRANCH
  default

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

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

AFFECTED FILES
  hgext/git/__init__.py
  hgext/git/dirstate.py
  tests/test-git-interop.t

CHANGE DETAILS




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

Patch

diff --git a/tests/test-git-interop.t b/tests/test-git-interop.t
--- a/tests/test-git-interop.t
+++ b/tests/test-git-interop.t
@@ -1,13 +1,12 @@ 
 #require pygit2
 
 Setup:
-  > GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
+  $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
   > GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
   > GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
   > GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
   > GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
   > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
-
   > count=10
   > gitcommit() {
   >    GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000";
@@ -16,7 +15,28 @@ 
   >    count=`expr $count + 1`
   >  }
 
-  > echo "[extensions]" >> $HGRCPATH
+
+Test auto-loading extension works:
+  $ mkdir nogit
+  $ cd nogit
+  $ mkdir .hg
+  $ echo git >> .hg/requires
+  $ hg status
+  abort: repository specified git format in .hg/requires but has no .git directory
+  [255]
+  $ git init
+  Initialized empty Git repository in $TESTTMP/nogit/.git/
+This status invocation shows some hg gunk because we didn't use
+`hg init --git`, which fixes up .git/info/exclude for us.
+  $ hg status
+  ? .hg/cache/git-commits.sqlite
+  ? .hg/cache/git-commits.sqlite-shm
+  ? .hg/cache/git-commits.sqlite-wal
+  ? .hg/requires
+  $ cd ..
+
+Now globally enable extension for the rest of the test:
+  $ echo "[extensions]" >> $HGRCPATH
   > echo "git=" >> $HGRCPATH
 
 Make a new repo with git:
diff --git a/hgext/git/dirstate.py b/hgext/git/dirstate.py
--- a/hgext/git/dirstate.py
+++ b/hgext/git/dirstate.py
@@ -76,7 +76,12 @@ 
         self._plchangecallbacks = {}
 
     def p1(self):
-        return self.git.head.peel().id.raw
+        try:
+            return self.git.head.peel().id.raw
+        except pygit2.GitError:
+            # Typically happens when peeling HEAD fails, as in an
+            # empty repository.
+            return nodemod.nullid
 
     def p2(self):
         # TODO: MERGE_HEAD? something like that, right?
diff --git a/hgext/git/__init__.py b/hgext/git/__init__.py
--- a/hgext/git/__init__.py
+++ b/hgext/git/__init__.py
@@ -86,19 +86,29 @@ 
 
 
 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'
+    reqsf = os.path.join(storebasepath, b'requires')
+    reqs = set()
+    if os.path.exists(reqsf):
+        with open(reqsf, 'rb') as f:
+            reqs = {l.strip() for l in f}
+    if b'git' in reqs:
+        if not os.path.exists(os.path.join(storebasepath, b'..', b'.git')):
+            raise error.Abort(
+                _(
+                    b'repository specified git format in '
+                    b'.hg/requires but has no .git directory'
+                )
             )
-        )
+        # 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')):
         return gitstore(storebasepath, vfstype)
     return orig(requirements, storebasepath, vfstype)
 
@@ -128,9 +138,7 @@ 
             os.path.join(path, b'.git', b'info', b'exclude'), 'ab'
         ) as exclude:
             exclude.write(b'\n.hg\n')
-    with open(os.path.join(dothg, b'this-is-git'), 'wb') as f:
-        pass
-    with open(os.path.join(dothg, b'requirements'), 'wb') as f:
+    with open(os.path.join(dothg, b'requires'), 'wb') as f:
         f.write(b'git\n')
 
 
@@ -256,6 +264,11 @@ 
     return repo
 
 
+def _featuresetup(ui, supported):
+    # don't die on seeing a repo with the git requirement
+    supported |= {b'git'}
+
+
 def extsetup(ui):
     extensions.wrapfunction(localrepo, b'makestore', _makestore)
     extensions.wrapfunction(localrepo, b'makefilestorage', _makefilestorage)
@@ -264,3 +277,4 @@ 
     entry[1].extend(
         [(b'', b'git', None, b'setup up a git repository instead of hg')]
     )
+    localrepo.featuresetupfuncs.add(_featuresetup)