# HG changeset patch # User Artem Tikhomirov # Date 1356542093 -3600 # Node ID 2103388d4010bff6dcf8d2e4c42a67b9d95aa646 # Parent 59e555c85da0fee93f4261413e17cdc683560cdf Expose option to report changesets in reversed order diff -r 59e555c85da0 -r 2103388d4010 src/org/tmatesoft/hg/core/HgIterateDirection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/core/HgIterateDirection.java Wed Dec 26 18:14:53 2012 +0100 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012 TMate Software Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.core; + + +/** + * Change order changesets are reported to handler + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public enum HgIterateDirection { + /** + * Natural order, earlier revisions come first + */ + OldToNew, + + /** + * Reversed order, newer revisions come first, much like command-line client does + */ + NewToOld +} \ No newline at end of file diff -r 59e555c85da0 -r 2103388d4010 src/org/tmatesoft/hg/core/HgLogCommand.java --- a/src/org/tmatesoft/hg/core/HgLogCommand.java Wed Dec 26 17:51:07 2012 +0100 +++ b/src/org/tmatesoft/hg/core/HgLogCommand.java Wed Dec 26 18:14:53 2012 +0100 @@ -36,7 +36,6 @@ import org.tmatesoft.hg.internal.AdapterPlug; import org.tmatesoft.hg.internal.BatchRangeHelper; -import org.tmatesoft.hg.internal.Experimental; import org.tmatesoft.hg.internal.IntMap; import org.tmatesoft.hg.internal.IntVector; import org.tmatesoft.hg.internal.Lifecycle; @@ -91,6 +90,9 @@ * Note, 'hg log --follow' combines both #followHistory and #followAncestry */ private boolean followAncestry; + + private HgIterateDirection iterateDirection = HgIterateDirection.OldToNew; + private ChangesetTransformer csetTransform; private HgParentChildMap parentHelper; @@ -240,6 +242,19 @@ public HgLogCommand file(String file, boolean followCopyRename, boolean followFileAncestry) { return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename, followFileAncestry); } + + /** + * Specifies order for changesets reported through #execute(...) methods. + * By default, command reports changeset in their natural repository order, older first, + * newer last (i.e. {@link HgIterateDirection#OldToNew} + * + * @param order {@link HgIterateDirection#NewToOld} to get newer revisions first + * @return this for convenience + */ + public HgLogCommand order(HgIterateDirection order) { + iterateDirection = order; + return this; + } /** * Similar to {@link #execute(HgChangesetHandler)}, collects and return result as a list. @@ -305,12 +320,12 @@ filterInsp.changesets(startRev, lastCset); if (file == null) { progressHelper.start(lastCset - startRev + 1); - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { filterInsp.delegateTo(csetTransform); repo.getChangelog().range(startRev, lastCset, filterInsp); csetTransform.checkFailure(); } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; BatchRangeHelper brh = new BatchRangeHelper(startRev, lastCset, BATCH_SIZE, true); BatchChangesetInspector batchInspector = new BatchChangesetInspector(Math.min(lastCset-startRev+1, BATCH_SIZE)); filterInsp.delegateTo(batchInspector); @@ -338,11 +353,11 @@ @SuppressWarnings("unused") List fileAncestry = treeBuilder.go(fileNode, curRename.second()); int[] commitRevisions = narrowChangesetRange(treeBuilder.getCommitRevisions(), startRev, lastCset); - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { repo.getChangelog().range(filterInsp, commitRevisions); csetTransform.checkFailure(); } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; // visit one by one in the opposite direction for (int i = commitRevisions.length-1; i >= 0; i--) { int csetWithFileChange = commitRevisions[i]; @@ -353,11 +368,11 @@ // report complete file history (XXX may narrow range with [startRev, endRev], but need to go from file rev to link rev) int fileStartRev = 0; //fileNode.getChangesetRevisionIndex(0) >= startRev int fileEndRev = fileNode.getLastRevision(); - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { fileNode.history(fileStartRev, fileEndRev, filterInsp); csetTransform.checkFailure(); } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; BatchRangeHelper brh = new BatchRangeHelper(fileStartRev, fileEndRev, BATCH_SIZE, true); BatchChangesetInspector batchInspector = new BatchChangesetInspector(Math.min(fileEndRev-fileStartRev+1, BATCH_SIZE)); filterInsp.delegateTo(batchInspector); @@ -376,12 +391,12 @@ Pair nextRename = fileRenames.get(nameIndex+1); HgFileRevision src, dst; // A -> B - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { // curRename: A, nextRename: B src = new HgFileRevision(fileNode, curRename.second(), null); dst = new HgFileRevision(nextRename.first(), nextRename.first().getRevision(0), src.getPath()); } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; // curRename: B, nextRename: A src = new HgFileRevision(nextRename.first(), nextRename.second(), null); dst = new HgFileRevision(fileNode, fileNode.getRevision(0), src.getPath()); @@ -538,23 +553,6 @@ progressHelper.done(); } - /** - * DO NOT USE THIS METHOD, DEBUG PURPOSES ONLY!!! - */ - @Experimental(reason="Work in progress") - public HgLogCommand debugSwitch1() { - // FIXME can't expose iteration direction unless general iteration (changelog, not a file) supports it, too. - // however, need to test the code already there, hence this debug switch - if (iterateDirection == IterateDirection.FromOldToNew) { - iterateDirection = IterateDirection.FromNewToOld; - } else { - iterateDirection = IterateDirection.FromOldToNew; - } - return this; - } - - private IterateDirection iterateDirection = IterateDirection.FromOldToNew; - private static class ReverseIterator implements Iterator { private final ListIterator listIterator; @@ -614,10 +612,10 @@ Nodeid copyRev = fileNode.getCopySourceRevision(); fileNode = repo.getFileNode(fp); Pair p = new Pair(fileNode, copyRev); - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { rv.addFirst(p); } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; rv.addLast(p); } }; @@ -809,7 +807,7 @@ public void updateJunctionPoint(Pair curRename, Pair nextRename) { // A (old) renamed to B(new). A(0..k..n) -> B(0..m). If followAncestry, k == n // curRename.second() points to A(k) - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { // looking at A chunk (curRename), nextRename points to B HistoryNode junctionSrc = findJunctionPointInCurrentChunk(curRename.second()); // A(k) HistoryNode junctionDestMock = treeBuildInspector.one(nextRename.first(), 0); // B(0) @@ -821,7 +819,7 @@ // moreover, children of original A(k) (junctionSrc) would list mock B(0) which is undesired once we iterate over real B junctionNode = new HistoryNode(junctionSrc.changeset, junctionSrc.fileRevision, null, null); } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; // looking at B chunk (curRename), nextRename points at A HistoryNode junctionDest = changeHistory.get(0); // B(0) // prepare mock A(k) @@ -845,7 +843,7 @@ public void connectWithLastJunctionPoint(Pair curRename, Pair prevRename, HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException { assert junctionNode != null; // A renamed to B. A(0..k..n) -> B(0..m). If followAncestry: k == n - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { // forward, from old to new: // changeHistory points to B // Already reported: A(0)..A(n), A(k) is in junctionNode @@ -859,7 +857,7 @@ renameHandler.copy(copiedFrom, copiedTo); } } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; // changeHistory points to A // Already reported B(m), B(m-1)...B(0), B(0) is in junctionNode // Shall connect histories A(k).bind(B(0)) @@ -896,10 +894,10 @@ public void dispatchAllChanges() throws HgCallbackTargetException, CancelledException { // XXX shall sort changeHistory according to changeset numbers? Iterator it; - if (iterateDirection == IterateDirection.FromOldToNew) { + if (iterateDirection == HgIterateDirection.OldToNew) { it = changeHistory.listIterator(); } else { - assert iterateDirection == IterateDirection.FromNewToOld; + assert iterateDirection == HgIterateDirection.NewToOld; it = new ReverseIterator(changeHistory); } while(it.hasNext()) { @@ -1234,8 +1232,4 @@ } } } - - private enum IterateDirection { - FromOldToNew, FromNewToOld - } } diff -r 59e555c85da0 -r 2103388d4010 test/org/tmatesoft/hg/test/TestHistory.java --- a/test/org/tmatesoft/hg/test/TestHistory.java Wed Dec 26 17:51:07 2012 +0100 +++ b/test/org/tmatesoft/hg/test/TestHistory.java Wed Dec 26 18:14:53 2012 +0100 @@ -20,6 +20,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.tmatesoft.hg.core.HgIterateDirection.NewToOld; import java.util.ArrayList; import java.util.Collections; @@ -96,7 +97,7 @@ List r = new HgLogCommand(repo).execute(); report("hg log - COMPLETE REPO HISTORY", r, true); - r = new HgLogCommand(repo).debugSwitch1().execute(); + r = new HgLogCommand(repo).order(NewToOld).execute(); report("hg log - COMPLETE REPO HISTORY, FROM NEW TO OLD", r, false); } @@ -174,7 +175,7 @@ // // Direction h = new CollectWithRenameHandler(); - new HgLogCommand(repo).file(fname2, true, false).debugSwitch1().execute(h); + new HgLogCommand(repo).file(fname2, true, false).order(NewToOld).execute(h); // Identical rename shall be reported, at the same moment errorCollector.assertEquals(1, h.rh.renames.size()); rename = h.rh.renames.get(0); @@ -216,7 +217,7 @@ h = new TreeCollectHandler(false); rh = new RenameCollector(h); // h.checkPrevInChildren = true; see above - new HgLogCommand(repo).file(fname2, true, false).debugSwitch1().execute(h); + new HgLogCommand(repo).file(fname2, true, false).order(NewToOld).execute(h); errorCollector.assertEquals(1, rh.renames.size()); rename = rh.renames.get(0); errorCollector.assertEquals(fname1, rename.first().getPath().toString()); @@ -238,7 +239,7 @@ // // Direction h = new CollectWithRenameHandler(); - new HgLogCommand(repo).file(fname2, false, true).debugSwitch1().execute(h); + new HgLogCommand(repo).file(fname2, false, true).order(NewToOld).execute(h); report("HgChangesetHandler(renames: false, ancestry:true)", h.getChanges(), fname2Follow, false/*!!!*/, errorCollector); // // TreeChangeHandler - in #testChangesetTreeFollowAncestryNotRenames @@ -261,7 +262,7 @@ h = new TreeCollectHandler(false); rh = new RenameCollector(h); h.checkPrevInChildren = true; - new HgLogCommand(repo).file(fname2, false, true).debugSwitch1().execute(h); + new HgLogCommand(repo).file(fname2, false, true).order(NewToOld).execute(h); report("HgChangesetTreeHandler(renames: false, ancestry:true)", h.getResult(), fname2Follow, false, errorCollector); } @@ -317,7 +318,7 @@ // // Switch direction and compare, order shall match that from console h = new CollectWithRenameHandler(); - new HgLogCommand(repo).file(fname2, true, true).debugSwitch1().execute(h); + new HgLogCommand(repo).file(fname2, true, true).order(NewToOld).execute(h); // Identical rename event shall be reported errorCollector.assertEquals(1, h.rh.renames.size()); rename = h.rh.renames.get(0);