Mercurial > public > mercurial-scm > hg
comparison mercurial/context.py @ 30567:73ce055b169a
memctx: allow the metadataonlyctx 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.
author | Mateusz Kwapich <mitrandir@fb.com> |
---|---|
date | Mon, 21 Nov 2016 08:09:41 -0800 |
parents | 1070df141718 |
children | 9bf43a72b49d |
comparison
equal
deleted
inserted
replaced
30566:46d2c8b23c33 | 30567:73ce055b169a |
---|---|
1973 del self._changectx[self._path] | 1973 del self._changectx[self._path] |
1974 | 1974 |
1975 def write(self, data, flags): | 1975 def write(self, data, flags): |
1976 """wraps repo.wwrite""" | 1976 """wraps repo.wwrite""" |
1977 self._data = data | 1977 self._data = data |
1978 | |
1979 class metadataonlyctx(committablectx): | |
1980 """Like memctx but it's reusing the manifest of different commit. | |
1981 Intended to be used by lightweight operations that are creating | |
1982 metadata-only changes. | |
1983 | |
1984 Revision information is supplied at initialization time. 'repo' is the | |
1985 current localrepo, 'ctx' is original revision which manifest we're reuisng | |
1986 'parents' is a sequence of two parent revisions identifiers (pass None for | |
1987 every missing parent), 'text' is the commit. | |
1988 | |
1989 user receives the committer name and defaults to current repository | |
1990 username, date is the commit date in any format supported by | |
1991 util.parsedate() and defaults to current date, extra is a dictionary of | |
1992 metadata or is left empty. | |
1993 """ | |
1994 def __new__(cls, repo, path, *args, **kwargs): | |
1995 return super(metadataonlyctx, cls).__new__(cls, repo) | |
1996 | |
1997 def __init__(self, repo, originalctx, parents, text, user=None, date=None, | |
1998 extra=None, editor=False): | |
1999 super(metadataonlyctx, self).__init__(repo, text, user, date, extra) | |
2000 self._rev = None | |
2001 self._node = None | |
2002 self._originalctx = originalctx | |
2003 self._manifestnode = originalctx.manifestnode() | |
2004 parents = [(p or nullid) for p in parents] | |
2005 p1, p2 = self._parents = [changectx(self._repo, p) for p in parents] | |
2006 | |
2007 # sanity check to ensure that the reused manifest parents are | |
2008 # manifests of our commit parents | |
2009 mp1, mp2 = self.manifestctx().parents | |
2010 if p1 != nullid and p1.manifestctx().node() != mp1: | |
2011 raise RuntimeError('can\'t reuse the manifest: ' | |
2012 'its p1 doesn\'t match the new ctx p1') | |
2013 if p2 != nullid and p2.manifestctx().node() != mp2: | |
2014 raise RuntimeError('can\'t reuse the manifest: ' | |
2015 'its p2 doesn\'t match the new ctx p2') | |
2016 | |
2017 self._files = originalctx.files() | |
2018 self.substate = {} | |
2019 | |
2020 if extra: | |
2021 self._extra = extra.copy() | |
2022 else: | |
2023 self._extra = {} | |
2024 | |
2025 if self._extra.get('branch', '') == '': | |
2026 self._extra['branch'] = 'default' | |
2027 | |
2028 if editor: | |
2029 self._text = editor(self._repo, self, []) | |
2030 self._repo.savecommitmessage(self._text) | |
2031 | |
2032 def manifestnode(self): | |
2033 return self._manifestnode | |
2034 | |
2035 @propertycache | |
2036 def _manifestctx(self): | |
2037 return self._repo.manifestlog[self._manifestnode] | |
2038 | |
2039 def filectx(self, path, filelog=None): | |
2040 return self._originalctx.filectx(path, filelog=filelog) | |
2041 | |
2042 def commit(self): | |
2043 """commit context to the repo""" | |
2044 return self._repo.commitctx(self) | |
2045 | |
2046 @property | |
2047 def _manifest(self): | |
2048 return self._originalctx.manifest() | |
2049 | |
2050 @propertycache | |
2051 def _status(self): | |
2052 """Calculate exact status from ``files`` specified in the ``origctx`` | |
2053 and parents manifests. | |
2054 """ | |
2055 man1 = self.p1().manifest() | |
2056 p2 = self._parents[1] | |
2057 # "1 < len(self._parents)" can't be used for checking | |
2058 # existence of the 2nd parent, because "metadataonlyctx._parents" is | |
2059 # explicitly initialized by the list, of which length is 2. | |
2060 if p2.node() != nullid: | |
2061 man2 = p2.manifest() | |
2062 managing = lambda f: f in man1 or f in man2 | |
2063 else: | |
2064 managing = lambda f: f in man1 | |
2065 | |
2066 modified, added, removed = [], [], [] | |
2067 for f in self._files: | |
2068 if not managing(f): | |
2069 added.append(f) | |
2070 elif self[f]: | |
2071 modified.append(f) | |
2072 else: | |
2073 removed.append(f) | |
2074 | |
2075 return scmutil.status(modified, added, removed, [], [], [], []) |