# HG changeset patch # User Artem Tikhomirov # Date 1360939923 -3600 # Node ID 1e95f48d9886abe79b9711ab371bc877ca5e773e # Parent a71a05ec11bc0b04bfd6d5137f1974b782836abb Report line index for insertion and deletion, test against 'hg diff' output diff -r a71a05ec11bc -r 1e95f48d9886 src/org/tmatesoft/hg/internal/AnnotateFacility.java --- a/src/org/tmatesoft/hg/internal/AnnotateFacility.java Thu Feb 14 16:36:13 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/AnnotateFacility.java Fri Feb 15 15:52:03 2013 +0100 @@ -83,11 +83,13 @@ } public interface AddBlock extends Block { + int insertedAt(); // line index in the old file int firstAddedLine(); int totalAddedLines(); String[] addedLines(); } public interface DeleteBlock extends Block { + int removedAt(); // line index in the new file int firstRemovedLine(); int totalRemovedLines(); String[] removedLines(); @@ -105,17 +107,17 @@ @Override protected void changed(int s1From, int s1To, int s2From, int s2To) { - insp.changed(new BlockImpl2(seq1, seq2, s1From, s1To-s1From, s2From, s2To - s2From)); + insp.changed(new BlockImpl2(seq1, seq2, s1From, s1To-s1From, s2From, s2To - s2From, s1From, s2From)); } @Override protected void added(int s1InsertPoint, int s2From, int s2To) { - insp.added(new BlockImpl2(null, seq2, -1, -1, s2From, s2To - s2From)); + insp.added(new BlockImpl2(null, seq2, -1, -1, s2From, s2To - s2From, s1InsertPoint, -1)); } @Override - protected void deleted(int s1From, int s1To) { - insp.deleted(new BlockImpl2(seq1, null, s1From, s1To - s1From, -1, -1)); + protected void deleted(int s2DeletePoint, int s1From, int s1To) { + insp.deleted(new BlockImpl2(seq1, null, s1From, s1To - s1From, -1, -1, -1, s2DeletePoint)); } @Override @@ -151,14 +153,22 @@ private final int s1Len; private final int s2Start; private final int s2Len; + private final int s1InsertPoint; + private final int s2DeletePoint; - public BlockImpl2(ChunkSequence s1, ChunkSequence s2, int s1Start, int s1Len, int s2Start, int s2Len) { + public BlockImpl2(ChunkSequence s1, ChunkSequence s2, int s1Start, int s1Len, int s2Start, int s2Len, int s1InsertPoint, int s2DeletePoint) { oldSeq = s1; newSeq = s2; this.s1Start = s1Start; this.s1Len = s1Len; this.s2Start = s2Start; this.s2Len = s2Len; + this.s1InsertPoint = s1InsertPoint; + this.s2DeletePoint = s2DeletePoint; + } + + public int insertedAt() { + return s1InsertPoint; } public int firstAddedLine() { @@ -172,6 +182,10 @@ public String[] addedLines() { return generateLines(totalAddedLines(), firstAddedLine()); } + + public int removedAt() { + return s2DeletePoint; + } public int firstRemovedLine() { return s1Start; @@ -188,7 +202,7 @@ private String[] generateLines(int count, int startFrom) { String[] rv = new String[count]; for (int i = 0; i < count; i++) { - rv[i] = String.format("LINE %d", startFrom + i); + rv[i] = String.format("LINE %d", startFrom + i+1); } return rv; } diff -r a71a05ec11bc -r 1e95f48d9886 src/org/tmatesoft/hg/internal/PatchGenerator.java --- a/src/org/tmatesoft/hg/internal/PatchGenerator.java Thu Feb 14 16:36:13 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/PatchGenerator.java Fri Feb 15 15:52:03 2013 +0100 @@ -187,7 +187,7 @@ changed(changeStartS1, matchStartSeq1, changeStartS2, matchStartSeq2); } else { assert changeStartS2 == matchStartSeq2; - deleted(changeStartS1, matchStartSeq1); + deleted(matchStartSeq2, changeStartS1, matchStartSeq1); } } else { assert changeStartS1 == matchStartSeq1; @@ -210,7 +210,7 @@ // NO-OP } - protected void deleted(int s1From, int s1To) { + protected void deleted(int s2DeletePoint, int s1From, int s1To) { // NO-OP } @@ -231,7 +231,7 @@ } @Override - protected void deleted(int s1From, int s1To) { + protected void deleted(int s2DeletionPoint, int s1From, int s1To) { System.out.printf("deleted [%d..%d)\n", s1From, s1To); } @@ -259,7 +259,7 @@ } @Override - protected void deleted(int s1From, int s1To) { + protected void deleted(int s2DeletionPoint, int s1From, int s1To) { int from = seq1.chunk(s1From).getOffset(); int to = seq1.chunk(s1To).getOffset(); deltaCollector.add(from, to, new byte[0]); diff -r a71a05ec11bc -r 1e95f48d9886 test/org/tmatesoft/hg/test/TestBlame.java --- a/test/org/tmatesoft/hg/test/TestBlame.java Thu Feb 14 16:36:13 2013 +0100 +++ b/test/org/tmatesoft/hg/test/TestBlame.java Fri Feb 15 15:52:03 2013 +0100 @@ -16,13 +16,19 @@ */ package org.tmatesoft.hg.test; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.regex.Pattern; + +import org.junit.Assert; import org.junit.Test; import org.tmatesoft.hg.internal.AnnotateFacility; import org.tmatesoft.hg.internal.AnnotateFacility.AddBlock; +import org.tmatesoft.hg.internal.AnnotateFacility.Block; import org.tmatesoft.hg.internal.AnnotateFacility.ChangeBlock; import org.tmatesoft.hg.internal.AnnotateFacility.DeleteBlock; import org.tmatesoft.hg.internal.IntMap; -import org.tmatesoft.hg.internal.AnnotateFacility.Block; import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgLookup; import org.tmatesoft.hg.repo.HgRepository; @@ -38,38 +44,47 @@ @Test public void testSingleParentBlame() throws Exception { HgRepository repo = new HgLookup().detectFromWorkingDir(); - HgDataFile df = repo.getFileNode("src/org/tmatesoft/hg/internal/PatchGenerator.java"); - final IntMap linesOld= new IntMap(100); - final IntMap linesNew = new IntMap(100); - new AnnotateFacility().annotate(df, 539, new AnnotateFacility.Inspector() { - - public void same(Block block) { - // TODO Auto-generated method stub - + final String fname = "src/org/tmatesoft/hg/internal/PatchGenerator.java"; + final int checkChangeset = 539; + HgDataFile df = repo.getFileNode(fname); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + new AnnotateFacility().annotate(df, checkChangeset, 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); + // + String[] apiResult = splitLines(bos.toString()); + String[] expected = splitLines(gp.result()); + Assert.assertArrayEquals(expected, apiResult); + } + + private static String[] splitLines(CharSequence seq) { + int lineCount = 0; + for (int i = 0, x = seq.length(); i < x; i++) { + if (seq.charAt(i) == '\n') { + lineCount++; } - - public void deleted(DeleteBlock block) { - String[] lines = block.removedLines(); - assert lines.length == block.totalRemovedLines(); - for (int i = 0, ln = block.firstRemovedLine(); i < lines.length; i++, ln++) { - linesOld.put(ln, String.format("%3d:---:%s", ln, lines[i])); - } + } + if (seq.length() > 0 && seq.charAt(seq.length()-1) != '\n') { + lineCount++; + } + String[] rv = new String[lineCount]; + int lineStart = 0, lineEnd = 0, ix = 0; + do { + while (lineEnd < seq.length() && seq.charAt(lineEnd) != '\n') lineEnd++; + if (lineEnd == lineStart) { + continue; } - - public void changed(ChangeBlock block) { - deleted(block); - added(block); - } - - public void added(AddBlock block) { - String[] addedLines = block.addedLines(); - assert addedLines.length == block.totalAddedLines(); - for (int i = 0, ln = block.firstAddedLine(), x = addedLines.length; i < x; i++, ln++) { - linesNew.put(ln, String.format("%3d:+++:%s", ln, addedLines[i])); - } - } - }); - + CharSequence line = seq.subSequence(lineStart, lineEnd); + rv[ix++] = line.toString(); + lineStart = ++lineEnd; + } while (lineStart < seq.length()); + assert ix == lineCount; + return rv; + } + + private void leftovers() { + IntMap linesOld = new IntMap(100), linesNew = new IntMap(100); System.out.println("Changes to old revision:"); for (int i = linesOld.firstKey(), x = linesOld.lastKey(); i < x; i++) { if (linesOld.containsKey(i)) { @@ -86,6 +101,74 @@ } public static void main(String[] args) throws Exception { + System.out.println(Arrays.equals(new String[0], splitLines(""))); + System.out.println(Arrays.equals(new String[] { "abc" }, splitLines("abc"))); new TestBlame().testSingleParentBlame(); } + + static class DiffOutInspector implements AnnotateFacility.Inspector { + private final PrintStream out; + + DiffOutInspector(PrintStream ps) { + out = ps; + } + + public void same(Block block) { + // nothing + } + + public void deleted(DeleteBlock block) { + out.printf("@@ -%d,%d +%d,0 @@\n", block.firstRemovedLine() + 1, block.totalRemovedLines(), block.removedAt()); +// String[] lines = block.removedLines(); +// assert lines.length == block.totalRemovedLines(); +// for (int i = 0, ln = block.firstRemovedLine(); i < lines.length; i++, ln++) { +// linesOld.put(ln, String.format("%3d:---:%s", ln, lines[i])); +// } + } + + public void changed(ChangeBlock block) { +// deleted(block); +// added(block); + out.printf("@@ -%d,%d +%d,%d @@\n", block.firstRemovedLine() + 1, block.totalRemovedLines(), block.firstAddedLine() + 1, block.totalAddedLines()); + } + + public void added(AddBlock block) { + out.printf("@@ -%d,0 +%d,%d @@\n", block.insertedAt(), block.firstAddedLine() + 1, block.totalAddedLines()); +// String[] addedLines = block.addedLines(); +// assert addedLines.length == block.totalAddedLines(); +// for (int i = 0, ln = block.firstAddedLine(), x = addedLines.length; i < x; i++, ln++) { +// linesNew.put(ln, String.format("%3d:+++:%s", ln, addedLines[i])); +// } + } + } + + public static class LineGrepOutputParser implements OutputParser { + + private final Pattern pattern; + private final StringBuilder result = new StringBuilder(); + + public LineGrepOutputParser(String regexp) { + pattern = Pattern.compile(regexp); + } + + public CharSequence result() { + return result; + } + + public void parse(CharSequence seq) { + int lineStart = 0, lineEnd = 0; + do { + while (lineEnd < seq.length() && seq.charAt(lineEnd) != '\n') lineEnd++; + if (lineEnd == lineStart) { + continue; + } + CharSequence line = seq.subSequence(lineStart, lineEnd); + if (pattern.matcher(line).matches()) { + result.append(line); + result.append('\n'); + } + lineStart = ++lineEnd; + } while (lineStart < seq.length()); + } + } }