269 populate() |
269 populate() |
270 return scmutil.match(wctx, fcache.get(rev, []), default='path') |
270 return scmutil.match(wctx, fcache.get(rev, []), default='path') |
271 |
271 |
272 return filematcher |
272 return filematcher |
273 |
273 |
274 def revset(repo, pats, opts): |
274 def _makelogrevset(repo, pats, opts, revs): |
275 """Return (expr, filematcher) where expr is a revset string built |
275 """Return (expr, filematcher) where expr is a revset string built |
276 log options and file patterns, or None. Note that --rev options |
276 from log options and file patterns or None. If --stat or --patch |
277 are ignored when building expr because we do not know if they are |
277 are not passed filematcher is None. Otherwise it is a callable |
278 proper revsets or legacy expressions like a 'foo-bar' tags. If |
278 taking a revision number and returning a match objects filtering |
279 --stat or --patch are not passed filematcher is None. Otherwise it |
279 the files to be detailed when displaying the revision. |
280 a a callable taking a revision number and returning a match |
|
281 objects filtering the files to be detailed when displaying the |
|
282 revision. |
|
283 """ |
280 """ |
284 opt2revset = { |
281 opt2revset = { |
285 'follow': ('follow()', None), |
282 'follow': ('follow()', None), |
286 'follow_first': ('_followfirst()', None), |
283 'follow_first': ('_followfirst()', None), |
287 'no_merges': ('not merge()', None), |
284 'no_merges': ('not merge()', None), |
296 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '), |
293 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '), |
297 'user': ('user(%(val)r)', ' or '), |
294 'user': ('user(%(val)r)', ' or '), |
298 } |
295 } |
299 |
296 |
300 opts = dict(opts) |
297 opts = dict(opts) |
301 # branch and only_branch are really aliases and must be handled at |
298 # follow or not follow? |
302 # the same time |
|
303 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', []) |
|
304 follow = opts.get('follow') or opts.get('follow_first') |
299 follow = opts.get('follow') or opts.get('follow_first') |
305 followfirst = opts.get('follow_first') |
300 followfirst = opts.get('follow_first') |
306 if 'follow' in opts: |
301 if 'follow' in opts: |
307 del opts['follow'] |
302 del opts['follow'] |
308 if 'follow_first' in opts: |
303 if 'follow_first' in opts: |
309 del opts['follow_first'] |
304 del opts['follow_first'] |
|
305 |
|
306 # branch and only_branch are really aliases and must be handled at |
|
307 # the same time |
|
308 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', []) |
310 # pats/include/exclude are passed to match.match() directly in |
309 # pats/include/exclude are passed to match.match() directly in |
311 # _matchfile() revset but walkchangerevs() builds its matcher with |
310 # _matchfile() revset but walkchangerevs() builds its matcher with |
312 # scmutil.match(). The difference is input pats are globbed on |
311 # scmutil.match(). The difference is input pats are globbed on |
313 # platforms without shell expansion (windows). |
312 # platforms without shell expansion (windows). |
314 pctx = repo[None] |
313 pctx = repo[None] |
390 revset = '(' + ' and '.join(revset) + ')' |
389 revset = '(' + ' and '.join(revset) + ')' |
391 else: |
390 else: |
392 revset = None |
391 revset = None |
393 return revset, filematcher |
392 return revset, filematcher |
394 |
393 |
|
394 def getlogrevs(repo, pats, opts): |
|
395 """Return (revs, expr, filematcher) where revs is a list of |
|
396 revision numbers, expr is a revset string built from log options |
|
397 and file patterns or None, and used to filter 'revs'. If --stat or |
|
398 --patch are not passed filematcher is None. Otherwise it is a |
|
399 callable taking a revision number and returning a match objects |
|
400 filtering the files to be detailed when displaying the revision. |
|
401 """ |
|
402 if not len(repo): |
|
403 return [], None, None |
|
404 if opts.get('rev'): |
|
405 revs = scmutil.revrange(repo, opts['rev']) |
|
406 else: |
|
407 revs = range(len(repo)) |
|
408 if not revs: |
|
409 return [], None, None |
|
410 expr, filematcher = _makelogrevset(repo, pats, opts, revs) |
|
411 if expr: |
|
412 revs = revsetmod.match(repo.ui, expr)(repo, revs) |
|
413 return revs, expr, filematcher |
|
414 |
395 def generate(ui, dag, displayer, showparents, edgefn, getrenamed=None, |
415 def generate(ui, dag, displayer, showparents, edgefn, getrenamed=None, |
396 filematcher=None): |
416 filematcher=None): |
397 seen, state = [], asciistate() |
417 seen, state = [], asciistate() |
398 for rev, type, ctx, parents in dag: |
418 for rev, type, ctx, parents in dag: |
399 char = ctx.node() in showparents and '@' or 'o' |
419 char = ctx.node() in showparents and '@' or 'o' |
432 directory. |
452 directory. |
433 """ |
453 """ |
434 |
454 |
435 check_unsupported_flags(pats, opts) |
455 check_unsupported_flags(pats, opts) |
436 |
456 |
437 expr, filematcher = revset(repo, pats, opts) |
457 revs, expr, filematcher = getlogrevs(repo, pats, opts) |
438 if opts.get('rev'): |
|
439 revs = scmutil.revrange(repo, opts['rev']) |
|
440 else: |
|
441 revs = range(len(repo)) |
|
442 if expr: |
|
443 revs = revsetmod.match(repo.ui, expr)(repo, revs) |
|
444 revs = sorted(revs, reverse=1) |
458 revs = sorted(revs, reverse=1) |
445 limit = cmdutil.loglimit(opts) |
459 limit = cmdutil.loglimit(opts) |
446 if limit is not None: |
460 if limit is not None: |
447 revs = revs[:limit] |
461 revs = revs[:limit] |
448 revdag = graphmod.dagwalker(repo, revs) |
462 revdag = graphmod.dagwalker(repo, revs) |