[PATCH 3 of 3 V3] memctx: allow the memlightctx thats reusing the manifest node

Augie Fackler raf at durin42.com
Mon Nov 21 18:26:16 EST 2016


On Mon, Nov 21, 2016 at 08:13:32AM -0800, Mateusz Kwapich wrote:
> # HG changeset patch
> # User Mateusz Kwapich <mitrandir at fb.com>
> # Date 1479744581 28800
> #      Mon Nov 21 08:09:41 2016 -0800
> # Node ID 4af70f21264ac8e52d9b218080bbc96ee5505606
> # Parent  4a0824bead3ba5980bd8528937fba5f7bb31ba9f
> memctx: allow the memlightctx thats reusing the manifest node
>
> When we have a lot of files writing a new manifest revision can be expensive.
> This commit adds a possibility for memctx to reuse a manifest from a different
> commit. This can be beneficial for commands that are creating metadata changes
> without any actual files changed like "hg metaedit" in evolve extension.
>
> I will send the change for evolve that leverages this once this is accepted.
>
> diff --git a/mercurial/context.py b/mercurial/context.py
> --- a/mercurial/context.py
> +++ b/mercurial/context.py
> @@ -1975,3 +1975,101 @@ class memfilectx(committablefilectx):
>      def write(self, data, flags):
>          """wraps repo.wwrite"""
>          self._data = data
> +
> +class memlightctx(committablectx):

Could this instead be called "metadataonlyctx"? No need to do a
resend, if you're happy with my bikeshed color I can fix it in flight.

Also, could histedit be updated to use this for 'mess' actions
perhaps? Probably not easy, but if it is I'd love to see an in-tree
client of this class. Can you take a look?

> +    """Like memctx but it's reusing the manifest of different commit.
> +    Intended to be used by lightweight operations that are creating
> +    metadata-only changes.
> +
> +    Revision information is supplied at initialization time.  'repo' is the
> +    current localrepo, 'ctx' is original revision which manifest we're reuisng
> +    'parents' is a sequence of two parent revisions identifiers (pass None for
> +    every missing parent), 'text' is the commit.
> +
> +    user receives the committer name and defaults to current repository
> +    username, date is the commit date in any format supported by
> +    util.parsedate() and defaults to current date, extra is a dictionary of
> +    metadata or is left empty.
> +    """
> +    def __new__(cls, repo, path, *args, **kwargs):
> +        return super(memlightctx, cls).__new__(cls, repo)
> +
> +    def __init__(self, repo, originalctx, parents, text, user=None, date=None,
> +                 extra=None, editor=False):
> +        super(memlightctx, self).__init__(repo, text, user, date, extra)
> +        self._rev = None
> +        self._node = None
> +        self._originalctx = originalctx
> +        self._manifestnode = originalctx.manifestnode()
> +        parents = [(p or nullid) for p in parents]
> +        p1, p2 = self._parents = [changectx(self._repo, p) for p in parents]
> +
> +        # sanity check to ensure that the reused manifest parents are
> +        # manifests of our commit parents
> +        mp1, mp2 = self.manifestctx().parents
> +        if p1 != nullid and p1.manifestctx().node() != mp1:
> +            raise RuntimeError('can\'t reuse the manifest: '
> +                               'its p1 doesn\'t match the new ctx p1')
> +        if p2 != nullid and p2.manifestctx().node() != mp2:
> +            raise RuntimeError('can\'t reuse the manifest: '
> +                               'its p2 doesn\'t match the new ctx p2')
> +
> +        self._files = originalctx.files()
> +        self.substate = {}
> +
> +        if extra:
> +            self._extra = extra.copy()
> +        else:
> +            self._extra = {}
> +
> +        if self._extra.get('branch', '') == '':
> +            self._extra['branch'] = 'default'
> +
> +        if editor:
> +            self._text = editor(self._repo, self, [])
> +            self._repo.savecommitmessage(self._text)
> +
> +    def manifestnode(self):
> +        return self._manifestnode
> +
> +    @propertycache
> +    def _manifestctx(self):
> +        return self._repo.manifestlog[self._manifestnode]
> +
> +    def filectx(self, path, filelog=None):
> +        return self._originalctx.filectx(path, filelog=filelog)
> +
> +    def commit(self):
> +        """commit context to the repo"""
> +        return self._repo.commitctx(self)
> +
> +    @property
> +    def _manifest(self):
> +        return self._originalctx.manifest()
> +
> +    @propertycache
> +    def _status(self):
> +        """Calculate exact status from ``files`` specified in the ``origctx``
> +        and parents manifests.
> +        """
> +        man1 = self.p1().manifest()
> +        p2 = self._parents[1]
> +        # "1 < len(self._parents)" can't be used for checking
> +        # existence of the 2nd parent, because "memlightctx._parents" is
> +        # explicitly initialized by the list, of which length is 2.
> +        if p2.node() != nullid:
> +            man2 = p2.manifest()
> +            managing = lambda f: f in man1 or f in man2
> +        else:
> +            managing = lambda f: f in man1
> +
> +        modified, added, removed = [], [], []
> +        for f in self._files:
> +            if not managing(f):
> +                added.append(f)
> +            elif self[f]:
> +                modified.append(f)
> +            else:
> +                removed.append(f)
> +
> +        return scmutil.status(modified, added, removed, [], [], [], [])
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list