# HG changeset patch # User Artem Tikhomirov # Date 1355773872 -3600 # Node ID e6c8b9b654b2c12a4b5c540049909492ef5e210e # Parent 5dcb4581c8ef0c01c388d7741fe17dc2477ee33e Provide access to HgDataFile being iterated into HgChangesetTreeHandler.TreeElement to give context for renamed files diff -r 5dcb4581c8ef -r e6c8b9b654b2 cmdline/org/tmatesoft/hg/console/Main.java --- a/cmdline/org/tmatesoft/hg/console/Main.java Mon Dec 17 19:06:07 2012 +0100 +++ b/cmdline/org/tmatesoft/hg/console/Main.java Mon Dec 17 20:51:12 2012 +0100 @@ -191,6 +191,7 @@ final boolean isFork = entry.children().size() > 1; final HgChangeset cset = entry.changeset(); System.out.printf("%d:%s - %s (%s)\n", cset.getRevisionIndex(), cset.getNodeid().shortNotation(), cset.getComment(), cset.getPhase()); + System.out.printf("Known as %s (file rev:%s)\n", entry.file().getPath(), entry.fileRevision().shortNotation()); if (!isJoin && !isFork && !entry.children().isEmpty()) { System.out.printf("\t=> %s\n", sb); } diff -r 5dcb4581c8ef -r e6c8b9b654b2 src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java --- a/src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java Mon Dec 17 19:06:07 2012 +0100 +++ b/src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java Mon Dec 17 20:51:12 2012 +0100 @@ -19,6 +19,7 @@ import java.util.Collection; import org.tmatesoft.hg.internal.Callback; +import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.util.Pair; /** @@ -45,6 +46,17 @@ * @return revision of the revlog being iterated. */ public Nodeid fileRevision(); + + /** + * File node, provided revlog being iterated is a {@link HgDataFile}; {@link #fileRevision()} + * references revision from the history of this very {@link HgDataFile file}. + * + * Comes handy when file history with renames is being followed to find out + * file name for particular revision in the history. + * + * @return instance of the file being walked, or null if it's not a file but other revlog. + */ + public HgDataFile file(); /** * @return changeset associated with the current file revision diff -r 5dcb4581c8ef -r e6c8b9b654b2 src/org/tmatesoft/hg/core/HgLogCommand.java --- a/src/org/tmatesoft/hg/core/HgLogCommand.java Mon Dec 17 19:06:07 2012 +0100 +++ b/src/org/tmatesoft/hg/core/HgLogCommand.java Mon Dec 17 20:51:12 2012 +0100 @@ -297,16 +297,19 @@ } /** - * Tree-wise iteration of a file history, with handy access to parent-child relations between changesets. + * Tree-wise iteration of a file history, with handy access to parent-child relations between changesets. + * When file history is being followed, handler may additionally implement {@link HgFileRenameHandlerMixin} + * to get notified about switching between history chunks that belong to different names. * * @param handler callback to process changesets. + * @see HgFileRenameHandlerMixin * @throws HgCallbackTargetException propagated exception from the handler * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state * @throws CancelledException if execution of the command was cancelled * @throws IllegalArgumentException if command is not satisfied with its arguments * @throws ConcurrentModificationException if this log command instance is already running */ - public void execute(HgChangesetTreeHandler handler) throws HgCallbackTargetException, HgException, CancelledException { + public void execute(final HgChangesetTreeHandler handler) throws HgCallbackTargetException, HgException, CancelledException { if (handler == null) { throw new IllegalArgumentException(); } @@ -326,11 +329,43 @@ // last node of historyA with first node of historyB (A renamed to B case) // to make overall history smooth. HistoryNode lastFromPrevIteration = null; - HgFileRevision copiedFrom = null, copiedTo = null; - boolean shallReportRenameAfter1Step = false; - final int CACHE_CSET_IN_ADVANCE_THRESHOLD = 100; /* XXX is it really worth it? */ - ElementImpl ei = null; + class HandlerDispatcher { + private final int CACHE_CSET_IN_ADVANCE_THRESHOLD = 100; /* XXX is it really worth it? */ + private ElementImpl ei = null; + private ProgressSupport progress; + private HgDataFile currentFileNode; + + public void prepare(ProgressSupport parentProgress, int historyNodeCount, TreeBuildInspector treeBuildInspector) { + if (ei == null) { + // when follow is true, changeHistory.size() of the first revision might be quite short + // (e.g. bad fname recognized soon), hence ensure at least cache size at once + ei = new ElementImpl(Math.max(CACHE_CSET_IN_ADVANCE_THRESHOLD, historyNodeCount)); + } + if (historyNodeCount < CACHE_CSET_IN_ADVANCE_THRESHOLD ) { + int[] commitRevisions = treeBuildInspector.getCommitRevisions(); + // read bunch of changesets at once and cache 'em + ei.initTransform(); + repo.getChangelog().range(ei, commitRevisions); + parentProgress.worked(1); + progress = new ProgressSupport.Sub(parentProgress, 2); + } else { + progress = new ProgressSupport.Sub(parentProgress, 3); + } + progress.start(historyNodeCount); + } + public void once(HistoryNode n) throws HgCallbackTargetException, CancelledException { + handler.treeElement(ei.init(n, currentFileNode)); + progress.worked(1); + cancelHelper.checkCancelled(); + } + + public void switchTo(HgDataFile df) { + // from now on, use df in TreeElement + currentFileNode = df; + } + }; + final HandlerDispatcher dispatcher = new HandlerDispatcher(); // renamed files in the queue are placed with respect to #iterateDirection // i.e. if we iterate from new to old, recent filenames come first @@ -344,24 +379,7 @@ assert changeHistory.size() > 0; progressHelper.worked(1); cancelHelper.checkCancelled(); - final ProgressSupport ph2; - if (ei == null) { - // when follow is true, changeHistory.size() of the first revision might be quite short - // (e.g. bad fname recognized soon), hence ensure at least cache size at once - ei = new ElementImpl(Math.max(CACHE_CSET_IN_ADVANCE_THRESHOLD, changeHistory.size())); - } - if (changeHistory.size() < CACHE_CSET_IN_ADVANCE_THRESHOLD ) { - int[] commitRevisions = treeBuildInspector.getCommitRevisions(); - assert changeHistory.size() == commitRevisions.length; - // read bunch of changesets at once and cache 'em - ei.initTransform(); - repo.getChangelog().range(ei, commitRevisions); - progressHelper.worked(1); - ph2 = new ProgressSupport.Sub(progressHelper, 2); - } else { - ph2 = new ProgressSupport.Sub(progressHelper, 3); - } - ph2.start(changeHistory.size()); + dispatcher.prepare(progressHelper, changeHistory.size(), treeBuildInspector); if (lastFromPrevIteration != null) { if (iterateDirection == IterateDirection.FromOldToNew) { // forward, from old to new: @@ -369,13 +387,13 @@ // then A(n).bind(B(0)) HistoryNode oldestOfTheNextChunk = changeHistory.get(0); // B(0) lastFromPrevIteration.bindChild(oldestOfTheNextChunk); // lastFromPrevIteration is A(n) - changeHistory.add(0, lastFromPrevIteration); + dispatcher.once(lastFromPrevIteration); if (renameHandler != null) { // shall report renames assert namesIndex > 0; HgDataFile lastIterationFileNode = fileRenamesQueue.get(namesIndex-1).first(); // A - copiedFrom = new HgFileRevision(lastIterationFileNode, lastFromPrevIteration.fileRevision, null); - copiedTo = new HgFileRevision(renameInfo.first(), oldestOfTheNextChunk.fileRevision, copiedFrom.getPath()); - shallReportRenameAfter1Step = true; // report rename after A(n) + HgFileRevision copiedFrom = new HgFileRevision(lastIterationFileNode, lastFromPrevIteration.fileRevision, null); + HgFileRevision copiedTo = new HgFileRevision(renameInfo.first(), oldestOfTheNextChunk.fileRevision, copiedFrom.getPath()); + renameHandler.copy(copiedFrom, copiedTo); } } else { assert iterateDirection == IterateDirection.FromNewToOld; @@ -383,14 +401,14 @@ // First, report B(m), B(m-1)...B(1), then A(n).bind(B(0)), report B(0), A(n)... HistoryNode newestOfNextChunk = changeHistory.get(changeHistory.size() - 1); // A(n) newestOfNextChunk.bindChild(lastFromPrevIteration); - changeHistory.add(lastFromPrevIteration); + dispatcher.once(lastFromPrevIteration); if (renameHandler != null) { assert namesIndex > 0; // renameInfo points to chunk of name A now, and lastFromPrevIteration (from namesIndex-1) is B - copiedFrom = new HgFileRevision(renameInfo.first(), newestOfNextChunk.fileRevision, null); + HgFileRevision copiedFrom = new HgFileRevision(renameInfo.first(), newestOfNextChunk.fileRevision, null); HgDataFile lastIterationFileNode = fileRenamesQueue.get(namesIndex-1).first(); // B - copiedTo = new HgFileRevision(lastIterationFileNode, lastFromPrevIteration.fileRevision, copiedFrom.getPath()); - shallReportRenameAfter1Step = true; // report rename after B(0) + HgFileRevision copiedTo = new HgFileRevision(lastIterationFileNode, lastFromPrevIteration.fileRevision, copiedFrom.getPath()); + renameHandler.copy(copiedFrom, copiedTo); } } } @@ -409,6 +427,7 @@ } else { lastFromPrevIteration = null; // just for the sake of no references to old items } + dispatcher.switchTo(renameInfo.first()); // XXX shall sort changeHistory according to changeset numbers? Iterator it; if (iterateDirection == IterateDirection.FromOldToNew) { @@ -419,17 +438,7 @@ } while(it.hasNext()) { HistoryNode n = it.next(); - handler.treeElement(ei.init(n)); - ph2.worked(1); - cancelHelper.checkCancelled(); - if (shallReportRenameAfter1Step) { - assert renameHandler != null; - assert copiedFrom != null; - assert copiedTo != null; - renameHandler.copy(copiedFrom, copiedTo); - shallReportRenameAfter1Step = false; - copiedFrom = copiedTo = null; - } + dispatcher.once(n); } } // for fileRenamesQueue; progressHelper.done(); @@ -718,6 +727,7 @@ private class ElementImpl implements HgChangesetTreeHandler.TreeElement, HgChangelog.Inspector { private HistoryNode historyNode; + private HgDataFile fileNode; private Pair parents; private List children; private IntMap cachedChangesets; @@ -730,8 +740,9 @@ cachedChangesets = new IntMap(total); } - ElementImpl init(HistoryNode n) { + ElementImpl init(HistoryNode n, HgDataFile df) { historyNode = n; + fileNode = df; parents = null; children = null; changesetRevision = null; @@ -743,6 +754,10 @@ public Nodeid fileRevision() { return historyNode.fileRevision; } + + public HgDataFile file() { + return fileNode; + } public HgChangeset changeset() { return get(historyNode.changeset)[0];