context: add ctx.files{modified,added,removed}() methods
authorMartin von Zweigbergk <martinvonz@google.com>
Thu, 18 Apr 2019 13:34:20 -0700
changeset 42374 65fa61ca20af
parent 42373 f3d06d37e194
child 42375 7a64ad3f325d
context: add ctx.files{modified,added,removed}() methods Changeset-centric copy tracing is currently very slow because it often reads manifests. One place it needs the manifest is in _chain(), where it removes a copy X->Y if Y has subsequently gotten removed. I want to speed that up by keeping track directly in the changeset of which files are removed in the changeset. These methods will be similar to ctx.p[12]copies() in that way: they will either read from the changeset or calculate the information from the manifests otherwise. Note that these are different from ctx.{modified,added,removed}() on merge commits. Those functions always compare to p1, but the new ones compare to both parents. filesadded() means "file does not exist in either parent but exists now", filesremoved() means "file existed in either parent but does not exist now", and filesmodified() means "file existed in either parent and still exists". The set of files in ctx.files() is the union of the files from the three new functions (and the three new ones are all disjoint sets). Also note that uncommitted merges are weird as usual. The invariant mentioned above still holds, but the functions compare to p1 (and are thus identical to the existing methods). Differential Revision: https://phab.mercurial-scm.org/D6367
mercurial/context.py
--- a/mercurial/context.py	Thu May 09 15:09:07 2019 -0700
+++ b/mercurial/context.py	Thu Apr 18 13:34:20 2019 -0700
@@ -463,6 +463,24 @@
         return self._changeset.date
     def files(self):
         return self._changeset.files
+    def filesmodified(self):
+        modified = set(self.files())
+        modified.difference_update(self.filesadded())
+        modified.difference_update(self.filesremoved())
+        return sorted(modified)
+    def filesadded(self):
+        added = []
+        for f in self.files():
+            if not any(f in p for p in self.parents()):
+                added.append(f)
+        return added
+    def filesremoved(self):
+        removed = []
+        for f in self.files():
+            if f not in self:
+                removed.append(f)
+        return removed
+
     @propertycache
     def _copies(self):
         source = self._repo.ui.config('experimental', 'copies.read-from')
@@ -1170,6 +1188,10 @@
         return self._status.removed
     def deleted(self):
         return self._status.deleted
+    filesmodified = modified
+    filesadded = added
+    filesremoved = removed
+
     def branch(self):
         return encoding.tolocal(self._extra['branch'])
     def closesbranch(self):