Mercurial > hg
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) |