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)