Mercurial > hg
comparison mercurial/cmdutil.py @ 45651:c7413ffe0402
cmdutil: remove remainder of old walkchangerevs() implementation
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 10 Sep 2020 18:57:31 +0900 |
parents | 0356b41fe01d |
children | 9628d3cd9d13 |
comparison
equal
deleted
inserted
replaced
45650:0356b41fe01d | 45651:c7413ffe0402 |
---|---|
14 | 14 |
15 from .i18n import _ | 15 from .i18n import _ |
16 from .node import ( | 16 from .node import ( |
17 hex, | 17 hex, |
18 nullid, | 18 nullid, |
19 nullrev, | |
20 short, | 19 short, |
21 ) | 20 ) |
22 from .pycompat import ( | 21 from .pycompat import ( |
23 getattr, | 22 getattr, |
24 open, | 23 open, |
47 pycompat, | 46 pycompat, |
48 repair, | 47 repair, |
49 revlog, | 48 revlog, |
50 rewriteutil, | 49 rewriteutil, |
51 scmutil, | 50 scmutil, |
52 smartset, | |
53 state as statemod, | 51 state as statemod, |
54 subrepoutil, | 52 subrepoutil, |
55 templatekw, | 53 templatekw, |
56 templater, | 54 templater, |
57 util, | 55 util, |
2247 yield windowsize | 2245 yield windowsize |
2248 if windowsize < sizelimit: | 2246 if windowsize < sizelimit: |
2249 windowsize *= 2 | 2247 windowsize *= 2 |
2250 | 2248 |
2251 | 2249 |
2252 def _walkrevs(repo, opts): | |
2253 # Default --rev value depends on --follow but --follow behavior | |
2254 # depends on revisions resolved from --rev... | |
2255 follow = opts.get(b'follow') or opts.get(b'follow_first') | |
2256 revspec = opts.get(b'rev') | |
2257 if follow and revspec: | |
2258 revs = scmutil.revrange(repo, revspec) | |
2259 revs = repo.revs(b'reverse(::%ld)', revs) | |
2260 elif revspec: | |
2261 revs = scmutil.revrange(repo, revspec) | |
2262 elif follow and repo.dirstate.p1() == nullid: | |
2263 revs = smartset.baseset() | |
2264 elif follow: | |
2265 revs = repo.revs(b'reverse(:.)') | |
2266 else: | |
2267 revs = smartset.spanset(repo) | |
2268 revs.reverse() | |
2269 return revs | |
2270 | |
2271 | |
2272 class FileWalkError(Exception): | |
2273 pass | |
2274 | |
2275 | |
2276 def walkfilerevs(repo, match, follow, revs, fncache): | |
2277 '''Walks the file history for the matched files. | |
2278 | |
2279 Returns the changeset revs that are involved in the file history. | |
2280 | |
2281 Throws FileWalkError if the file history can't be walked using | |
2282 filelogs alone. | |
2283 ''' | |
2284 wanted = set() | |
2285 copies = [] | |
2286 minrev, maxrev = min(revs), max(revs) | |
2287 | |
2288 def filerevs(filelog, last): | |
2289 """ | |
2290 Only files, no patterns. Check the history of each file. | |
2291 | |
2292 Examines filelog entries within minrev, maxrev linkrev range | |
2293 Returns an iterator yielding (linkrev, parentlinkrevs, copied) | |
2294 tuples in backwards order | |
2295 """ | |
2296 cl_count = len(repo) | |
2297 revs = [] | |
2298 for j in pycompat.xrange(0, last + 1): | |
2299 linkrev = filelog.linkrev(j) | |
2300 if linkrev < minrev: | |
2301 continue | |
2302 # only yield rev for which we have the changelog, it can | |
2303 # happen while doing "hg log" during a pull or commit | |
2304 if linkrev >= cl_count: | |
2305 break | |
2306 | |
2307 parentlinkrevs = [] | |
2308 for p in filelog.parentrevs(j): | |
2309 if p != nullrev: | |
2310 parentlinkrevs.append(filelog.linkrev(p)) | |
2311 n = filelog.node(j) | |
2312 revs.append( | |
2313 (linkrev, parentlinkrevs, follow and filelog.renamed(n)) | |
2314 ) | |
2315 | |
2316 return reversed(revs) | |
2317 | |
2318 def iterfiles(): | |
2319 pctx = repo[b'.'] | |
2320 for filename in match.files(): | |
2321 if follow: | |
2322 if filename not in pctx: | |
2323 raise error.Abort( | |
2324 _( | |
2325 b'cannot follow file not in parent ' | |
2326 b'revision: "%s"' | |
2327 ) | |
2328 % filename | |
2329 ) | |
2330 yield filename, pctx[filename].filenode() | |
2331 else: | |
2332 yield filename, None | |
2333 for filename_node in copies: | |
2334 yield filename_node | |
2335 | |
2336 for file_, node in iterfiles(): | |
2337 filelog = repo.file(file_) | |
2338 if not len(filelog): | |
2339 if node is None: | |
2340 # A zero count may be a directory or deleted file, so | |
2341 # try to find matching entries on the slow path. | |
2342 if follow: | |
2343 raise error.Abort( | |
2344 _(b'cannot follow nonexistent file: "%s"') % file_ | |
2345 ) | |
2346 raise FileWalkError(b"Cannot walk via filelog") | |
2347 else: | |
2348 continue | |
2349 | |
2350 if node is None: | |
2351 last = len(filelog) - 1 | |
2352 else: | |
2353 last = filelog.rev(node) | |
2354 | |
2355 # keep track of all ancestors of the file | |
2356 ancestors = {filelog.linkrev(last)} | |
2357 | |
2358 # iterate from latest to oldest revision | |
2359 for rev, flparentlinkrevs, copied in filerevs(filelog, last): | |
2360 if not follow: | |
2361 if rev > maxrev: | |
2362 continue | |
2363 else: | |
2364 # Note that last might not be the first interesting | |
2365 # rev to us: | |
2366 # if the file has been changed after maxrev, we'll | |
2367 # have linkrev(last) > maxrev, and we still need | |
2368 # to explore the file graph | |
2369 if rev not in ancestors: | |
2370 continue | |
2371 # XXX insert 1327 fix here | |
2372 if flparentlinkrevs: | |
2373 ancestors.update(flparentlinkrevs) | |
2374 | |
2375 fncache.setdefault(rev, []).append(file_) | |
2376 wanted.add(rev) | |
2377 if copied: | |
2378 copies.append(copied) | |
2379 | |
2380 return wanted | |
2381 | |
2382 | |
2383 class _followfilter(object): | |
2384 def __init__(self, repo, onlyfirst=False): | |
2385 self.repo = repo | |
2386 self.startrev = nullrev | |
2387 self.roots = set() | |
2388 self.onlyfirst = onlyfirst | |
2389 | |
2390 def match(self, rev): | |
2391 def realparents(rev): | |
2392 try: | |
2393 if self.onlyfirst: | |
2394 return self.repo.changelog.parentrevs(rev)[0:1] | |
2395 else: | |
2396 return filter( | |
2397 lambda x: x != nullrev, | |
2398 self.repo.changelog.parentrevs(rev), | |
2399 ) | |
2400 except error.WdirUnsupported: | |
2401 prevs = [p.rev() for p in self.repo[rev].parents()] | |
2402 if self.onlyfirst: | |
2403 return prevs[:1] | |
2404 else: | |
2405 return prevs | |
2406 | |
2407 if self.startrev == nullrev: | |
2408 self.startrev = rev | |
2409 return True | |
2410 | |
2411 if rev > self.startrev: | |
2412 # forward: all descendants | |
2413 if not self.roots: | |
2414 self.roots.add(self.startrev) | |
2415 for parent in realparents(rev): | |
2416 if parent in self.roots: | |
2417 self.roots.add(rev) | |
2418 return True | |
2419 else: | |
2420 # backwards: all parents | |
2421 if not self.roots: | |
2422 self.roots.update(realparents(self.startrev)) | |
2423 if rev in self.roots: | |
2424 self.roots.remove(rev) | |
2425 self.roots.update(realparents(rev)) | |
2426 return True | |
2427 | |
2428 return False | |
2429 | |
2430 | |
2431 def walkchangerevs(repo, revs, makefilematcher, prepare): | 2250 def walkchangerevs(repo, revs, makefilematcher, prepare): |
2432 '''Iterate over files and the revs in a "windowed" way. | 2251 '''Iterate over files and the revs in a "windowed" way. |
2433 | 2252 |
2434 Callers most commonly need to iterate backwards over the history | 2253 Callers most commonly need to iterate backwards over the history |
2435 in which they are interested. Doing so has awful (quadratic-looking) | 2254 in which they are interested. Doing so has awful (quadratic-looking) |