comparison mercurial/cmdutil.py @ 35685:659dfbd852e2

log: extract function that processes log file patterns We'll need a matcher to compute revs followed from the given patterns.
author Yuya Nishihara <yuya@tcha.org>
date Wed, 03 Jan 2018 15:13:22 +0900
parents 1c929b4942a3
children b25fa5da4ca2
comparison
equal deleted inserted replaced
35684:1c929b4942a3 35685:659dfbd852e2
2320 if stopiteration: 2320 if stopiteration:
2321 break 2321 break
2322 2322
2323 return iterate() 2323 return iterate()
2324 2324
2325 def _makelogmatcher(repo, pats, opts):
2326 """Build matcher and expanded patterns from log options
2327
2328 Returns (match, pats, slowpath) where
2329 - match: a matcher built from the given pats and -I/-X opts
2330 - pats: patterns used (globs are expanded on Windows)
2331 - slowpath: True if patterns aren't as simple as scanning filelogs
2332 """
2333 # pats/include/exclude are passed to match.match() directly in
2334 # _matchfiles() revset but walkchangerevs() builds its matcher with
2335 # scmutil.match(). The difference is input pats are globbed on
2336 # platforms without shell expansion (windows).
2337 wctx = repo[None]
2338 match, pats = scmutil.matchandpats(wctx, pats, opts)
2339 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
2340 if not slowpath:
2341 follow = opts.get('follow') or opts.get('follow_first')
2342 for f in match.files():
2343 if follow and f not in wctx:
2344 # If the file exists, it may be a directory, so let it
2345 # take the slow path.
2346 if os.path.exists(repo.wjoin(f)):
2347 slowpath = True
2348 continue
2349 else:
2350 raise error.Abort(_('cannot follow file not in parent '
2351 'revision: "%s"') % f)
2352 filelog = repo.file(f)
2353 if not filelog:
2354 # A zero count may be a directory or deleted file, so
2355 # try to find matching entries on the slow path.
2356 if follow:
2357 raise error.Abort(
2358 _('cannot follow nonexistent file: "%s"') % f)
2359 slowpath = True
2360
2361 # We decided to fall back to the slowpath because at least one
2362 # of the paths was not a file. Check to see if at least one of them
2363 # existed in history - in that case, we'll continue down the
2364 # slowpath; otherwise, we can turn off the slowpath
2365 if slowpath:
2366 for path in match.files():
2367 if path == '.' or path in repo.store:
2368 break
2369 else:
2370 slowpath = False
2371
2372 return match, pats, slowpath
2373
2325 def _makefollowlogfilematcher(repo, files, followfirst): 2374 def _makefollowlogfilematcher(repo, files, followfirst):
2326 # When displaying a revision with --patch --follow FILE, we have 2375 # When displaying a revision with --patch --follow FILE, we have
2327 # to know which file of the revision must be diffed. With 2376 # to know which file of the revision must be diffed. With
2328 # --follow, we want the names of the ancestors of FILE in the 2377 # --follow, we want the names of the ancestors of FILE in the
2329 # revision, stored in "fcache". "fcache" is populated by 2378 # revision, stored in "fcache". "fcache" is populated by
2368 'keyword': ('keyword(%s)', '%lr'), 2417 'keyword': ('keyword(%s)', '%lr'),
2369 'prune': ('ancestors(%s)', 'not %lr'), 2418 'prune': ('ancestors(%s)', 'not %lr'),
2370 'user': ('user(%s)', '%lr'), 2419 'user': ('user(%s)', '%lr'),
2371 } 2420 }
2372 2421
2373 def _makelogrevset(repo, pats, opts): 2422 def _makelogrevset(repo, match, pats, slowpath, opts):
2374 """Return (expr, filematcher) where expr is a revset string built 2423 """Return (expr, filematcher) where expr is a revset string built
2375 from log options and file patterns or None. If --stat or --patch 2424 from log options and file patterns or None. If --stat or --patch
2376 are not passed filematcher is None. Otherwise it is a callable 2425 are not passed filematcher is None. Otherwise it is a callable
2377 taking a revision number and returning a match objects filtering 2426 taking a revision number and returning a match objects filtering
2378 the files to be detailed when displaying the revision. 2427 the files to be detailed when displaying the revision.
2387 2436
2388 # branch and only_branch are really aliases and must be handled at 2437 # branch and only_branch are really aliases and must be handled at
2389 # the same time 2438 # the same time
2390 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', []) 2439 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
2391 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']] 2440 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
2392 # pats/include/exclude are passed to match.match() directly in
2393 # _matchfiles() revset but walkchangerevs() builds its matcher with
2394 # scmutil.match(). The difference is input pats are globbed on
2395 # platforms without shell expansion (windows).
2396 wctx = repo[None]
2397 match, pats = scmutil.matchandpats(wctx, pats, opts)
2398 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
2399 if not slowpath:
2400 for f in match.files():
2401 if follow and f not in wctx:
2402 # If the file exists, it may be a directory, so let it
2403 # take the slow path.
2404 if os.path.exists(repo.wjoin(f)):
2405 slowpath = True
2406 continue
2407 else:
2408 raise error.Abort(_('cannot follow file not in parent '
2409 'revision: "%s"') % f)
2410 filelog = repo.file(f)
2411 if not filelog:
2412 # A zero count may be a directory or deleted file, so
2413 # try to find matching entries on the slow path.
2414 if follow:
2415 raise error.Abort(
2416 _('cannot follow nonexistent file: "%s"') % f)
2417 slowpath = True
2418
2419 # We decided to fall back to the slowpath because at least one
2420 # of the paths was not a file. Check to see if at least one of them
2421 # existed in history - in that case, we'll continue down the
2422 # slowpath; otherwise, we can turn off the slowpath
2423 if slowpath:
2424 for path in match.files():
2425 if path == '.' or path in repo.store:
2426 break
2427 else:
2428 slowpath = False
2429 2441
2430 fpats = ('_patsfollow', '_patsfollowfirst') 2442 fpats = ('_patsfollow', '_patsfollowfirst')
2431 fnopats = ('_ancestors', '_fancestors') 2443 fnopats = ('_ancestors', '_fancestors')
2432 2444
2433 if slowpath: 2445 if slowpath:
2526 opts.pop('follow_first', None) 2538 opts.pop('follow_first', None)
2527 limit = loglimit(opts) 2539 limit = loglimit(opts)
2528 revs = _logrevs(repo, opts) 2540 revs = _logrevs(repo, opts)
2529 if not revs: 2541 if not revs:
2530 return smartset.baseset(), None 2542 return smartset.baseset(), None
2543 match, pats, slowpath = _makelogmatcher(repo, pats, opts)
2531 if opts.get('rev') and follow: 2544 if opts.get('rev') and follow:
2532 revs = dagop.revancestors(repo, revs, followfirst=followfirst) 2545 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
2533 revs.reverse() 2546 revs.reverse()
2534 expr, filematcher = _makelogrevset(repo, pats, opts) 2547 expr, filematcher = _makelogrevset(repo, match, pats, slowpath, opts)
2535 if opts.get('graph') and opts.get('rev'): 2548 if opts.get('graph') and opts.get('rev'):
2536 # User-specified revs might be unsorted, but don't sort before 2549 # User-specified revs might be unsorted, but don't sort before
2537 # _makelogrevset because it might depend on the order of revs 2550 # _makelogrevset because it might depend on the order of revs
2538 if not (revs.isdescending() or revs.istopo()): 2551 if not (revs.isdescending() or revs.istopo()):
2539 revs.sort(reverse=True) 2552 revs.sort(reverse=True)