Mercurial > hg
diff hgext/graphlog.py @ 16186:af3e67354beb
graphlog: apply file filters --patch/--stat output
When passing --patch/--stat, file filters have to be applied to generate the
correct diff or stat output:
- Without --follow, the static match object can be reused
- With --follow, the files displayed at revision X are the ancestors of
selected files at parent revision. To do this, we reproduce the ancestry
calculations done by --follow, lazily.
test-glog.t changes show that --patch output is not satisfying because renames
are reported as copies. This can probably be fixed by:
- Without --follow: compute files to display, look for renames sources and
extend the matcher to include them.
- With --follow: detect .path() transitions between parent/child filectx,
filter them using the linked changectx .removed() field and extend fcache
with them.
author | Patrick Mezard <patrick@mezard.eu> |
---|---|
date | Sun, 26 Feb 2012 17:12:15 +0100 |
parents | 6863caf01daa |
children | 16ec050490fc |
line wrap: on
line diff
--- a/hgext/graphlog.py Sun Feb 26 17:10:57 2012 +0100 +++ b/hgext/graphlog.py Sun Feb 26 17:12:15 2012 +0100 @@ -242,8 +242,40 @@ raise util.Abort(_("-G/--graph option is incompatible with --%s") % op.replace("_", "-")) +def makefilematcher(repo, pats, followfirst): + # When displaying a revision with --patch --follow FILE, we have + # to know which file of the revision must be diffed. With + # --follow, we want the names of the ancestors of FILE in the + # revision, stored in "fcache". "fcache" is populated by + # reproducing the graph traversal already done by --follow revset + # and relating linkrevs to file names (which is not "correct" but + # good enough). + fcache = {} + fcacheready = [False] + pctx = repo['.'] + wctx = repo[None] + + def populate(): + for fn in pats: + for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)): + for c in i: + fcache.setdefault(c.linkrev(), set()).add(c.path()) + + def filematcher(rev): + if not fcacheready[0]: + # Lazy initialization + fcacheready[0] = True + populate() + return scmutil.match(wctx, fcache.get(rev, []), default='path') + + return filematcher + def revset(repo, pats, opts): - """Return revset str built of revisions, log options and file patterns. + """Return (expr, filematcher) where expr is a revset string built + of revisions, log options and file patterns. If --stat or --patch + are not passed filematcher is None. Otherwise it a a callable + taking a revision number and returning a match objects filtering + the files to be detailed when displaying the revision. """ opt2revset = { 'follow': ('follow()', None), @@ -329,6 +361,13 @@ else: opts['_patslog'] = list(pats) + filematcher = None + if opts.get('patch') or opts.get('stat'): + if follow: + filematcher = makefilematcher(repo, pats, followfirst) + else: + filematcher = lambda rev: match + revset = [] for op, val in opts.iteritems(): if not val: @@ -349,9 +388,10 @@ revset = '(' + ' and '.join(revset) + ')' else: revset = 'all()' - return revset + return revset, filematcher -def generate(ui, dag, displayer, showparents, edgefn, getrenamed=None): +def generate(ui, dag, displayer, showparents, edgefn, getrenamed=None, + filematcher=None): seen, state = [], asciistate() for rev, type, ctx, parents in dag: char = ctx.node() in showparents and '@' or 'o' @@ -362,7 +402,10 @@ rename = getrenamed(fn, ctx.rev()) if rename: copies.append((fn, rename[0])) - displayer.show(ctx, copies=copies) + revmatchfn = None + if filematcher is not None: + revmatchfn = filematcher(ctx.rev()) + displayer.show(ctx, copies=copies, matchfn=revmatchfn) lines = displayer.hunk.pop(rev).split('\n')[:-1] displayer.flush(rev) edges = edgefn(type, char, lines, seen, rev, parents) @@ -389,7 +432,8 @@ check_unsupported_flags(pats, opts) - revs = sorted(scmutil.revrange(repo, [revset(repo, pats, opts)]), reverse=1) + expr, filematcher = revset(repo, pats, opts) + revs = sorted(scmutil.revrange(repo, [expr]), reverse=1) limit = cmdutil.loglimit(opts) if limit is not None: revs = revs[:limit] @@ -403,7 +447,8 @@ getrenamed = templatekw.getrenamedfn(repo, endrev=endrev) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] - generate(ui, revdag, displayer, showparents, asciiedges, getrenamed) + generate(ui, revdag, displayer, showparents, asciiedges, getrenamed, + filematcher) def graphrevs(repo, nodes, opts): limit = cmdutil.loglimit(opts)