changing-files: add clean computation of changed files for linear changesets
authorPierre-Yves David <pierre-yves.david@octobus.net>
Tue, 29 Sep 2020 22:46:29 +0200
changeset 45667 0303fc1f43f8
parent 45666 f6811e5bd994
child 45668 47ad23549b81
changing-files: add clean computation of changed files for linear changesets The `files` field is not reliable, so we need to compute things from scratch. We deal with the second simplest case, linear changesets. We diff the current manifest with the parent manifest. This reveal the file added, changed and removed. Differential Revision: https://phab.mercurial-scm.org/D9127
mercurial/metadata.py
--- a/mercurial/metadata.py	Tue Sep 29 22:38:08 2020 +0200
+++ b/mercurial/metadata.py	Tue Sep 29 22:46:29 2020 +0200
@@ -230,6 +230,14 @@
     p2 = ctx.p2()
     if p1.rev() == node.nullrev and p2.rev() == node.nullrev:
         return _process_root(ctx)
+    elif p1.rev() != node.nullrev and p2.rev() == node.nullrev:
+        return _process_linear(p1, ctx)
+    elif p1.rev() == node.nullrev and p2.rev() != node.nullrev:
+        # In the wild, one can encounter changeset where p1 is null but p2 is not
+        return _process_linear(p1, ctx, parent=2)
+    elif p1.rev() == p2.rev():
+        # In the wild, one can encounter such "non-merge"
+        return _process_linear(p1, ctx)
     filescopies = computechangesetcopies(ctx)
     filesadded = computechangesetfilesadded(ctx)
     filesremoved = computechangesetfilesremoved(ctx)
@@ -255,6 +263,44 @@
     return md
 
 
+def _process_linear(parent_ctx, children_ctx, parent=1):
+    """compute the appropriate changed files for a changeset with a single parent
+    """
+    md = ChangingFiles()
+    parent_manifest = parent_ctx.manifest()
+    children_manifest = children_ctx.manifest()
+
+    copies_candidate = []
+
+    for filename, d in parent_manifest.diff(children_manifest).items():
+        if d[1][0] is None:
+            # no filenode for the "new" value, file is absent
+            md.mark_removed(filename)
+        else:
+            copies_candidate.append(filename)
+            if d[0][0] is None:
+                # not filenode for the "old" value file was absent
+                md.mark_added(filename)
+            else:
+                # filenode for both "old" and "new"
+                md.mark_touched(filename)
+
+    if parent == 1:
+        copied = md.mark_copied_from_p1
+    elif parent == 2:
+        copied = md.mark_copied_from_p2
+    else:
+        assert False, "bad parent value %d" % parent
+
+    for filename in copies_candidate:
+        copy_info = children_ctx[filename].renamed()
+        if copy_info:
+            source, srcnode = copy_info
+            copied(source, filename)
+
+    return md
+
+
 def computechangesetfilesadded(ctx):
     """return the list of files added in a changeset
     """