D6186: changelog: parse copy metadata if available in extras

martinvonz (Martin von Zweigbergk) phabricator at mercurial-scm.org
Fri Apr 5 01:49:09 EDT 2019


martinvonz updated this revision to Diff 14664.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D6186?vs=14634&id=14664

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

AFFECTED FILES
  mercurial/changelog.py
  mercurial/context.py
  mercurial/copies.py
  tests/test-copies-in-changeset.t
  tests/test-copies.t

CHANGE DETAILS

diff --git a/tests/test-copies.t b/tests/test-copies.t
--- a/tests/test-copies.t
+++ b/tests/test-copies.t
@@ -1,4 +1,4 @@
-#testcases filelog compatibility
+#testcases filelog compatibility changeset
 
   $ cat >> $HGRCPATH << EOF
   > [extensions]
@@ -14,6 +14,14 @@
   > EOF
 #endif
 
+#if changeset
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > copies.read-from = changeset-only
+  > copies.write-to = changeset-only
+  > EOF
+#endif
+
   $ REPONUM=0
   $ newrepo() {
   >     cd $TESTTMP
@@ -376,11 +384,13 @@
   o  0 add x on branch 1
      x
   $ hg debugp1copies -r 2
+  x -> z (changeset !)
   $ hg debugp2copies -r 2
-  x -> z
+  x -> z (no-changeset !)
   $ hg debugpathcopies 1 2
+  x -> z (changeset !)
   $ hg debugpathcopies 0 2
-  x -> z
+  x -> z (no-changeset !)
 
 Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent
 of the merge to the merge should include the copy from the other side.
@@ -539,6 +549,9 @@
 
 Grafting revision 4 on top of revision 2, showing that it respect the rename:
 
+TODO: Make this work with copy info in changesets (probably by writing a
+changeset-centric version of copies.mergecopies())
+#if no-changeset
   $ hg up 2 -q
   $ hg graft -r 4 --base 3 --hidden
   grafting 4:af28412ec03c "added d, modified b" (tip)
@@ -554,6 +567,8 @@
       b
      +baba
   
+#endif
+
 Test to make sure that fullcopytracing algorithm don't fail when both the merging csets are dirty
 (a dirty cset is one who is not the descendant of merge base)
 -------------------------------------------------------------------------------------------------
diff --git a/tests/test-copies-in-changeset.t b/tests/test-copies-in-changeset.t
--- a/tests/test-copies-in-changeset.t
+++ b/tests/test-copies-in-changeset.t
@@ -2,9 +2,11 @@
   $ cat >> $HGRCPATH << EOF
   > [experimental]
   > copies.write-to=changeset-only
+  > copies.read-from=changeset-only
   > [alias]
   > changesetcopies = log -r . -T 'files: {files}
   >   {extras % "{ifcontains("copies", key, "{key}: {value}\n")}"}'
+  > showcopies = log -r . -T '{file_copies % "{source} -> {name}\n"}'
   > EOF
 
 Check that copies are recorded correctly
@@ -23,14 +25,25 @@
   p1copies: b\x00a (esc)
   c\x00a (esc)
   d\x00a (esc)
+  $ hg showcopies
+  a -> b
+  a -> c
+  a -> d
+  $ hg showcopies --config experimental.copies.read-from=compatibility
+  a -> b
+  a -> c
+  a -> d
+  $ hg showcopies --config experimental.copies.read-from=filelog-only
 
 Check that renames are recorded correctly
 
   $ hg mv b b2
   $ hg ci -m 'rename b to b2'
   $ hg changesetcopies
   files: b b2
   p1copies: b2\x00b (esc)
+  $ hg showcopies
+  b -> b2
 
 Rename onto existing file. This should get recorded in the changeset files list and in the extras,
 even though there is no filelog entry.
@@ -46,6 +59,8 @@
   $ hg changesetcopies
   files: c
   p1copies: c\x00b2 (esc)
+  $ hg showcopies
+  b2 -> c
   $ hg debugindex c
      rev linkrev nodeid       p1           p2
        0       1 b789fdd96dc2 000000000000 000000000000
@@ -74,6 +89,10 @@
   p1copies: g\x00a (esc)
   i\x00f (esc)
   p2copies: h\x00d (esc)
+  $ hg showcopies
+  a -> g
+  d -> h
+  f -> i
 
 Test writing to both changeset and filelog
 
@@ -88,6 +107,12 @@
   copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
   \x01 (esc)
   a
+  $ hg showcopies
+  a -> j
+  $ hg showcopies --config experimental.copies.read-from=compatibility
+  a -> j
+  $ hg showcopies --config experimental.copies.read-from=filelog-only
+  a -> j
 
 Test writing only to filelog
 
@@ -101,5 +126,10 @@
   copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
   \x01 (esc)
   a
+  $ hg showcopies
+  $ hg showcopies --config experimental.copies.read-from=compatibility
+  a -> k
+  $ hg showcopies --config experimental.copies.read-from=filelog-only
+  a -> k
 
   $ cd ..
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -162,8 +162,8 @@
 
 def usechangesetcentricalgo(repo):
     """Checks if we should use changeset-centric copy algorithms"""
-    return (repo.ui.config('experimental', 'copies.read-from') ==
-            'compatibility')
+    return (repo.ui.config('experimental', 'copies.read-from') in
+            ('changeset-only', 'compatibility'))
 
 def _committedforwardcopies(a, b, match):
     """Like _forwardcopies(), but b.rev() cannot be None (working copy)"""
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -441,6 +441,21 @@
         return self._changeset.files
     @propertycache
     def _copies(self):
+        source = self._repo.ui.config('experimental', 'copies.read-from')
+        p1copies = self._changeset.p1copies
+        p2copies = self._changeset.p2copies
+        # If config says to get copy metadata only from changeset, then return
+        # that, defaulting to {} if there was no copy metadata.
+        # In compatibility mode, we return copy data from the changeset if
+        # it was recorded there, and otherwise we fall back to getting it from
+        # the filelogs (below).
+        if (source == 'changeset-only' or
+            (source == 'compatibility' and p1copies is not None)):
+            return p1copies or {}, p2copies or {}
+
+        # Otherwise (config said to read only from filelog, or we are in
+        # compatiblity mode and there is not data in the changeset), we get
+        # the copy metadata from the filelogs.
         p1copies = {}
         p2copies = {}
         p1 = self.p1()
diff --git a/mercurial/changelog.py b/mercurial/changelog.py
--- a/mercurial/changelog.py
+++ b/mercurial/changelog.py
@@ -87,6 +87,18 @@
     ]
     return "\n".join(items)
 
+def decodecopies(data):
+    try:
+        copies = {}
+        for l in data.split('\n'):
+            k, v = l.split('\0')
+            copies[_string_unescape(k)] = _string_unescape(v)
+        return copies
+    except ValueError:
+        # Perhaps someone had chosen the same key name (e.g. "p1copies") and
+        # used different syntax for the value.
+        return None
+
 def stripdesc(desc):
     """strip trailing whitespace and leading and trailing empty lines"""
     return '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
@@ -286,6 +298,16 @@
         return self._text[off[2] + 1:off[3]].split('\n')
 
     @property
+    def p1copies(self):
+        rawcopies = self.extra.get('p1copies')
+        return rawcopies and decodecopies(rawcopies)
+
+    @property
+    def p2copies(self):
+        rawcopies = self.extra.get('p2copies')
+        return rawcopies and decodecopies(rawcopies)
+
+    @property
     def description(self):
         return encoding.tolocal(self._text[self._offsets[3] + 2:])
 



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


More information about the Mercurial-devel mailing list