# HG changeset patch # User Artem Tikhomirov # Date 1369331068 -7200 # Node ID 72c979555cb8c1147a6739c3fc6146651acae986 # Parent 5f52074707b2a1402fc1827f20ab7f90ba88ce01 HgDiffCommand. Do not use deprecated code. Javadoc diff -r 5f52074707b2 -r 72c979555cb8 src/org/tmatesoft/hg/core/HgDiffCommand.java --- a/src/org/tmatesoft/hg/core/HgDiffCommand.java Wed May 22 16:46:15 2013 +0200 +++ b/src/org/tmatesoft/hg/core/HgDiffCommand.java Thu May 23 19:44:28 2013 +0200 @@ -16,16 +16,15 @@ */ package org.tmatesoft.hg.core; -import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex; import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; import static org.tmatesoft.hg.repo.HgRepository.TIP; import org.tmatesoft.hg.internal.BlameHelper; +import org.tmatesoft.hg.internal.CsetParamKeeper; import org.tmatesoft.hg.internal.Experimental; import org.tmatesoft.hg.internal.FileHistory; import org.tmatesoft.hg.internal.FileRevisionHistoryChunk; import org.tmatesoft.hg.repo.HgDataFile; -import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.repo.HgRuntimeException; import org.tmatesoft.hg.util.CancelledException; @@ -43,12 +42,13 @@ private final HgRepository repo; private HgDataFile df; - private int clogRevIndexStart, clogRevIndexEnd; - private int clogRevIndexToParents; + private final CsetParamKeeper clogRevIndexStart, clogRevIndexEnd; private HgIterateDirection iterateDirection = HgIterateDirection.NewToOld; public HgDiffCommand(HgRepository hgRepo) { repo = hgRepo; + clogRevIndexStart = new CsetParamKeeper(hgRepo); + clogRevIndexEnd = new CsetParamKeeper(hgRepo); } public HgDiffCommand file(Path file) { @@ -56,24 +56,63 @@ return this; } + /** + * Selects the file which history to blame, mandatory. + * + * @param file repository file + * @return this for convenience + */ public HgDiffCommand file(HgDataFile file) { df = file; return this; } - public HgDiffCommand range(int changelogRevIndexStart, int changelogRevIndexEnd) { - clogRevIndexStart = changelogRevIndexStart; - clogRevIndexEnd = changelogRevIndexEnd; + /** + * Select range of file's history for {@link #executeDiff(HgBlameInspector)} + * and {@link #executeAnnotate(HgBlameInspector)}. + *

