comparison hgext/graphlog.py @ 16161:5a627b49b4d9

graphlog: paths/-I/-X handling requires a new revset The filtering logic of match objects cannot be reproduced with the existing revsets as it operates at changeset files level. A changeset touching "a" and "b" is matched by "-I a -X b" but not by "file(a) and not file(b)". To solve this, a new internal "_matchfiles(...)" revset is introduced. It works like "file(x)" but accepts more than one argument and its arguments are prefixed with "p:", "i:" and "x:" to be used as patterns, include patterns or exclude patterns respectively. The _matchfiles revset is kept private for now: - There are probably smarter ways to pass the arguments in a user-friendly way - A "rev:" argument is likely appear at some point to emulate log command behaviour with regard to filesets: they are evaluated for the parent revision and applied everywhere instead of being reevaluated for each revision.
author Patrick Mezard <patrick@mezard.eu>
date Thu, 23 Feb 2012 18:05:20 +0100
parents 1bfc7ba8b404
children 336e61875335
comparison
equal deleted inserted replaced
16160:1bfc7ba8b404 16161:5a627b49b4d9
253 'no_merges': ('not merge()', None), 253 'no_merges': ('not merge()', None),
254 'only_merges': ('merge()', None), 254 'only_merges': ('merge()', None),
255 'removed': ('removes("*")', None), 255 'removed': ('removes("*")', None),
256 'date': ('date(%(val)r)', None), 256 'date': ('date(%(val)r)', None),
257 'branch': ('branch(%(val)r)', ' or '), 257 'branch': ('branch(%(val)r)', ' or '),
258 'exclude': ('not file(%(val)r)', ' and '),
259 'include': ('file(%(val)r)', ' and '),
260 '_pats': ('file(%(val)r)', ' or '),
261 '_patslog': ('filelog(%(val)r)', ' or '), 258 '_patslog': ('filelog(%(val)r)', ' or '),
262 'keyword': ('keyword(%(val)r)', ' or '), 259 'keyword': ('keyword(%(val)r)', ' or '),
263 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '), 260 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
264 'user': ('user(%(val)r)', ' or '), 261 'user': ('user(%(val)r)', ' or '),
265 'rev': ('%(val)s', ' or '), 262 'rev': ('%(val)s', ' or '),
279 if not len(filelog): 276 if not len(filelog):
280 # A zero count may be a directory or deleted file, so 277 # A zero count may be a directory or deleted file, so
281 # try to find matching entries on the slow path. 278 # try to find matching entries on the slow path.
282 slowpath = True 279 slowpath = True
283 if slowpath: 280 if slowpath:
284 # See cmdutil.walkchangerevs() slow path 281 # See cmdutil.walkchangerevs() slow path.
285 opts['_pats'] = list(pats) 282 #
283 # pats/include/exclude cannot be represented as separate
284 # revset expressions as their filtering logic applies at file
285 # level. For instance "-I a -X a" matches a revision touching
286 # "a" and "b" while "file(a) and not file(b)" does not.
287 matchargs = []
288 for p in pats:
289 matchargs.append('p:' + p)
290 for p in opts.get('include', []):
291 matchargs.append('i:' + p)
292 for p in opts.get('exclude', []):
293 matchargs.append('x:' + p)
294 matchargs = ','.join(('%r' % p) for p in matchargs)
295 opts['rev'] = opts.get('rev', []) + ['_matchfiles(%s)' % matchargs]
286 else: 296 else:
287 opts['_patslog'] = list(pats) 297 opts['_patslog'] = list(pats)
288 298
289 revset = [] 299 revset = []
290 for op, val in opts.iteritems(): 300 for op, val in opts.iteritems():