changeset 51837:bcb825bf0c5e

manifest: add a read_delta_new_entries method This new method have a well defined semantic and can be adjusted by narrow as it needs.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 06 Aug 2024 02:12:08 +0200
parents 9844bab33aee
children e4954fd3d1c3
files mercurial/interfaces/repository.py mercurial/manifest.py
diffstat 2 files changed, 54 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/interfaces/repository.py	Thu Aug 01 13:15:54 2024 +0200
+++ b/mercurial/interfaces/repository.py	Tue Aug 06 02:12:08 2024 +0200
@@ -1224,6 +1224,21 @@
 
         The returned object conforms to the ``imanifestdict`` interface."""
 
+    def read_delta_new_entries(*, shallow=False):
+        """Return a manifest containing just the entries that might be new to
+        the repository.
+
+        This is often equivalent to a diff against both parents, but without
+        garantee. For performance reason, It might contains more files in some cases.
+
+        If `shallow` is True, this will read the delta for this directory,
+        without recursively reading subdirectory manifests. Instead, any
+        subdirectory entry will be reported as it appears in the manifest, i.e.
+        the subdirectory will be reported among files and distinguished only by
+        its 't' flag. This only apply if the underlying manifest support it.
+
+        The returned object conforms to the ``imanifestdict`` interface."""
+
     def readfast(shallow=False):
         """Calls either ``read()`` or ``readdelta()``.
 
@@ -1477,6 +1492,10 @@
         """nodeconstants used by the current repository."""
     )
 
+    narrowed = interfaceutil.Attribute(
+        """True, is the manifest is narrowed by a matcher"""
+    )
+
     def __getitem__(node):
         """Obtain a manifest instance for a given binary node.
 
--- a/mercurial/manifest.py	Thu Aug 01 13:15:54 2024 +0200
+++ b/mercurial/manifest.py	Tue Aug 06 02:12:08 2024 +0200
@@ -2090,6 +2090,10 @@
         """
         return self.get(b'', node)
 
+    @property
+    def narrowed(self):
+        return not (self._narrowmatch is None or self._narrowmatch.always())
+
     def get(
         self, tree: bytes, node: bytes, verify: bool = True
     ) -> AnyManifestCtx:
@@ -2317,6 +2321,20 @@
                     md.set(f, new_node, new_flag)
             return md
 
+    def read_delta_new_entries(self, *, shallow=False) -> ManifestDict:
+        """see `interface.imanifestrevisionbase` documentations"""
+        # If we are using narrow, returning a delta against an arbitrary
+        # changeset might return file outside the narrowspec. This can create
+        # issue when running validation server side with strict security as
+        # push from low priviledge usage might be seen as adding new revision
+        # for files they cannot touch. So we are strict if narrow is involved.
+        if self._manifestlog.narrowed:
+            return self.read_delta_parents(shallow=shallow, exact=True)
+        store = self._storage()
+        r = store.rev(self._node)
+        d = mdiff.patchtext(store.revdiff(store.deltaparent(r), r))
+        return manifestdict(store.nodeconstants.nodelen, d)
+
     def find(self, key: bytes) -> Tuple[bytes, bytes]:
         return self.read().find(key)
 
@@ -2576,6 +2594,23 @@
                         md.set(f, new_node, new_flag)
                 return md
 
+    def read_delta_new_entries(
+        self, *, shallow: bool = False
+    ) -> AnyManifestDict:
+        """see `interface.imanifestrevisionbase` documentations"""
+        # If we are using narrow, returning a delta against an arbitrary
+        # changeset might return file outside the narrowspec. This can create
+        # issue when running validation server side with strict security as
+        # push from low priviledge usage might be seen as adding new revision
+        # for files they cannot touch. So we are strict if narrow is involved.
+        if self._manifestlog.narrowed:
+            return self.read_delta_parents(shallow=shallow, exact=True)
+        # delegate to existing another existing method for simplicity
+        store = self._storage()
+        r = store.rev(self._node)
+        bases = (store.deltaparent(r),)
+        return self.read_any_fast_delta(bases, shallow=shallow)[1]
+
     def readfast(self, shallow=False) -> AnyManifestDict:
         """Calls either readdelta or read, based on which would be less work.
         readdelta is called if the delta is against the p1, and therefore can be