Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/context.py @ 32283:07da778f3b58
filectx: add an overlayfilectx class
The end goal is to make it possible to avoid potential expensive fctx.data()
when unnecessary.
While memctx is useful for creating new file contexts, there are many cases
where we could reuse an existing raw file revision (amend, histedit, rebase,
process a revision constructed by a remote peer, etc). The overlayfilectx
class is made to support such reuse cases. Together with a later patch, hash
calculation and expensive flag processor could be avoided.
author | Jun Wu <quark@fb.com> |
---|---|
date | Tue, 09 May 2017 20:23:21 -0700 |
parents | 067985c26773 |
children | 81936f6462c1 |
comparison
equal
deleted
inserted
replaced
32282:067985c26773 | 32283:07da778f3b58 |
---|---|
685 """A filecontext object represents the common logic for its children: | 685 """A filecontext object represents the common logic for its children: |
686 filectx: read-only access to a filerevision that is already present | 686 filectx: read-only access to a filerevision that is already present |
687 in the repo, | 687 in the repo, |
688 workingfilectx: a filecontext that represents files from the working | 688 workingfilectx: a filecontext that represents files from the working |
689 directory, | 689 directory, |
690 memfilectx: a filecontext that represents files in-memory.""" | 690 memfilectx: a filecontext that represents files in-memory, |
691 overlayfilectx: duplicate another filecontext with some fields overridden. | |
692 """ | |
691 @propertycache | 693 @propertycache |
692 def _filelog(self): | 694 def _filelog(self): |
693 return self._repo.file(self._path) | 695 return self._repo.file(self._path) |
694 | 696 |
695 @propertycache | 697 @propertycache |
2076 | 2078 |
2077 def write(self, data, flags): | 2079 def write(self, data, flags): |
2078 """wraps repo.wwrite""" | 2080 """wraps repo.wwrite""" |
2079 self._data = data | 2081 self._data = data |
2080 | 2082 |
2083 class overlayfilectx(committablefilectx): | |
2084 """Like memfilectx but take an original filectx and optional parameters to | |
2085 override parts of it. This is useful when fctx.data() is expensive (i.e. | |
2086 flag processor is expensive) and raw data, flags, and filenode could be | |
2087 reused (ex. rebase or mode-only amend a REVIDX_EXTSTORED file). | |
2088 """ | |
2089 | |
2090 def __init__(self, originalfctx, datafunc=None, path=None, flags=None, | |
2091 copied=None, ctx=None): | |
2092 """originalfctx: filecontext to duplicate | |
2093 | |
2094 datafunc: None or a function to override data (file content). It is a | |
2095 function to be lazy. path, flags, copied, ctx: None or overridden value | |
2096 | |
2097 copied could be (path, rev), or False. copied could also be just path, | |
2098 and will be converted to (path, nullid). This simplifies some callers. | |
2099 """ | |
2100 | |
2101 if path is None: | |
2102 path = originalfctx.path() | |
2103 if ctx is None: | |
2104 ctx = originalfctx.changectx() | |
2105 ctxmatch = lambda: True | |
2106 else: | |
2107 ctxmatch = lambda: ctx == originalfctx.changectx() | |
2108 | |
2109 repo = originalfctx.repo() | |
2110 flog = originalfctx.filelog() | |
2111 super(overlayfilectx, self).__init__(repo, path, flog, ctx) | |
2112 | |
2113 if copied is None: | |
2114 copied = originalfctx.renamed() | |
2115 copiedmatch = lambda: True | |
2116 else: | |
2117 if copied and not isinstance(copied, tuple): | |
2118 # repo._filecommit will recalculate copyrev so nullid is okay | |
2119 copied = (copied, nullid) | |
2120 copiedmatch = lambda: copied == originalfctx.renamed() | |
2121 | |
2122 # When data, copied (could affect data), ctx (could affect filelog | |
2123 # parents) are not overridden, rawdata, rawflags, and filenode may be | |
2124 # reused (repo._filecommit should double check filelog parents). | |
2125 # | |
2126 # path, flags are not hashed in filelog (but in manifestlog) so they do | |
2127 # not affect reusable here. | |
2128 # | |
2129 # If ctx or copied is overridden to a same value with originalfctx, | |
2130 # still consider it's reusable. originalfctx.renamed() may be a bit | |
2131 # expensive so it's not called unless necessary. Assuming datafunc is | |
2132 # always expensive, do not call it for this "reusable" test. | |
2133 reusable = datafunc is None and ctxmatch() and copiedmatch() | |
2134 | |
2135 if datafunc is None: | |
2136 datafunc = originalfctx.data | |
2137 if flags is None: | |
2138 flags = originalfctx.flags() | |
2139 | |
2140 self._datafunc = datafunc | |
2141 self._flags = flags | |
2142 self._copied = copied | |
2143 | |
2144 if reusable: | |
2145 # copy extra fields from originalfctx | |
2146 attrs = ['rawdata', 'rawflags', '_filenode', '_filerev'] | |
2147 for attr in attrs: | |
2148 if util.safehasattr(originalfctx, attr): | |
2149 setattr(self, attr, getattr(originalfctx, attr)) | |
2150 | |
2151 def data(self): | |
2152 return self._datafunc() | |
2153 | |
2081 class metadataonlyctx(committablectx): | 2154 class metadataonlyctx(committablectx): |
2082 """Like memctx but it's reusing the manifest of different commit. | 2155 """Like memctx but it's reusing the manifest of different commit. |
2083 Intended to be used by lightweight operations that are creating | 2156 Intended to be used by lightweight operations that are creating |
2084 metadata-only changes. | 2157 metadata-only changes. |
2085 | 2158 |