Mercurial > hg
comparison hgext/graphlog.py @ 16173:9178d284b880
graphlog: implement --follow with file arguments
author | Patrick Mezard <patrick@mezard.eu> |
---|---|
date | Sat, 25 Feb 2012 22:11:36 +0100 |
parents | 336e61875335 |
children | 0a73c4bd9f47 |
comparison
equal
deleted
inserted
replaced
16172:db75321c7a0e | 16173:9178d284b880 |
---|---|
239 def check_unsupported_flags(pats, opts): | 239 def check_unsupported_flags(pats, opts): |
240 for op in ["follow_first", "copies", "newest_first"]: | 240 for op in ["follow_first", "copies", "newest_first"]: |
241 if op in opts and opts[op]: | 241 if op in opts and opts[op]: |
242 raise util.Abort(_("-G/--graph option is incompatible with --%s") | 242 raise util.Abort(_("-G/--graph option is incompatible with --%s") |
243 % op.replace("_", "-")) | 243 % op.replace("_", "-")) |
244 if pats and opts.get('follow'): | |
245 raise util.Abort(_("-G/--graph option is incompatible with --follow " | |
246 "with file argument")) | |
247 | 244 |
248 def revset(repo, pats, opts): | 245 def revset(repo, pats, opts): |
249 """Return revset str built of revisions, log options and file patterns. | 246 """Return revset str built of revisions, log options and file patterns. |
250 """ | 247 """ |
251 opt2revset = { | 248 opt2revset = { |
254 'only_merges': ('merge()', None), | 251 'only_merges': ('merge()', None), |
255 'removed': ('removes("*")', None), | 252 'removed': ('removes("*")', None), |
256 'date': ('date(%(val)r)', None), | 253 'date': ('date(%(val)r)', None), |
257 'branch': ('branch(%(val)r)', ' or '), | 254 'branch': ('branch(%(val)r)', ' or '), |
258 '_patslog': ('filelog(%(val)r)', ' or '), | 255 '_patslog': ('filelog(%(val)r)', ' or '), |
256 '_patsfollow': ('follow(%(val)r)', ' or '), | |
259 'keyword': ('keyword(%(val)r)', ' or '), | 257 'keyword': ('keyword(%(val)r)', ' or '), |
260 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '), | 258 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '), |
261 'user': ('user(%(val)r)', ' or '), | 259 'user': ('user(%(val)r)', ' or '), |
262 'rev': ('%(val)s', ' or '), | 260 'rev': ('%(val)s', ' or '), |
263 } | 261 } |
266 # branch and only_branch are really aliases and must be handled at | 264 # branch and only_branch are really aliases and must be handled at |
267 # the same time | 265 # the same time |
268 if 'branch' in opts and 'only_branch' in opts: | 266 if 'branch' in opts and 'only_branch' in opts: |
269 opts['branch'] = opts['branch'] + opts.pop('only_branch') | 267 opts['branch'] = opts['branch'] + opts.pop('only_branch') |
270 | 268 |
269 follow = opts.get('follow') | |
270 if 'follow' in opts: | |
271 del opts['follow'] | |
271 # pats/include/exclude are passed to match.match() directly in | 272 # pats/include/exclude are passed to match.match() directly in |
272 # _matchfile() revset but walkchangerevs() builds its matcher with | 273 # _matchfile() revset but walkchangerevs() builds its matcher with |
273 # scmutil.match(). The difference is input pats are globbed on | 274 # scmutil.match(). The difference is input pats are globbed on |
274 # platforms without shell expansion (windows). | 275 # platforms without shell expansion (windows). |
275 match, pats = scmutil.matchandpats(repo[None], pats, opts) | 276 pctx = repo[None] |
277 match, pats = scmutil.matchandpats(pctx, pats, opts) | |
276 slowpath = match.anypats() or (match.files() and opts.get('removed')) | 278 slowpath = match.anypats() or (match.files() and opts.get('removed')) |
277 if not slowpath: | 279 if not slowpath: |
278 for f in match.files(): | 280 for f in match.files(): |
281 if follow and f not in pctx: | |
282 raise util.Abort(_('cannot follow file not in parent ' | |
283 'revision: "%s"') % f) | |
279 filelog = repo.file(f) | 284 filelog = repo.file(f) |
280 if not len(filelog): | 285 if not len(filelog): |
281 # A zero count may be a directory or deleted file, so | 286 # A zero count may be a directory or deleted file, so |
282 # try to find matching entries on the slow path. | 287 # try to find matching entries on the slow path. |
288 if follow: | |
289 raise util.Abort( | |
290 _('cannot follow nonexistent file: "%s"') % f) | |
283 slowpath = True | 291 slowpath = True |
284 if slowpath: | 292 if slowpath: |
285 # See cmdutil.walkchangerevs() slow path. | 293 # See cmdutil.walkchangerevs() slow path. |
286 # | 294 # |
295 if follow: | |
296 raise util.Abort(_('can only follow copies/renames for explicit ' | |
297 'filenames')) | |
287 # pats/include/exclude cannot be represented as separate | 298 # pats/include/exclude cannot be represented as separate |
288 # revset expressions as their filtering logic applies at file | 299 # revset expressions as their filtering logic applies at file |
289 # level. For instance "-I a -X a" matches a revision touching | 300 # level. For instance "-I a -X a" matches a revision touching |
290 # "a" and "b" while "file(a) and not file(b)" does not. | 301 # "a" and "b" while "file(a) and not file(b)" does not. |
291 matchargs = [] | 302 matchargs = [] |
296 for p in opts.get('exclude', []): | 307 for p in opts.get('exclude', []): |
297 matchargs.append('x:' + p) | 308 matchargs.append('x:' + p) |
298 matchargs = ','.join(('%r' % p) for p in matchargs) | 309 matchargs = ','.join(('%r' % p) for p in matchargs) |
299 opts['rev'] = opts.get('rev', []) + ['_matchfiles(%s)' % matchargs] | 310 opts['rev'] = opts.get('rev', []) + ['_matchfiles(%s)' % matchargs] |
300 else: | 311 else: |
301 opts['_patslog'] = list(pats) | 312 if follow: |
313 if pats: | |
314 opts['_patsfollow'] = list(pats) | |
315 else: | |
316 opts['follow'] = True | |
317 else: | |
318 opts['_patslog'] = list(pats) | |
302 | 319 |
303 revset = [] | 320 revset = [] |
304 for op, val in opts.iteritems(): | 321 for op, val in opts.iteritems(): |
305 if not val: | 322 if not val: |
306 continue | 323 continue |