[Request] [++- ] D8567: mergestate: implement trivial in-memory mergestate

durin42 (Augie Fackler) phabricator at mercurial-scm.org
Mon May 18 22:10:53 UTC 2020


durin42 created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  This is the dumbest possible "mergestate" implementation: it doesn't actually
  handle conflict storage in the slightest, but for the current in-memory merge
  cases it works great, and prevents us from accidentally touching .hg/merge
  while doing non-wdir operations.
  
  NOT DONE: this breaks tests in future changes in the series, currently getting
  stuck on the "premerge()" method in the mergestate object.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  mercurial/mergestate.py

CHANGE DETAILS

diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -85,7 +85,40 @@
 }
 
 
-class mergestate(object):
+class _basemergestate(object):
+    def __init__(self, repo):
+        self._repo = repo
+        self._readmergedriver = None
+
+    @util.propertycache
+    def mergedriver(self):
+        # protect against the following:
+        # - A configures a malicious merge driver in their hgrc, then
+        #   pauses the merge
+        # - A edits their hgrc to remove references to the merge driver
+        # - A gives a copy of their entire repo, including .hg, to B
+        # - B inspects .hgrc and finds it to be clean
+        # - B then continues the merge and the malicious merge driver
+        #  gets invoked
+        configmergedriver = self._repo.ui.config(
+            b'experimental', b'mergedriver'
+        )
+        if (
+            self._readmergedriver is not None
+            and self._readmergedriver != configmergedriver
+        ):
+            raise error.ConfigError(
+                _(b"merge driver changed since merge started"),
+                hint=_(b"revert merge driver change or abort merge"),
+            )
+
+        return configmergedriver
+
+    def reset(self, node=None, other=None, labels=None):
+        self._readmergedriver = None
+
+
+class mergestate(_basemergestate):
     '''track 3-way merge state of individual files
 
     The merge state is stored on disk when needed. Two files are used: one with
@@ -154,11 +187,12 @@
         """Initialize the merge state.
 
         Do not use this directly! Instead call read() or clean()."""
-        self._repo = repo
+        super(mergestate, self).__init__(repo)
         self._dirty = False
         self._labels = None
 
     def reset(self, node=None, other=None, labels=None):
+        super(mergestate, self).reset(node=node, other=other, labels=labels)
         self._state = {}
         self._stateextras = {}
         self._local = None
@@ -170,7 +204,6 @@
         if node:
             self._local = node
             self._other = other
-        self._readmergedriver = None
         if self.mergedriver:
             self._mdstate = MERGE_DRIVER_STATE_SUCCESS
         else:
@@ -355,30 +388,6 @@
         return records
 
     @util.propertycache
-    def mergedriver(self):
-        # protect against the following:
-        # - A configures a malicious merge driver in their hgrc, then
-        #   pauses the merge
-        # - A edits their hgrc to remove references to the merge driver
-        # - A gives a copy of their entire repo, including .hg, to B
-        # - B inspects .hgrc and finds it to be clean
-        # - B then continues the merge and the malicious merge driver
-        #  gets invoked
-        configmergedriver = self._repo.ui.config(
-            b'experimental', b'mergedriver'
-        )
-        if (
-            self._readmergedriver is not None
-            and self._readmergedriver != configmergedriver
-        ):
-            raise error.ConfigError(
-                _(b"merge driver changed since merge started"),
-                hint=_(b"revert merge driver change or abort merge"),
-            )
-
-        return configmergedriver
-
-    @util.propertycache
     def local(self):
         if self._local is None:
             msg = b"local accessed but self._local isn't set"
@@ -857,3 +866,35 @@
             repo.dirstate.copy(f0, f)
         else:
             repo.dirstate.normal(f)
+
+
+class memmergestate(_basemergestate):
+    def __init__(self, repo):
+        super(memmergestate, self).__init__(repo)
+        self.reset()
+
+    def add(self, fcl, fco, fca, fd):
+        """add a new (potentially?) conflicting file to the merge state"""
+        self._conflicts.add(fcl.path())
+
+    # Since memmergestate isn't mutable yet, these are all trivial
+    # implementations used by the "happy path" in merge code.
+    def reset(self, node=None, other=None, labels=None):
+        super(memmergestate, self).reset(node=node, other=other, labels=labels)
+        self._conflicts = set()
+
+    def commit(self):
+        if self._conflicts:
+            error.InMemoryMergeConflictsError(
+                'cannot commit memmergestate with conflicts, have %d conflicts'
+                % self.unresolvedcount()
+            )
+
+    def counts(self):
+        return 0, 0, 0
+
+    def unresolvedcount(self):
+        return len(self._conflicts)
+
+    def actions(self):
+        return {}



To: durin42, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mercurial-scm.org/pipermail/mercurial-patches/attachments/20200518/6a7d5444/attachment-0001.html>


More information about the Mercurial-patches mailing list