Mercurial > hg
comparison mercurial/context.py @ 30718:ce662ee40d2d
context: add a `blockancestors(fctx, fromline, toline)` function
This yields ancestors of `fctx` by only keeping changesets touching the file
within specified linerange = (fromline, toline).
Matching revisions are found by inspecting the result of `mdiff.allblocks()`,
filtered by `mdiff.blocksinrange()`, to find out if there are blocks of type
"!" within specified line range.
If, at some iteration, an ancestor with an empty line range is encountered,
the algorithm stops as it means that the considered block of lines actually
has been introduced in the revision of this iteration. Otherwise, we finally
yield the initial revision of the file as the block originates from it.
When a merge changeset is encountered during ancestors lookup, we consider
there's a diff in the current line range as long as there is a diff between
the merge changeset and at least one of its parents (in the current line
range).
author | Denis Laxalde <denis.laxalde@logilab.fr> |
---|---|
date | Wed, 28 Dec 2016 23:03:37 +0100 |
parents | 9bf43a72b49d |
children | 2df983125d37 |
comparison
equal
deleted
inserted
replaced
30717:3eeb8e138e5c | 30718:ce662ee40d2d |
---|---|
1151 # hard for renames | 1151 # hard for renames |
1152 c = self._filelog.children(self._filenode) | 1152 c = self._filelog.children(self._filenode) |
1153 return [filectx(self._repo, self._path, fileid=x, | 1153 return [filectx(self._repo, self._path, fileid=x, |
1154 filelog=self._filelog) for x in c] | 1154 filelog=self._filelog) for x in c] |
1155 | 1155 |
1156 def blockancestors(fctx, fromline, toline): | |
1157 """Yield ancestors of `fctx` with respect to the block of lines within | |
1158 `fromline`-`toline` range. | |
1159 """ | |
1160 def changesrange(fctx1, fctx2, linerange2): | |
1161 """Return `(diffinrange, linerange1)` where `diffinrange` is True | |
1162 if diff from fctx2 to fctx1 has changes in linerange2 and | |
1163 `linerange1` is the new line range for fctx1. | |
1164 """ | |
1165 diffopts = patch.diffopts(fctx._repo.ui) | |
1166 blocks = mdiff.allblocks(fctx1.data(), fctx2.data(), diffopts) | |
1167 filteredblocks, linerange1 = mdiff.blocksinrange(blocks, linerange2) | |
1168 diffinrange = any(stype == '!' for _, stype in filteredblocks) | |
1169 return diffinrange, linerange1 | |
1170 | |
1171 visit = {(fctx.linkrev(), fctx.filenode()): (fctx, (fromline, toline))} | |
1172 while visit: | |
1173 c, linerange2 = visit.pop(max(visit)) | |
1174 pl = c.parents() | |
1175 if not pl: | |
1176 # The block originates from the initial revision. | |
1177 yield c | |
1178 continue | |
1179 inrange = False | |
1180 for p in pl: | |
1181 inrangep, linerange1 = changesrange(p, c, linerange2) | |
1182 inrange = inrange or inrangep | |
1183 if linerange1[0] == linerange1[1]: | |
1184 # Parent's linerange is empty, meaning that the block got | |
1185 # introduced in this revision; no need to go futher in this | |
1186 # branch. | |
1187 continue | |
1188 visit[p.linkrev(), p.filenode()] = p, linerange1 | |
1189 if inrange: | |
1190 yield c | |
1191 | |
1156 class committablectx(basectx): | 1192 class committablectx(basectx): |
1157 """A committablectx object provides common functionality for a context that | 1193 """A committablectx object provides common functionality for a context that |
1158 wants the ability to commit, e.g. workingctx or memctx.""" | 1194 wants the ability to commit, e.g. workingctx or memctx.""" |
1159 def __init__(self, repo, text="", user=None, date=None, extra=None, | 1195 def __init__(self, repo, text="", user=None, date=None, extra=None, |
1160 changes=None): | 1196 changes=None): |