+ * {@link #executeDiff(HgBlameInspector) diff} uses these as revisions to diff against each other, while + * {@link #executeAnnotate(HgBlameInspector) annotate} walks the range. + * + * @param changelogRevIndexStart index of changelog revision, left range boundary + * @param changelogRevIndexEnd index of changelog revision, right range boundary + * @return this for convenience + * @throws HgBadArgumentException if failed to find any of supplied changeset + */ + public HgDiffCommand range(int changelogRevIndexStart, int changelogRevIndexEnd) throws HgBadArgumentException { + clogRevIndexStart.set(changelogRevIndexStart); + clogRevIndexEnd.set(changelogRevIndexEnd); return this; } - // FIXME javadoc when needed and difference with range - public HgDiffCommand changeset(int changelogRevIndex) { - clogRevIndexToParents = changelogRevIndex; + /** + * Selects revision for {@link #executeAnnotateSingleRevision(HgBlameInspector)}, the one + * to diff against its parents. + * + * Besides, it is handy when range of interest spans up to the very beginning of the file history + * (and thus is equivalent to range(0, changelogRevIndex)) + * + * @param changelogRevIndex index of changelog revision + * @return this for convenience + * @throws HgBadArgumentException if failed to find supplied changeset + */ + public HgDiffCommand changeset(int changelogRevIndex) throws HgBadArgumentException { + clogRevIndexStart.set(0); + clogRevIndexEnd.set(changelogRevIndex); return this; } - // FIXME javadoc when needed + /** + * Revision differences are reported in selected order when + * annotating {@link #range(int, int) range} of changesets with + * {@link #executeAnnotate(HgBlameInspector)}. + *

+ * This method doesn't affect {@link #executeAnnotateSingleRevision(HgBlameInspector)} and + * {@link #executeDiff(HgBlameInspector)} + * + * @param order desired iteration order + * @return this for convenience + */ public HgDiffCommand order(HgIterateDirection order) { iterateDirection = order; return this; @@ -82,41 +121,41 @@ // FIXME progress and cancellation /** - * mimic 'hg diff -r clogRevIndex1 -r clogRevIndex2' + * Diff two revisions selected with {@link #range(int, int)} against each other. + *

mimics 'hg diff -r clogRevIndex1 -r clogRevIndex2' + * + * @throws HgCallbackTargetException propagated exception from the handler + * @throws CancelledException if execution of the command was cancelled + * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state */ public void executeDiff(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { + checkFile(); try { - int fileRevIndex1 = fileRevIndex(df, clogRevIndexStart); - int fileRevIndex2 = fileRevIndex(df, clogRevIndexEnd); + int fileRevIndex1 = fileRevIndex(df, clogRevIndexStart.get()); + int fileRevIndex2 = fileRevIndex(df, clogRevIndexEnd.get()); BlameHelper bh = new BlameHelper(insp); - bh.prepare(df, clogRevIndexStart, clogRevIndexEnd); - bh.diff(fileRevIndex1, clogRevIndexStart, fileRevIndex2, clogRevIndexEnd); + bh.prepare(df, clogRevIndexStart.get(), clogRevIndexEnd.get()); + bh.diff(fileRevIndex1, clogRevIndexStart.get(), fileRevIndex2, clogRevIndexEnd.get()); } catch (HgRuntimeException ex) { throw new HgLibraryFailureException(ex); } } /** - * Walk file history range and report changes (diff) for each revision + * Walk file history {@link #range(int, int) range} and report changes (diff) for each revision + * + * @throws HgCallbackTargetException propagated exception from the handler + * @throws CancelledException if execution of the command was cancelled + * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state */ public void executeAnnotate(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { - if (wrongRevisionIndex(clogRevIndexStart) || wrongRevisionIndex(clogRevIndexEnd)) { - throw new IllegalArgumentException(); - } - // FIXME check file and range are set + checkFile(); try { - // Note, changelogRevIndexEnd may be TIP, while the code below doesn't tolerate constants - // - int lastRevision = repo.getChangelog().getLastRevision(); - if (clogRevIndexEnd == TIP) { - clogRevIndexEnd = lastRevision; - } - HgInternals.checkRevlogRange(clogRevIndexStart, clogRevIndexEnd, lastRevision); if (!df.exists()) { return; } BlameHelper bh = new BlameHelper(insp); - FileHistory fileHistory = bh.prepare(df, clogRevIndexStart, clogRevIndexEnd); + FileHistory fileHistory = bh.prepare(df, clogRevIndexStart.get(), clogRevIndexEnd.get()); int[] fileClogParentRevs = new int[2]; int[] fileParentRevs = new int[2]; @@ -124,8 +163,8 @@ for (int fri : fhc.fileRevisions(iterateDirection)) { int clogRevIndex = fhc.changeset(fri); // the way we built fileHistory ensures we won't walk past [changelogRevIndexStart..changelogRevIndexEnd] - assert clogRevIndex >= clogRevIndexStart; - assert clogRevIndex <= clogRevIndexEnd; + assert clogRevIndex >= clogRevIndexStart.get(); + assert clogRevIndex <= clogRevIndexEnd.get(); fhc.fillFileParents(fri, fileParentRevs); fhc.fillCsetParents(fri, fileClogParentRevs); bh.annotateChange(fri, clogRevIndex, fileParentRevs, fileClogParentRevs); @@ -140,10 +179,15 @@ * Annotates changes of the file against its parent(s). * Unlike {@link #annotate(HgDataFile, int, Inspector, HgIterateDirection)}, doesn't * walk file history, looks at the specified revision only. Handles both parents (if merge revision). + * + * @throws HgCallbackTargetException propagated exception from the handler + * @throws CancelledException if execution of the command was cancelled + * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state */ public void executeAnnotateSingleRevision(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { + checkFile(); try { - int changelogRevisionIndex = clogRevIndexToParents; + int changelogRevisionIndex = clogRevIndexEnd.get(); // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f int fileRevIndex = fileRevIndex(df, changelogRevisionIndex); int[] fileRevParents = new int[2]; @@ -163,6 +207,11 @@ } } + private void checkFile() { + if (df == null) { + throw new IllegalArgumentException("File is not set"); + } + } private static int fileRevIndex(HgDataFile df, int csetRevIndex) throws HgRuntimeException { Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath()); diff -r 5f52074707b2 -r 72c979555cb8 src/org/tmatesoft/hg/core/HgRepoFacade.java --- a/src/org/tmatesoft/hg/core/HgRepoFacade.java Wed May 22 16:46:15 2013 +0200 +++ b/src/org/tmatesoft/hg/core/HgRepoFacade.java Thu May 23 19:44:28 2013 +0200 @@ -153,4 +153,8 @@ public HgCommitCommand createCommitCommand() { return new HgCommitCommand(repo); } + + public HgDiffCommand createDiffCommand() { + return new HgDiffCommand(repo); + } } diff -r 5f52074707b2 -r 72c979555cb8 src/org/tmatesoft/hg/internal/FileAnnotation.java --- a/src/org/tmatesoft/hg/internal/FileAnnotation.java Wed May 22 16:46:15 2013 +0200 +++ b/src/org/tmatesoft/hg/internal/FileAnnotation.java Thu May 23 19:44:28 2013 +0200 @@ -17,13 +17,9 @@ package org.tmatesoft.hg.internal; -import org.tmatesoft.hg.core.HgCallbackTargetException; -import org.tmatesoft.hg.core.HgIterateDirection; import org.tmatesoft.hg.core.HgBlameInspector; import org.tmatesoft.hg.core.HgBlameInspector.RevisionDescriptor; -import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgInvalidStateException; -import org.tmatesoft.hg.repo.HgRuntimeException; /** * Produce output like 'hg annotate' does @@ -46,17 +42,6 @@ int totalLines(); } - /** - * Annotate file revision, line by line. - */ - public static void annotate(HgDataFile df, int changelogRevisionIndex, LineInspector insp) throws HgCallbackTargetException, HgRuntimeException { - if (!df.exists()) { - return; - } - FileAnnotation fa = new FileAnnotation(insp); - df.annotate(0, changelogRevisionIndex, fa, HgIterateDirection.NewToOld); - } - // keeps of equal blocks, origin to target, from some previous step private RangeSeq activeEquals; // equal blocks of the current iteration, to be recalculated before next step diff -r 5f52074707b2 -r 72c979555cb8 test/org/tmatesoft/hg/test/TestBlame.java --- a/test/org/tmatesoft/hg/test/TestBlame.java Wed May 22 16:46:15 2013 +0200 +++ b/test/org/tmatesoft/hg/test/TestBlame.java Thu May 23 19:44:28 2013 +0200 @@ -42,15 +42,15 @@ import org.junit.Test; import org.tmatesoft.hg.core.HgAnnotateCommand; import org.tmatesoft.hg.core.HgAnnotateCommand.LineInfo; +import org.tmatesoft.hg.core.HgBlameInspector; import org.tmatesoft.hg.core.HgCallbackTargetException; -import org.tmatesoft.hg.core.HgIterateDirection; +import org.tmatesoft.hg.core.HgDiffCommand; import org.tmatesoft.hg.core.HgRepoFacade; import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.internal.FileAnnotation; import org.tmatesoft.hg.internal.FileAnnotation.LineDescriptor; import org.tmatesoft.hg.internal.FileAnnotation.LineInspector; import org.tmatesoft.hg.internal.IntVector; -import org.tmatesoft.hg.repo.HgBlameInspector; import org.tmatesoft.hg.repo.HgChangelog; import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgLookup; @@ -75,7 +75,9 @@ final int checkChangeset = repo.getChangelog().getRevisionIndex(Nodeid.fromAscii("946b131962521f9199e1fedbdc2487d3aaef5e46")); // 539 HgDataFile df = repo.getFileNode(fname); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - df.annotateSingleRevision(checkChangeset, new DiffOutInspector(new PrintStream(bos))); + HgDiffCommand diffCmd = new HgDiffCommand(repo); + diffCmd.file(df).changeset(checkChangeset); + diffCmd.executeAnnotateSingleRevision(new DiffOutInspector(new PrintStream(bos))); LineGrepOutputParser gp = new LineGrepOutputParser("^@@.+"); ExecHelper eh = new ExecHelper(gp, null); eh.run("hg", "diff", "-c", String.valueOf(checkChangeset), "-U", "0", fname); @@ -92,6 +94,8 @@ HgDataFile df = repo.getFileNode(fname); AnnotateRunner ar = new AnnotateRunner(df.getPath(), null); + final HgDiffCommand diffCmd = new HgDiffCommand(repo); + diffCmd.file(df).order(NewToOld); final HgChangelog clog = repo.getChangelog(); final int[] toTest = new int[] { clog.getRevisionIndex(Nodeid.fromAscii("946b131962521f9199e1fedbdc2487d3aaef5e46")), // 539 @@ -100,7 +104,8 @@ for (int cs : toTest) { ar.run(cs, false); FileAnnotateInspector fa = new FileAnnotateInspector(); - FileAnnotation.annotate(df, cs, fa); + diffCmd.range(0, cs); + diffCmd.executeAnnotate(new FileAnnotation(fa)); doAnnotateLineCheck(cs, ar.getLines(), Arrays.asList(fa.lineRevisions), Arrays.asList(fa.lines)); } } @@ -111,10 +116,12 @@ HgDataFile df = repo.getFileNode("file1"); AnnotateRunner ar = new AnnotateRunner(df.getPath(), repo.getWorkingDir()); + final HgDiffCommand diffCmd = new HgDiffCommand(repo).file(df).order(NewToOld); for (int cs : new int[] { 4, 6 /*, 8 see below*/, TIP}) { ar.run(cs, false); FileAnnotateInspector fa = new FileAnnotateInspector(); - FileAnnotation.annotate(df, cs, fa); + diffCmd.range(0, cs); + diffCmd.executeAnnotate(new FileAnnotation(fa)); doAnnotateLineCheck(cs, ar.getLines(), Arrays.asList(fa.lineRevisions), Arrays.asList(fa.lines)); } /*`hg annotate -r 8` and HgBlameFacility give different result @@ -138,7 +145,9 @@ HgDataFile df = repo.getFileNode("file1"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DiffOutInspector dump = new DiffOutInspector(new PrintStream(bos)); - df.annotate(0, TIP, dump, HgIterateDirection.OldToNew); + HgDiffCommand diffCmd = new HgDiffCommand(repo); + diffCmd.file(df).range(0, TIP).order(OldToNew); + diffCmd.executeAnnotate(dump); LinkedList apiResult = new LinkedList(Arrays.asList(splitLines(bos.toString()))); /* @@ -206,19 +215,22 @@ // earlier than rev2 shall be reported as new from change3 int[] change_2_8_new2old = new int[] {4, 6, 3, 4, -1, 3}; int[] change_2_8_old2new = new int[] {-1, 3, 3, 4, 4, 6 }; - df.annotate(2, 8, insp, NewToOld); + final HgDiffCommand cmd = new HgDiffCommand(repo); + cmd.file(df); + cmd.range(2, 8).order(NewToOld); + cmd.executeAnnotate(insp); Assert.assertArrayEquals(change_2_8_new2old, insp.getReportedRevisionPairs()); insp.reset(); - df.annotate(2, 8, insp, OldToNew); + cmd.order(OldToNew).executeAnnotate(insp); Assert.assertArrayEquals(change_2_8_old2new, insp.getReportedRevisionPairs()); // same as 2 to 8, with addition of rev9 changes rev7 (rev6 to rev7 didn't change content, only name) int[] change_3_9_new2old = new int[] {7, 9, 4, 6, 3, 4, -1, 3 }; int[] change_3_9_old2new = new int[] {-1, 3, 3, 4, 4, 6, 7, 9 }; insp.reset(); - df.annotate(3, 9, insp, NewToOld); + cmd.range(3, 9).order(NewToOld).executeAnnotate(insp); Assert.assertArrayEquals(change_3_9_new2old, insp.getReportedRevisionPairs()); insp.reset(); - df.annotate(3, 9, insp, OldToNew); + cmd.order(OldToNew).executeAnnotate(insp); Assert.assertArrayEquals(change_3_9_old2new, insp.getReportedRevisionPairs()); } @@ -269,14 +281,15 @@ LineGrepOutputParser gp = new LineGrepOutputParser("^@@.+"); ExecHelper eh = new ExecHelper(gp, repo.getWorkingDir()); int[] toTest = { 3, 4, 5 }; // p1 ancestry line, p2 ancestry line, not in ancestry line + final HgDiffCommand diffCmd = new HgDiffCommand(repo).file(df); for (int cs : toTest) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); - df.diff(cs, 8, new DiffOutInspector(new PrintStream(bos))); + diffCmd.range(cs, 8).executeDiff(new DiffOutInspector(new PrintStream(bos))); eh.run("hg", "diff", "-r", String.valueOf(cs), "-r", "8", "-U", "0", df.getPath().toString()); // String[] apiResult = splitLines(bos.toString()); String[] expected = splitLines(gp.result()); - Assert.assertArrayEquals("diff -r " + cs + " - r 8", expected, apiResult); + Assert.assertArrayEquals("diff -r " + cs + "-r 8", expected, apiResult); gp.reset(); } } @@ -293,7 +306,8 @@ eh.run("hg", "diff", "-c", "0", "-U", "0", df.getPath().toString()); // ByteArrayOutputStream bos = new ByteArrayOutputStream(); - df.annotateSingleRevision(0, new DiffOutInspector(new PrintStream(bos))); + HgDiffCommand diffCmd = new HgDiffCommand(repo).file(df); + diffCmd.changeset(0).executeAnnotateSingleRevision(new DiffOutInspector(new PrintStream(bos))); // String[] apiResult = splitLines(bos.toString()); String[] expected = splitLines(gp.result()); @@ -335,7 +349,10 @@ HgDataFile df = repo.getFileNode("file.txt"); DiffOutInspector dump = new DiffOutInspector(System.out); dump.needRevisions(true); - df.annotate(0, 8, dump, HgIterateDirection.NewToOld); + HgDiffCommand diffCmd = new HgDiffCommand(repo); + diffCmd.file(df); + diffCmd.range(0, 8).order(NewToOld); + diffCmd.executeAnnotate(dump); // af.annotateSingleRevision(df, 113, dump); // System.out.println(); // af.annotate(df, TIP, new LineDumpInspector(true), HgIterateDirection.NewToOld); @@ -351,7 +368,8 @@ errorCollector.verify(); */ FileAnnotateInspector fa = new FileAnnotateInspector(); - FileAnnotation.annotate(df, 8, fa); + diffCmd.range(0, 8).order(NewToOld); + diffCmd.executeAnnotate(new FileAnnotation(fa)); for (int i = 0; i < fa.lineRevisions.length; i++) { System.out.printf("%d: %s", fa.lineRevisions[i], fa.line(i) == null ? "null\n" : fa.line(i)); }