hgext/graphlog.py
changeset 16173 9178d284b880
parent 16171 336e61875335
child 16174 0a73c4bd9f47
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