* [JGIT PATCH 08/15] Always use the FileHeader buffer during Patch.parseHunks
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-8-git-send-email-spearce@spearce.org>
This ensures that if the code is ever refactored in the future to
permit different entry path into parseHunks that we won't read the
wrong buffer and potentially setup an invalid FileHeader.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/patch/Patch.java | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
index c940a00..164ad96 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
@@ -202,7 +202,7 @@ private int parseDiffGit(final byte[] buf, final int startOffset) {
return skipFile(buf, startOffset);
ptr = fh.parseGitHeaders(ptr);
- ptr = parseHunks(fh, buf, ptr);
+ ptr = parseHunks(fh, ptr);
fh.endOffset = ptr;
addFile(fh);
return ptr;
@@ -224,7 +224,7 @@ private int parseDiffCC(final byte[] buf, final int startOffset) {
private int parseTraditionalPatch(final byte[] buf, final int startOffset) {
final FileHeader fh = new FileHeader(buf, startOffset);
int ptr = fh.parseTraditionalHeaders(startOffset);
- ptr = parseHunks(fh, buf, ptr);
+ ptr = parseHunks(fh, ptr);
fh.endOffset = ptr;
addFile(fh);
return ptr;
@@ -237,7 +237,8 @@ private static int skipFile(final byte[] buf, int ptr) {
return ptr;
}
- private int parseHunks(final FileHeader fh, final byte[] buf, int c) {
+ private int parseHunks(final FileHeader fh, int c) {
+ final byte[] buf = fh.buf;
final int sz = buf.length;
while (c < sz) {
// If we see a file header at this point, we have all of the
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 07/15] Set empty patches with no Git metadata to PatchType.BINARY
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-7-git-send-email-spearce@spearce.org>
If a patch has no Git specific metadata and it has no hunks then
it is very likely a binary patch with a "Binary files ... differ"
warning message in a different language, or the message has been
mangled by an editor. We should consider such patches to be the
same as a binary patch, as there is nothing here to perform an
action on.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
| 18 ++++++++++++++++++
.../tst/org/spearce/jgit/patch/PatchTest.java | 2 ++
| 5 +++++
.../src/org/spearce/jgit/patch/Patch.java | 18 ++++++++++++++----
4 files changed, 39 insertions(+), 4 deletions(-)
--git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java
index d8696a9..4c2140a 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java
@@ -48,6 +48,7 @@ public void testParseGitFileName_Empty() {
assertEquals(-1, fh.parseGitFileName(0));
assertNotNull(fh.getHunks());
assertTrue(fh.getHunks().isEmpty());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_NoLF() {
@@ -68,6 +69,7 @@ public void testParseGitFileName_Foo() {
assertEquals(gitLine(name).length(), fh.parseGitFileName(0));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_FailFooBar() {
@@ -75,6 +77,7 @@ public void testParseGitFileName_FailFooBar() {
assertTrue(fh.parseGitFileName(0) > 0);
assertNull(fh.getOldName());
assertNull(fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_FooSpBar() {
@@ -83,6 +86,7 @@ public void testParseGitFileName_FooSpBar() {
assertEquals(gitLine(name).length(), fh.parseGitFileName(0));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_DqFooTabBar() {
@@ -92,6 +96,7 @@ public void testParseGitFileName_DqFooTabBar() {
assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_DqFooSpLfNulBar() {
@@ -101,6 +106,7 @@ public void testParseGitFileName_DqFooSpLfNulBar() {
assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_SrcFooC() {
@@ -109,6 +115,7 @@ public void testParseGitFileName_SrcFooC() {
assertEquals(gitLine(name).length(), fh.parseGitFileName(0));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_SrcFooCNonStandardPrefix() {
@@ -118,6 +125,7 @@ public void testParseGitFileName_SrcFooCNonStandardPrefix() {
assertEquals(header.length(), fh.parseGitFileName(0));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
}
public void testParseUnicodeName_NewFile() {
@@ -135,6 +143,7 @@ public void testParseUnicodeName_NewFile() {
assertSame(FileHeader.ChangeType.ADD, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
assertNull(fh.getOldMode());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
@@ -159,6 +168,7 @@ public void testParseUnicodeName_DeleteFile() {
assertSame(FileHeader.ChangeType.DELETE, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
assertNull(fh.getNewMode());
@@ -177,6 +187,7 @@ public void testParseModeChange() {
assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
assertNull(fh.getOldId());
assertNull(fh.getNewId());
@@ -204,6 +215,7 @@ public void testParseRename100_NewStyle() {
assertSame(FileHeader.ChangeType.RENAME, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
assertNull(fh.getOldId());
assertNull(fh.getNewId());
@@ -232,6 +244,7 @@ public void testParseRename100_OldStyle() {
assertSame(FileHeader.ChangeType.RENAME, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
assertNull(fh.getOldId());
assertNull(fh.getNewId());
@@ -260,6 +273,7 @@ public void testParseCopy100() {
assertSame(FileHeader.ChangeType.COPY, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
assertNull(fh.getOldId());
assertNull(fh.getNewId());
@@ -282,6 +296,7 @@ public void testParseFullIndexLine_WithMode() {
assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+ assertFalse(fh.hasMetaDataChanges());
assertNotNull(fh.getOldId());
assertNotNull(fh.getNewId());
@@ -302,6 +317,7 @@ public void testParseFullIndexLine_NoMode() {
assertEquals("a", fh.getOldName());
assertEquals("a", fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
assertNull(fh.getOldMode());
assertNull(fh.getNewMode());
@@ -330,6 +346,7 @@ public void testParseAbbrIndexLine_WithMode() {
assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+ assertFalse(fh.hasMetaDataChanges());
assertNotNull(fh.getOldId());
assertNotNull(fh.getNewId());
@@ -358,6 +375,7 @@ public void testParseAbbrIndexLine_NoMode() {
assertNull(fh.getOldMode());
assertNull(fh.getNewMode());
+ assertFalse(fh.hasMetaDataChanges());
assertNotNull(fh.getOldId());
assertNotNull(fh.getNewId());
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
index 833bf5d..bf37063 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
@@ -156,12 +156,14 @@ assertTrue(fh.getNewName().startsWith(
"org.spearce.egit.ui/icons/toolbar/"));
assertSame(FileHeader.PatchType.BINARY, fh.getPatchType());
assertTrue(fh.getHunks().isEmpty());
+ assertTrue(fh.hasMetaDataChanges());
}
final FileHeader fh = p.getFiles().get(4);
assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewName());
assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertFalse(fh.hasMetaDataChanges());
assertEquals("ee8a5a0", fh.getNewId().name());
assertEquals(1, fh.getHunks().size());
assertEquals(272, fh.getHunks().get(0).getOldStartLine());
--git a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
index 4bb6b7e..bf8d23a 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
@@ -250,6 +250,11 @@ public PatchType getPatchType() {
return patchType;
}
+ /** @return true if this patch modifies metadata about a file */
+ public boolean hasMetaDataChanges() {
+ return changeType != ChangeType.MODIFY || newMode != oldMode;
+ }
+
/** @return hunks altering this file; in order of appearance in patch */
public List<HunkHeader> getHunks() {
if (hunks == null)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
index 6e9ae77..c940a00 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
@@ -245,13 +245,13 @@ private int parseHunks(final FileHeader fh, final byte[] buf, int c) {
// with this position so it can be parsed again later.
//
if (match(buf, c, DIFF_GIT) >= 0)
- return c;
+ break;
if (match(buf, c, DIFF_CC) >= 0)
- return c;
+ break;
if (match(buf, c, OLD_NAME) >= 0)
- return c;
+ break;
if (match(buf, c, NEW_NAME) >= 0)
- return c;
+ break;
if (match(buf, c, HUNK_HDR) >= 0) {
final HunkHeader h = new HunkHeader(fh, c);
@@ -281,6 +281,16 @@ private int parseHunks(final FileHeader fh, final byte[] buf, int c) {
//
c = eol;
}
+
+ if (fh.getHunks().isEmpty()
+ && fh.getPatchType() == FileHeader.PatchType.UNIFIED
+ && !fh.hasMetaDataChanges()) {
+ // Hmm, an empty patch? If there is no metadata here we
+ // really have a binary patch that we didn't notice above.
+ //
+ fh.patchType = FileHeader.PatchType.BINARY;
+ }
+
return c;
}
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 09/15] Parse "GIT binary patch" style patch metadata
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-9-git-send-email-spearce@spearce.org>
Git can produce binary patches that carry the full content or
delta information encoded in a base-85 text payload. We parse
the headers out and produce a BinaryHunk wrapper for these so
applications can identify that the hunk exists, but we do not
attempt to decode the binary information.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../tst/org/spearce/jgit/patch/PatchTest.java | 42 ++++++
.../spearce/jgit/patch/testParse_GitBinary.patch | 135 ++++++++++++++++++++
.../src/org/spearce/jgit/patch/BinaryHunk.java | 128 +++++++++++++++++++
| 16 +++
.../src/org/spearce/jgit/patch/Patch.java | 32 +++++
5 files changed, 353 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/testParse_GitBinary.patch
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
index bf37063..453d88e 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
@@ -43,6 +43,7 @@
import junit.framework.TestCase;
import org.spearce.jgit.lib.FileMode;
+import org.spearce.jgit.lib.ObjectId;
public class PatchTest extends TestCase {
public void testEmpty() {
@@ -157,6 +158,45 @@ assertTrue(fh.getNewName().startsWith(
assertSame(FileHeader.PatchType.BINARY, fh.getPatchType());
assertTrue(fh.getHunks().isEmpty());
assertTrue(fh.hasMetaDataChanges());
+
+ assertNull(fh.getForwardBinaryHunk());
+ assertNull(fh.getReverseBinaryHunk());
+ }
+
+ final FileHeader fh = p.getFiles().get(4);
+ assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewName());
+ assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertFalse(fh.hasMetaDataChanges());
+ assertEquals("ee8a5a0", fh.getNewId().name());
+ assertNull(fh.getForwardBinaryHunk());
+ assertNull(fh.getReverseBinaryHunk());
+ assertEquals(1, fh.getHunks().size());
+ assertEquals(272, fh.getHunks().get(0).getOldStartLine());
+ }
+
+ public void testParse_GitBinary() throws IOException {
+ final Patch p = parseTestPatchFile();
+ final int[] binsizes = { 359, 393, 372, 404 };
+ assertEquals(5, p.getFiles().size());
+
+ for (int i = 0; i < 4; i++) {
+ final FileHeader fh = p.getFiles().get(i);
+ assertSame(FileHeader.ChangeType.ADD, fh.getChangeType());
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+ assertEquals(ObjectId.zeroId().name(), fh.getOldId().name());
+ assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+ assertTrue(fh.getNewName().startsWith(
+ "org.spearce.egit.ui/icons/toolbar/"));
+ assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
+ assertTrue(fh.getHunks().isEmpty());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertNotNull(fh.getForwardBinaryHunk());
+ assertNotNull(fh.getReverseBinaryHunk());
+ assertEquals(binsizes[i], fh.getForwardBinaryHunk().getSize());
+ assertEquals(0, fh.getReverseBinaryHunk().getSize());
}
final FileHeader fh = p.getFiles().get(4);
@@ -165,6 +205,8 @@ assertTrue(fh.getNewName().startsWith(
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
assertFalse(fh.hasMetaDataChanges());
assertEquals("ee8a5a0", fh.getNewId().name());
+ assertNull(fh.getForwardBinaryHunk());
+ assertNull(fh.getReverseBinaryHunk());
assertEquals(1, fh.getHunks().size());
assertEquals(272, fh.getHunks().get(0).getOldStartLine());
}
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testParse_GitBinary.patch b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testParse_GitBinary.patch
new file mode 100644
index 0000000..ab7b235
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testParse_GitBinary.patch
@@ -0,0 +1,135 @@
+From 8363f12135a7d0ff0b5fea7d5a35d294c0479518 Mon Sep 17 00:00:00 2001
+From: Robin Rosenberg <robin.rosenberg.lists@dewire.com>
+Date: Tue, 23 Sep 2008 22:19:19 +0200
+Subject: [PATCH] Push and fetch icons for the toolbar
+
+Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
+Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
+---
+ org.spearce.egit.ui/icons/toolbar/fetchd.png | Bin 0 -> 359 bytes
+ org.spearce.egit.ui/icons/toolbar/fetche.png | Bin 0 -> 393 bytes
+ org.spearce.egit.ui/icons/toolbar/pushd.png | Bin 0 -> 372 bytes
+ org.spearce.egit.ui/icons/toolbar/pushe.png | Bin 0 -> 404 bytes
+ org.spearce.egit.ui/plugin.xml | 32 ++++++++++++++-----------
+ 5 files changed, 18 insertions(+), 14 deletions(-)
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/fetchd.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/fetche.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushd.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushe.png
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetchd.png b/org.spearce.egit.ui/icons/toolbar/fetchd.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..4433c543f2a52b586a3ed5e31b138244107bc239
+GIT binary patch
+literal 359
+zcmV-t0hs=YP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0003lNkl<ZIE|%~
+zF{;8q6h+U7BBn4qm_`dxuy6}@!NzsCfLTKp;5yPsN=p|I(rKe&p~M74Bq5ObRRW{%
+zje4sYc=ybGk2gYV%`a+{hvjnl6{!Lo4hNJ{A44jDl#(C_K2BmJ09dV7A3>VW2}+n!
+zO1rKr0DRxqm&=7b&q>piUayDaIKlvw2}+e_&-3(PFkmzq(Q380-|r+zg6Da9KA(#Q
+zPa2QMl^Gz*GK3HmMPby1VQ9_(U^bf>W`H=3+3)uhMZxuY<#al++wJIfyXFi47K?>p
+z2GCj~rNp*vI-L&fb{osGh@!|$@ci;S2_arv_(sil1xb<+1Odb0kjLY}`F!ShJaW6;
+z>Lr*?r);;|7ihoV2SC*MjhoFzuh;A9KAB9aMXCk(Pk$Loi}X0uxcmSB002ovPDHLk
+FV1lxPoI3yj
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetche.png b/org.spearce.egit.ui/icons/toolbar/fetche.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..0ffeb419e6ab302caa5e58661854b33853dc43dc
+GIT binary patch
+literal 393
+zcmV;40e1e0P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0003{Nkl<ZIE|%}
+z%Su8~6o$WjJd|h&)kLg8qatclklHDbhzOh%4SI>*L3{^aqJcvRqCsRQ6~SndH7ExK
+zk=KcyE?#y6(aupYt$(ujUi|ChXYD1Vl>A3Z=W-tL|B2KE=%pm#uoxNA1!yxqxEMW&
+zB>{jQO^yT+ogtn_{8Ep$Aq3h-C?o|y>g-6?-!e46K4}{7I2X6^?w$w$wKqXWo#uE<
+zlN$@u$mIiCW0N$hIYc2#Jf_L5pe_`875HfeP>nhW1zLv1R!iSvNdTZ7`q(*62#YbV
+zQhB;#V#z_Hl;tD;jPm%3!!_Fv=xqj&EpW_lqPo^m>_wFE9KxQ3t1@8v1#@h(gk?2k
+zU%h_@BTD_vVB{6b=^Lij^3<ya#!DI7eU*yg9xg#(&qL<HX{n_QH=dOmU|OU>Dkk>j
+n^=YB|UiI3T3toz$0fY1nZ1068v8@+b00000NkvXXu0mjfWwNMg
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/pushd.png b/org.spearce.egit.ui/icons/toolbar/pushd.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..22c3f7bf17b8b5a931c7527d768af13607b03bce
+GIT binary patch
+literal 372
+zcmV-)0gL{LP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0003yNkl<ZIE|%~
+zF{%PF6h%)&8w)Kgg)~~o6c%=-wG$iH;R0NP3veAG$Sh>A(?&%>K?5S92zkHxGyeyN
+zQSnxRymxZ%OQJ-CZ<LQ0VHnEcaNzNHaJ${8)oOIRUG)l}M1;v?B8^6aVzEe}P~dX8
+zV6A1h+tKg$Ga)&E`~8km3g?`+IiJs8M#ur2PA68Y70x-1$0OVAmgRCusZ@FoAR=h3
+zDVNJsDix~LD)oBZD;$r<sngD7(Utm(zh18y4u?;WOu&C>t%;)O$w?l-T1yl~1VO;{
+zdS$=gv)ODopU<8HfZ1#YAcMg`B@Q~B4vWRYJJDL}%|UCO8Yd6XZnu?)$aFeQidwCf
+z_mE--u|}hjN&o=H7-fukIg4hqnKXNVchu|kh_lCf`xbzwX88RJ-{>O;Y5D>6^@Sy#
+SDlMe|0000<MNUMnLSTZnn4{zX
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/pushe.png b/org.spearce.egit.ui/icons/toolbar/pushe.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..1f99f0a702983d674f15eedae5f1218f0a30b5a0
+GIT binary patch
+literal 404
+zcmV;F0c-w=P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00047Nkl<ZIE|%~
+z%Su8~6o$WjJO~|4C>w|sG%6%VHSk(UL<B+v4SI>*L41dvA&3Z?G>L*BB*n0rWDTl8
+zL8Pb?Jzc!)CSJ}#$rF8}#a?Uu`(JCbg_M&2pmu`H$+oP&=V*R^(bPY1%&ibu+ZV$G
+zgp`tt<A@B;jw3Z6E&C{q>NBF4=c=f%6i@vsq5!CR9fSfc-IT0lZ>^0`E2vbS?r{1v
+z8l^m+g%^~^H#FDePyq!%wm_SSqPmu`yJKk6QAXzdroz+R(7<gg074jZz1Vo3Dy2y#
+zMW2W=)MJ~7I|%3fPE-KBpis_UGqzZuUe(cG%h>L#RCJHY0YK_74TR+C&ZX!&h^>3c
+zJvdA^W^@l;f6eS*z&I*^D|{frVpE>&7273F76LY=;y1$BWF(Q0qALI}5jqkZAq&fh
+y^_oorR)}l`>CE22@+$y+&Cvb}|KU##2Jr)k?t0Dap2#Es0000<MNUMnLSTZgH?cGT
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/plugin.xml b/org.spearce.egit.ui/plugin.xml
+index 7c98688..ee8a5a0 100644
+--- a/org.spearce.egit.ui/plugin.xml
++++ b/org.spearce.egit.ui/plugin.xml
+@@ -272,22 +272,26 @@
+ </separator>
+ </menu>
+ <action
+- class="org.spearce.egit.ui.internal.actions.FetchAction"
+- id="org.spearce.egit.ui.actionfetch"
+- label="%FetchAction_label"
+- style="push"
+- menubarPath="org.spearce.egit.ui.gitmenu/repo"
+- toolbarPath="org.spearce.egit.ui"
+- tooltip="%FetchAction_tooltip">
++ class="org.spearce.egit.ui.internal.actions.FetchAction"
++ disabledIcon="icons/toolbar/fetchd.png"
++ icon="icons/toolbar/fetche.png"
++ id="org.spearce.egit.ui.actionfetch"
++ label="%FetchAction_label"
++ menubarPath="org.spearce.egit.ui.gitmenu/repo"
++ style="push"
++ toolbarPath="org.spearce.egit.ui"
++ tooltip="%FetchAction_tooltip">
+ </action>
+ <action
+- class="org.spearce.egit.ui.internal.actions.PushAction"
+- id="org.spearce.egit.ui.actionpush"
+- label="%PushAction_label"
+- style="push"
+- menubarPath="org.spearce.egit.ui.gitmenu/repo"
+- toolbarPath="org.spearce.egit.ui"
+- tooltip="%PushAction_tooltip">
++ class="org.spearce.egit.ui.internal.actions.PushAction"
++ disabledIcon="icons/toolbar/pushd.png"
++ icon="icons/toolbar/pushe.png"
++ id="org.spearce.egit.ui.actionpush"
++ label="%PushAction_label"
++ menubarPath="org.spearce.egit.ui.gitmenu/repo"
++ style="push"
++ toolbarPath="org.spearce.egit.ui"
++ tooltip="%PushAction_tooltip">
+ </action>
+ <action
+ class="org.spearce.egit.ui.internal.actions.BranchAction"
+--
+1.6.1.rc2.306.ge5d5e
+
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java b/org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java
new file mode 100644
index 0000000..ce35286
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.patch;
+
+import static org.spearce.jgit.lib.Constants.encodeASCII;
+import static org.spearce.jgit.util.RawParseUtils.match;
+import static org.spearce.jgit.util.RawParseUtils.nextLF;
+import static org.spearce.jgit.util.RawParseUtils.parseBase10;
+
+/** Part of a "GIT binary patch" to describe the pre-image or post-image */
+public class BinaryHunk {
+ private static final byte[] LITERAL = encodeASCII("literal ");
+
+ private static final byte[] DELTA = encodeASCII("delta ");
+
+ /** Type of information stored in a binary hunk. */
+ public static enum Type {
+ /** The full content is stored, deflated. */
+ LITERAL_DEFLATED,
+
+ /** A Git pack-style delta is stored, deflated. */
+ DELTA_DEFLATED;
+ }
+
+ private final FileHeader file;
+
+ /** Offset within {@link #file}.buf to the "literal" or "delta " line. */
+ final int startOffset;
+
+ /** Position 1 past the end of this hunk within {@link #file}'s buf. */
+ int endOffset;
+
+ /** Type of the data meaning. */
+ private Type type;
+
+ /** Inflated length of the data. */
+ private int length;
+
+ BinaryHunk(final FileHeader fh, final int offset) {
+ file = fh;
+ startOffset = offset;
+ }
+
+ /** @return header for the file this hunk applies to */
+ public FileHeader getFileHeader() {
+ return file;
+ }
+
+ /** @return type of this binary hunk */
+ public Type getType() {
+ return type;
+ }
+
+ /** @return inflated size of this hunk's data */
+ public int getSize() {
+ return length;
+ }
+
+ int parseHunk(int ptr) {
+ final byte[] buf = file.buf;
+
+ if (match(buf, ptr, LITERAL) >= 0) {
+ type = Type.LITERAL_DEFLATED;
+ length = parseBase10(buf, ptr + LITERAL.length, null);
+
+ } else if (match(buf, ptr, DELTA) >= 0) {
+ type = Type.DELTA_DEFLATED;
+ length = parseBase10(buf, ptr + LITERAL.length, null);
+
+ } else {
+ // Not a valid binary hunk. Signal to the caller that
+ // we cannot parse any further and that this line should
+ // be treated otherwise.
+ //
+ return -1;
+ }
+ ptr = nextLF(buf, ptr);
+
+ // Skip until the first blank line; that is the end of the binary
+ // encoded information in this hunk. To save time we don't do a
+ // validation of the binary data at this point.
+ //
+ final int sz = buf.length;
+ while (ptr < sz) {
+ final boolean empty = buf[ptr] == '\n';
+ ptr = nextLF(buf, ptr);
+ if (empty)
+ break;
+ }
+
+ return ptr;
+ }
+}
--git a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
index bf8d23a..a6ff4a6 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
@@ -158,6 +158,12 @@
/** The hunks of this file */
private List<HunkHeader> hunks;
+ /** If {@link #patchType} is {@link PatchType#GIT_BINARY}, the new image */
+ BinaryHunk forwardBinaryHunk;
+
+ /** If {@link #patchType} is {@link PatchType#GIT_BINARY}, the old image */
+ BinaryHunk reverseBinaryHunk;
+
FileHeader(final byte[] b, final int offset) {
buf = b;
startOffset = offset;
@@ -270,6 +276,16 @@ void addHunk(final HunkHeader h) {
hunks.add(h);
}
+ /** @return if a {@link PatchType#GIT_BINARY}, the new-image delta/literal */
+ public BinaryHunk getForwardBinaryHunk() {
+ return forwardBinaryHunk;
+ }
+
+ /** @return if a {@link PatchType#GIT_BINARY}, the old-image delta/literal */
+ public BinaryHunk getReverseBinaryHunk() {
+ return reverseBinaryHunk;
+ }
+
/**
* Parse a "diff --git" or "diff --cc" line.
*
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
index 164ad96..56eb327 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
@@ -62,6 +62,8 @@
private static final byte[] BIN_TRAILER = encodeASCII(" differ\n");
+ private static final byte[] GIT_BINARY = encodeASCII("GIT binary patch\n");
+
static final byte[] SIG_FOOTER = encodeASCII("-- \n");
/** The files, in the order they were parsed out of the input. */
@@ -268,6 +270,11 @@ private int parseHunks(final FileHeader fh, int c) {
}
final int eol = nextLF(buf, c);
+ if (fh.getHunks().isEmpty() && match(buf, c, GIT_BINARY) >= 0) {
+ fh.patchType = FileHeader.PatchType.GIT_BINARY;
+ return parseGitBinary(fh, eol);
+ }
+
if (fh.getHunks().isEmpty() && BIN_TRAILER.length < eol - c
&& match(buf, eol - BIN_TRAILER.length, BIN_TRAILER) >= 0
&& matchAny(buf, c, BIN_HEADERS)) {
@@ -295,6 +302,31 @@ private int parseHunks(final FileHeader fh, int c) {
return c;
}
+ private int parseGitBinary(final FileHeader fh, int c) {
+ final BinaryHunk postImage = new BinaryHunk(fh, c);
+ final int nEnd = postImage.parseHunk(c);
+ if (nEnd < 0) {
+ // Not a binary hunk.
+ //
+
+ // TODO handle invalid binary hunks
+ return c;
+ }
+ c = nEnd;
+ postImage.endOffset = c;
+ fh.forwardBinaryHunk = postImage;
+
+ final BinaryHunk preImage = new BinaryHunk(fh, c);
+ final int oEnd = preImage.parseHunk(c);
+ if (oEnd >= 0) {
+ c = oEnd;
+ preImage.endOffset = c;
+ fh.reverseBinaryHunk = preImage;
+ }
+
+ return c;
+ }
+
private static boolean matchAny(final byte[] buf, final int c,
final byte[][] srcs) {
for (final byte[] s : srcs) {
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 11/15] Fix Patch.parse to honor the end point passed in
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-11-git-send-email-spearce@spearce.org>
Otherwise we may over-read the patch script and identify trailer
data as part of a patch when it was requested that we ignore it.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
| 46 +++++++-----
.../src/org/spearce/jgit/patch/BinaryHunk.java | 5 +-
| 16 ++--
| 9 +--
.../src/org/spearce/jgit/patch/Patch.java | 73 ++++++++++----------
5 files changed, 77 insertions(+), 72 deletions(-)
--git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java
index 4c2140a..36c528e 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/FileHeaderTest.java
@@ -45,28 +45,32 @@
public class FileHeaderTest extends TestCase {
public void testParseGitFileName_Empty() {
final FileHeader fh = data("");
- assertEquals(-1, fh.parseGitFileName(0));
+ assertEquals(-1, fh.parseGitFileName(0, fh.buf.length));
assertNotNull(fh.getHunks());
assertTrue(fh.getHunks().isEmpty());
assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_NoLF() {
- assertEquals(-1, data("a/ b/").parseGitFileName(0));
+ final FileHeader fh = data("a/ b/");
+ assertEquals(-1, fh.parseGitFileName(0, fh.buf.length));
}
public void testParseGitFileName_NoSecondLine() {
- assertEquals(-1, data("\n").parseGitFileName(0));
+ final FileHeader fh = data("\n");
+ assertEquals(-1, fh.parseGitFileName(0, fh.buf.length));
}
public void testParseGitFileName_EmptyHeader() {
- assertEquals(1, data("\n\n").parseGitFileName(0));
+ final FileHeader fh = data("\n\n");
+ assertEquals(1, fh.parseGitFileName(0, fh.buf.length));
}
public void testParseGitFileName_Foo() {
final String name = "foo";
final FileHeader fh = header(name);
- assertEquals(gitLine(name).length(), fh.parseGitFileName(0));
+ assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
+ fh.buf.length));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
assertFalse(fh.hasMetaDataChanges());
@@ -74,7 +78,7 @@ public void testParseGitFileName_Foo() {
public void testParseGitFileName_FailFooBar() {
final FileHeader fh = data("a/foo b/bar\n-");
- assertTrue(fh.parseGitFileName(0) > 0);
+ assertTrue(fh.parseGitFileName(0, fh.buf.length) > 0);
assertNull(fh.getOldName());
assertNull(fh.getNewName());
assertFalse(fh.hasMetaDataChanges());
@@ -83,7 +87,8 @@ public void testParseGitFileName_FailFooBar() {
public void testParseGitFileName_FooSpBar() {
final String name = "foo bar";
final FileHeader fh = header(name);
- assertEquals(gitLine(name).length(), fh.parseGitFileName(0));
+ assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
+ fh.buf.length));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
assertFalse(fh.hasMetaDataChanges());
@@ -93,7 +98,8 @@ public void testParseGitFileName_DqFooTabBar() {
final String name = "foo\tbar";
final String dqName = "foo\\tbar";
final FileHeader fh = dqHeader(dqName);
- assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0));
+ assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0,
+ fh.buf.length));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
assertFalse(fh.hasMetaDataChanges());
@@ -103,7 +109,8 @@ public void testParseGitFileName_DqFooSpLfNulBar() {
final String name = "foo \n\0bar";
final String dqName = "foo \\n\\0bar";
final FileHeader fh = dqHeader(dqName);
- assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0));
+ assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0,
+ fh.buf.length));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
assertFalse(fh.hasMetaDataChanges());
@@ -112,7 +119,8 @@ public void testParseGitFileName_DqFooSpLfNulBar() {
public void testParseGitFileName_SrcFooC() {
final String name = "src/foo/bar/argh/code.c";
final FileHeader fh = header(name);
- assertEquals(gitLine(name).length(), fh.parseGitFileName(0));
+ assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
+ fh.buf.length));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
assertFalse(fh.hasMetaDataChanges());
@@ -122,7 +130,7 @@ public void testParseGitFileName_SrcFooCNonStandardPrefix() {
final String name = "src/foo/bar/argh/code.c";
final String header = "project-v-1.0/" + name + " mydev/" + name + "\n";
final FileHeader fh = data(header + "-");
- assertEquals(header.length(), fh.parseGitFileName(0));
+ assertEquals(header.length(), fh.parseGitFileName(0, fh.buf.length));
assertEquals(name, fh.getOldName());
assertSame(fh.getOldName(), fh.getNewName());
assertFalse(fh.hasMetaDataChanges());
@@ -202,12 +210,12 @@ public void testParseRename100_NewStyle() {
+ "similarity index 100%\n"
+ "rename from a\n"
+ "rename to \" c/\\303\\205ngstr\\303\\266m\"\n");
- int ptr = fh.parseGitFileName(0);
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
assertTrue(ptr > 0);
assertNull(fh.getOldName()); // can't parse names on a rename
assertNull(fh.getNewName());
- ptr = fh.parseGitHeaders(ptr);
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
assertTrue(ptr > 0);
assertEquals("a", fh.getOldName());
@@ -231,12 +239,12 @@ public void testParseRename100_OldStyle() {
+ "similarity index 100%\n"
+ "rename old a\n"
+ "rename new \" c/\\303\\205ngstr\\303\\266m\"\n");
- int ptr = fh.parseGitFileName(0);
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
assertTrue(ptr > 0);
assertNull(fh.getOldName()); // can't parse names on a rename
assertNull(fh.getNewName());
- ptr = fh.parseGitHeaders(ptr);
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
assertTrue(ptr > 0);
assertEquals("a", fh.getOldName());
@@ -260,12 +268,12 @@ public void testParseCopy100() {
+ "similarity index 100%\n"
+ "copy from a\n"
+ "copy to \" c/\\303\\205ngstr\\303\\266m\"\n");
- int ptr = fh.parseGitFileName(0);
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
assertTrue(ptr > 0);
assertNull(fh.getOldName()); // can't parse names on a copy
assertNull(fh.getNewName());
- ptr = fh.parseGitHeaders(ptr);
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
assertTrue(ptr > 0);
assertEquals("a", fh.getOldName());
@@ -391,9 +399,9 @@ public void testParseAbbrIndexLine_NoMode() {
}
private static void assertParse(final FileHeader fh) {
- int ptr = fh.parseGitFileName(0);
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
assertTrue(ptr > 0);
- ptr = fh.parseGitHeaders(ptr);
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
assertTrue(ptr > 0);
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java b/org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java
index ce35286..3e07ec4 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/BinaryHunk.java
@@ -91,7 +91,7 @@ public int getSize() {
return length;
}
- int parseHunk(int ptr) {
+ int parseHunk(int ptr, final int end) {
final byte[] buf = file.buf;
if (match(buf, ptr, LITERAL) >= 0) {
@@ -115,8 +115,7 @@ int parseHunk(int ptr) {
// encoded information in this hunk. To save time we don't do a
// validation of the binary data at this point.
//
- final int sz = buf.length;
- while (ptr < sz) {
+ while (ptr < end) {
final boolean empty = buf[ptr] == '\n';
ptr = nextLF(buf, ptr);
if (empty)
--git a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
index a6ff4a6..a58e978 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
@@ -291,12 +291,14 @@ public BinaryHunk getReverseBinaryHunk() {
*
* @param ptr
* first character after the "diff --git " or "diff --cc " part.
+ * @param end
+ * one past the last position to parse.
* @return first character after the LF at the end of the line; -1 on error.
*/
- int parseGitFileName(int ptr) {
+ int parseGitFileName(int ptr, final int end) {
final int eol = nextLF(buf, ptr);
final int bol = ptr;
- if (eol >= buf.length) {
+ if (eol >= end) {
return -1;
}
@@ -353,9 +355,8 @@ int parseGitFileName(int ptr) {
return eol;
}
- int parseGitHeaders(int ptr) {
- final int sz = buf.length;
- while (ptr < sz) {
+ int parseGitHeaders(int ptr, final int end) {
+ while (ptr < end) {
final int eol = nextLF(buf, ptr);
if (match(buf, ptr, HUNK_HDR) >= 0) {
// First hunk header; break out and parse them later.
@@ -428,9 +429,8 @@ int parseGitHeaders(int ptr) {
return ptr;
}
- int parseTraditionalHeaders(int ptr) {
- final int sz = buf.length;
- while (ptr < sz) {
+ int parseTraditionalHeaders(int ptr, final int end) {
+ while (ptr < end) {
final int eol = nextLF(buf, ptr);
if (match(buf, ptr, HUNK_HDR) >= 0) {
// First hunk header; break out and parse them later.
--git a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
index 20dd6e2..4fd9bae 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
@@ -119,7 +119,7 @@ public int getLinesAdded() {
return nAdded;
}
- void parseHeader() {
+ void parseHeader(final int end) {
// Parse "@@ -236,9 +236,9 @@ protected boolean"
//
final byte[] buf = file.buf;
@@ -132,15 +132,14 @@ void parseHeader() {
newLineCount = parseBase10(buf, ptr.value + 1, ptr);
}
- int parseBody(final Patch script) {
+ int parseBody(final Patch script, final int end) {
final byte[] buf = file.buf;
- final int sz = buf.length;
int c = nextLF(buf, startOffset), last = c;
nDeleted = 0;
nAdded = 0;
- SCAN: for (; c < sz; last = c, c = nextLF(buf, c)) {
+ SCAN: for (; c < end; last = c, c = nextLF(buf, c)) {
switch (buf[c]) {
case ' ':
case '\n':
@@ -163,7 +162,7 @@ int parseBody(final Patch script) {
}
}
- if (last < sz && nContext + nDeleted - 1 == oldLineCount
+ if (last < end && nContext + nDeleted - 1 == oldLineCount
&& nContext + nAdded == newLineCount
&& match(buf, last, Patch.SIG_FOOTER) >= 0) {
// This is an extremely common occurrence of "corruption".
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
index 5cc208c..9aca22d 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
@@ -157,12 +157,11 @@ public void parse(final InputStream is) throws IOException {
*/
public void parse(final byte[] buf, int ptr, final int end) {
while (ptr < end)
- ptr = parseFile(buf, ptr);
+ ptr = parseFile(buf, ptr, end);
}
- private int parseFile(final byte[] buf, int c) {
- final int sz = buf.length;
- while (c < sz) {
+ private int parseFile(final byte[] buf, int c, final int end) {
+ while (c < end) {
if (match(buf, c, HUNK_HDR) >= 0) {
// If we find a disconnected hunk header we might
// have missed a file header previously. The hunk
@@ -176,19 +175,19 @@ private int parseFile(final byte[] buf, int c) {
// Valid git style patch?
//
if (match(buf, c, DIFF_GIT) >= 0)
- return parseDiffGit(buf, c);
+ return parseDiffGit(buf, c, end);
if (match(buf, c, DIFF_CC) >= 0)
- return parseDiffCC(buf, c);
+ return parseDiffCC(buf, c, end);
// Junk between files? Leading junk? Traditional
// (non-git generated) patch?
//
final int n = nextLF(buf, c);
- if (n >= sz) {
+ if (n >= end) {
// Patches cannot be only one line long. This must be
// trailing junk that we should ignore.
//
- return sz;
+ return end;
}
if (n - c < 6) {
@@ -204,10 +203,10 @@ private int parseFile(final byte[] buf, int c) {
// a "@@ -0,0" smelling line next. We only check the "@@ -".
//
final int f = nextLF(buf, n);
- if (f >= sz)
- return sz;
+ if (f >= end)
+ return end;
if (match(buf, f, HUNK_HDR) >= 0)
- return parseTraditionalPatch(buf, c);
+ return parseTraditionalPatch(buf, c, end);
}
c = n;
@@ -215,53 +214,53 @@ private int parseFile(final byte[] buf, int c) {
return c;
}
- private int parseDiffGit(final byte[] buf, final int startOffset) {
- final FileHeader fh = new FileHeader(buf, startOffset);
- int ptr = fh.parseGitFileName(startOffset + DIFF_GIT.length);
+ private int parseDiffGit(final byte[] buf, final int start, final int end) {
+ final FileHeader fh = new FileHeader(buf, start);
+ int ptr = fh.parseGitFileName(start + DIFF_GIT.length, end);
if (ptr < 0)
- return skipFile(buf, startOffset);
+ return skipFile(buf, start, end);
- ptr = fh.parseGitHeaders(ptr);
- ptr = parseHunks(fh, ptr);
+ ptr = fh.parseGitHeaders(ptr, end);
+ ptr = parseHunks(fh, ptr, end);
fh.endOffset = ptr;
addFile(fh);
return ptr;
}
- private int parseDiffCC(final byte[] buf, final int startOffset) {
- final FileHeader fh = new FileHeader(buf, startOffset);
- int ptr = fh.parseGitFileName(startOffset + DIFF_CC.length);
+ private int parseDiffCC(final byte[] buf, final int start, final int end) {
+ final FileHeader fh = new FileHeader(buf, start);
+ int ptr = fh.parseGitFileName(start + DIFF_CC.length, end);
if (ptr < 0)
- return skipFile(buf, startOffset);
+ return skipFile(buf, start, end);
// TODO Support parsing diff --cc headers
// TODO parse diff --cc hunks
- warn(buf, startOffset, "diff --cc format not supported");
+ warn(buf, start, "diff --cc format not supported");
fh.endOffset = ptr;
addFile(fh);
return ptr;
}
- private int parseTraditionalPatch(final byte[] buf, final int startOffset) {
- final FileHeader fh = new FileHeader(buf, startOffset);
- int ptr = fh.parseTraditionalHeaders(startOffset);
- ptr = parseHunks(fh, ptr);
+ private int parseTraditionalPatch(final byte[] buf, final int start,
+ final int end) {
+ final FileHeader fh = new FileHeader(buf, start);
+ int ptr = fh.parseTraditionalHeaders(start, end);
+ ptr = parseHunks(fh, ptr, end);
fh.endOffset = ptr;
addFile(fh);
return ptr;
}
- private static int skipFile(final byte[] buf, int ptr) {
+ private static int skipFile(final byte[] buf, int ptr, final int end) {
ptr = nextLF(buf, ptr);
if (match(buf, ptr, OLD_NAME) >= 0)
ptr = nextLF(buf, ptr);
return ptr;
}
- private int parseHunks(final FileHeader fh, int c) {
+ private int parseHunks(final FileHeader fh, int c, final int end) {
final byte[] buf = fh.buf;
- final int sz = buf.length;
- while (c < sz) {
+ while (c < end) {
// If we see a file header at this point, we have all of the
// hunks for our current file. We should stop and report back
// with this position so it can be parsed again later.
@@ -277,11 +276,11 @@ private int parseHunks(final FileHeader fh, int c) {
if (match(buf, c, HUNK_HDR) >= 0) {
final HunkHeader h = new HunkHeader(fh, c);
- h.parseHeader();
- c = h.parseBody(this);
+ h.parseHeader(end);
+ c = h.parseBody(this, end);
h.endOffset = c;
fh.addHunk(h);
- if (c < sz && buf[c] != '@' && buf[c] != 'd'
+ if (c < end && buf[c] != '@' && buf[c] != 'd'
&& match(buf, c, SIG_FOOTER) < 0) {
warn(buf, c, "Unexpected hunk trailer");
}
@@ -291,7 +290,7 @@ private int parseHunks(final FileHeader fh, int c) {
final int eol = nextLF(buf, c);
if (fh.getHunks().isEmpty() && match(buf, c, GIT_BINARY) >= 0) {
fh.patchType = FileHeader.PatchType.GIT_BINARY;
- return parseGitBinary(fh, eol);
+ return parseGitBinary(fh, eol, end);
}
if (fh.getHunks().isEmpty() && BIN_TRAILER.length < eol - c
@@ -321,9 +320,9 @@ private int parseHunks(final FileHeader fh, int c) {
return c;
}
- private int parseGitBinary(final FileHeader fh, int c) {
+ private int parseGitBinary(final FileHeader fh, int c, final int end) {
final BinaryHunk postImage = new BinaryHunk(fh, c);
- final int nEnd = postImage.parseHunk(c);
+ final int nEnd = postImage.parseHunk(c, end);
if (nEnd < 0) {
// Not a binary hunk.
//
@@ -335,7 +334,7 @@ private int parseGitBinary(final FileHeader fh, int c) {
fh.forwardBinaryHunk = postImage;
final BinaryHunk preImage = new BinaryHunk(fh, c);
- final int oEnd = preImage.parseHunk(c);
+ final int oEnd = preImage.parseHunk(c, end);
if (oEnd >= 0) {
c = oEnd;
preImage.endOffset = c;
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 10/15] Record patch parsing errors for later inspection by applications
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-10-git-send-email-spearce@spearce.org>
Errors identified while reading a patch script are now collected
into FormatError objects within the errors collection of a Patch.
These can be inspected to determine if a common form of breakage
is found within the patch script once its basic metadata is read.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../tst/org/spearce/jgit/patch/PatchErrorTest.java | 174 ++++++++++++++++++++
.../tst/org/spearce/jgit/patch/PatchTest.java | 4 +
.../spearce/jgit/patch/testError_BodyTooLong.patch | 17 ++
.../jgit/patch/testError_DisconnectedHunk.patch | 30 ++++
.../jgit/patch/testError_GarbageBetweenFiles.patch | 33 ++++
.../patch/testError_GitBinaryNoForwardHunk.patch | 10 +
.../jgit/patch/testError_TruncatedNew.patch | 15 ++
.../jgit/patch/testError_TruncatedOld.patch | 15 ++
.../src/org/spearce/jgit/patch/FormatError.java | 95 +++++++++++
| 20 ++-
.../src/org/spearce/jgit/patch/Patch.java | 38 ++++-
11 files changed, 441 insertions(+), 10 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchErrorTest.java
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_BodyTooLong.patch
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_DisconnectedHunk.patch
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GarbageBetweenFiles.patch
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GitBinaryNoForwardHunk.patch
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedNew.patch
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedOld.patch
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/patch/FormatError.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchErrorTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchErrorTest.java
new file mode 100644
index 0000000..3d7e6b2
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchErrorTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.patch;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class PatchErrorTest extends TestCase {
+ public void testError_DisconnectedHunk() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ {
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals(
+ "org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
+ fh.getNewName());
+ assertEquals(1, fh.getHunks().size());
+ }
+
+ assertEquals(1, p.getErrors().size());
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Hunk disconnected from file", e.getMessage());
+ assertEquals(18, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -109,4 +109,11 @@ assert"));
+ }
+
+ public void testError_TruncatedOld() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertEquals(1, p.getErrors().size());
+
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Truncated hunk, at least 1 old lines is missing", e
+ .getMessage());
+ assertEquals(313, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -236,9 +236,9 @@ protected "));
+ }
+
+ public void testError_TruncatedNew() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertEquals(1, p.getErrors().size());
+
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Truncated hunk, at least 1 new lines is missing", e
+ .getMessage());
+ assertEquals(313, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -236,9 +236,9 @@ protected "));
+ }
+
+ public void testError_BodyTooLong() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertEquals(1, p.getErrors().size());
+
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.WARNING, e.getSeverity());
+ assertEquals("Hunk header 4:11 does not match body line count of 4:12",
+ e.getMessage());
+ assertEquals(349, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -109,4 +109,11 @@ assert"));
+ }
+
+ public void testError_GarbageBetweenFiles() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(2, p.getFiles().size());
+ {
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals(
+ "org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java",
+ fh.getNewName());
+ assertEquals(1, fh.getHunks().size());
+ }
+ {
+ final FileHeader fh = p.getFiles().get(1);
+ assertEquals(
+ "org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
+ fh.getNewName());
+ assertEquals(1, fh.getHunks().size());
+ }
+
+ assertEquals(1, p.getErrors().size());
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.WARNING, e.getSeverity());
+ assertEquals("Unexpected hunk trailer", e.getMessage());
+ assertEquals(926, e.getOffset());
+ assertEquals("I AM NOT HERE\n", e.getLineText());
+ }
+
+ public void testError_GitBinaryNoForwardHunk() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(2, p.getFiles().size());
+ {
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals("org.spearce.egit.ui/icons/toolbar/fetchd.png", fh
+ .getNewName());
+ assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
+ assertTrue(fh.getHunks().isEmpty());
+ assertNull(fh.getForwardBinaryHunk());
+ }
+ {
+ final FileHeader fh = p.getFiles().get(1);
+ assertEquals("org.spearce.egit.ui/icons/toolbar/fetche.png", fh
+ .getNewName());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.getHunks().isEmpty());
+ assertNull(fh.getForwardBinaryHunk());
+ }
+
+ assertEquals(1, p.getErrors().size());
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Missing forward-image in GIT binary patch", e
+ .getMessage());
+ assertEquals(297, e.getOffset());
+ assertEquals("\n", e.getLineText());
+ }
+
+ private Patch parseTestPatchFile() throws IOException {
+ final String patchFile = getName() + ".patch";
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+}
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
index 453d88e..7c69fff 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/PatchTest.java
@@ -49,11 +49,13 @@
public void testEmpty() {
final Patch p = new Patch();
assertTrue(p.getFiles().isEmpty());
+ assertTrue(p.getErrors().isEmpty());
}
public void testParse_ConfigCaseInsensitive() throws IOException {
final Patch p = parseTestPatchFile();
assertEquals(2, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
final FileHeader fRepositoryConfigTest = p.getFiles().get(0);
final FileHeader fRepositoryConfig = p.getFiles().get(1);
@@ -145,6 +147,7 @@ assertSame(FileHeader.PatchType.UNIFIED, fRepositoryConfig
public void testParse_NoBinary() throws IOException {
final Patch p = parseTestPatchFile();
assertEquals(5, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
for (int i = 0; i < 4; i++) {
final FileHeader fh = p.getFiles().get(i);
@@ -179,6 +182,7 @@ public void testParse_GitBinary() throws IOException {
final Patch p = parseTestPatchFile();
final int[] binsizes = { 359, 393, 372, 404 };
assertEquals(5, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
for (int i = 0; i < 4; i++) {
final FileHeader fh = p.getFiles().get(i);
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_BodyTooLong.patch b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_BodyTooLong.patch
new file mode 100644
index 0000000..1d0b1c4
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_BodyTooLong.patch
@@ -0,0 +1,17 @@
+diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+index da7e704..34ce04a 100644
+--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
++++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+@@ -109,4 +109,11 @@ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
+ }
++
++ public void test006_readCaseInsensitive() throws IOException {
++ final File path = writeTrashFile("config_001", "[Foo]\nBar\n");
++ RepositoryConfig repositoryConfig = new RepositoryConfig(null, path);
++BAD LINE
++ assertEquals(true, repositoryConfig.getBoolean("foo", null, "bar", false));
++ assertEquals("", repositoryConfig.getString("foo", null, "bar"));
++ }
+ }
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_DisconnectedHunk.patch b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_DisconnectedHunk.patch
new file mode 100644
index 0000000..4762928
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_DisconnectedHunk.patch
@@ -0,0 +1,30 @@
+From: A. U. Thor
+
+@@ -109,4 +109,11 @@ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
+ }
++
++ public void test006_readCaseInsensitive() throws IOException {
++ final File path = writeTrashFile("config_001", "[Foo]\nBar\n");
++ RepositoryConfig repositoryConfig = new RepositoryConfig(null, path);
++ assertEquals(true, repositoryConfig.getBoolean("foo", null, "bar", false));
++ assertEquals("", repositoryConfig.getString("foo", null, "bar"));
++ }
+ }
+diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
++ if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equalsIgnoreCase(n) || "true".equalsIgnoreCase(n) || "1".equals(n)) {
+ return true;
+- } else if ("no".equals(n) || "false".equals(n) || "0".equals(n)) {
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GarbageBetweenFiles.patch b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GarbageBetweenFiles.patch
new file mode 100644
index 0000000..163357e
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GarbageBetweenFiles.patch
@@ -0,0 +1,33 @@
+diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+index da7e704..34ce04a 100644
+--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
++++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+@@ -109,4 +109,11 @@ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
+ }
++
++ public void test006_readCaseInsensitive() throws IOException {
++ final File path = writeTrashFile("config_001", "[Foo]\nBar\n");
++ RepositoryConfig repositoryConfig = new RepositoryConfig(null, path);
++ assertEquals(true, repositoryConfig.getBoolean("foo", null, "bar", false));
++ assertEquals("", repositoryConfig.getString("foo", null, "bar"));
++ }
+ }
+I AM NOT HERE
+diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
++ if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equalsIgnoreCase(n) || "true".equalsIgnoreCase(n) || "1".equals(n)) {
+ return true;
+- } else if ("no".equals(n) || "false".equals(n) || "0".equals(n)) {
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GitBinaryNoForwardHunk.patch b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GitBinaryNoForwardHunk.patch
new file mode 100644
index 0000000..e3f3307
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_GitBinaryNoForwardHunk.patch
@@ -0,0 +1,10 @@
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushe.png
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetchd.png b/org.spearce.egit.ui/icons/toolbar/fetchd.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..4433c543f2a52b586a3ed5e31b138244107bc239
+GIT binary patch
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetche.png b/org.spearce.egit.ui/icons/toolbar/fetche.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..0ffeb419e6ab302caa5e58661854b33853dc43dc
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedNew.patch b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedNew.patch
new file mode 100644
index 0000000..6bbb73d
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedNew.patch
@@ -0,0 +1,15 @@
+diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
+ return true;
+- } else if ("no".equals(n) || "false".equals(n) || "0".equals(n)) {
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedOld.patch b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedOld.patch
new file mode 100644
index 0000000..c8fbdc1
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/testError_TruncatedOld.patch
@@ -0,0 +1,15 @@
+diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
++ if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equalsIgnoreCase(n) || "true".equalsIgnoreCase(n) || "1".equals(n)) {
+ return true;
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/FormatError.java b/org.spearce.jgit/src/org/spearce/jgit/patch/FormatError.java
new file mode 100644
index 0000000..e6f0a03
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/FormatError.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.patch;
+
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.util.RawParseUtils;
+
+/** An error in a patch script */
+public class FormatError {
+ /** Classification of an error. */
+ public static enum Severity {
+ /** The error is unexpected, but can be worked around. */
+ WARNING,
+
+ /** The error indicates the script is severely flawed. */
+ ERROR;
+ }
+
+ private final byte[] buf;
+
+ private final int offset;
+
+ private final Severity severity;
+
+ private final String message;
+
+ FormatError(final byte[] buffer, final int ptr, final Severity sev,
+ final String msg) {
+ buf = buffer;
+ offset = ptr;
+ severity = sev;
+ message = msg;
+ }
+
+ /** @return the severity of the error. */
+ public Severity getSeverity() {
+ return severity;
+ }
+
+ /** @return a message describing the error. */
+ public String getMessage() {
+ return message;
+ }
+
+ /** @return the byte buffer holding the patch script. */
+ public byte[] getBuffer() {
+ return buf;
+ }
+
+ /** @return byte offset within {@link #getBuffer()} where the error is */
+ public int getOffset() {
+ return offset;
+ }
+
+ /** @return line of the patch script the error appears on. */
+ public String getLineText() {
+ final int eol = RawParseUtils.nextLF(buf, offset);
+ return RawParseUtils.decode(Constants.CHARSET, buf, offset, eol);
+ }
+}
--git a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
index fc606c3..20dd6e2 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
@@ -132,7 +132,7 @@ void parseHeader() {
newLineCount = parseBase10(buf, ptr.value + 1, ptr);
}
- int parseBody() {
+ int parseBody(final Patch script) {
final byte[] buf = file.buf;
final int sz = buf.length;
int c = nextLF(buf, startOffset), last = c;
@@ -175,9 +175,21 @@ int parseBody() {
return last;
}
- if (nContext + nDeleted != oldLineCount
- || nContext + nAdded != newLineCount) {
- // TODO report on truncated hunk
+ if (nContext + nDeleted < oldLineCount) {
+ final int missingCount = oldLineCount - (nContext + nDeleted);
+ script.error(buf, startOffset, "Truncated hunk, at least "
+ + missingCount + " old lines is missing");
+
+ } else if (nContext + nAdded < newLineCount) {
+ final int missingCount = newLineCount - (nContext + nAdded);
+ script.error(buf, startOffset, "Truncated hunk, at least "
+ + missingCount + " new lines is missing");
+
+ } else if (nContext + nDeleted > oldLineCount
+ || nContext + nAdded > newLineCount) {
+ script.warn(buf, startOffset, "Hunk header " + oldLineCount + ":"
+ + newLineCount + " does not match body line count of "
+ + (nContext + nDeleted) + ":" + (nContext + nAdded));
}
return c;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
index 56eb327..5cc208c 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
@@ -69,9 +69,13 @@
/** The files, in the order they were parsed out of the input. */
private final List<FileHeader> files;
+ /** Formatting errors, if any were identified. */
+ private final List<FormatError> errors;
+
/** Create an empty patch. */
public Patch() {
files = new ArrayList<FileHeader>();
+ errors = new ArrayList<FormatError>(0);
}
/**
@@ -93,6 +97,21 @@ public void addFile(final FileHeader fh) {
}
/**
+ * Add a formatting error to this patch script.
+ *
+ * @param err
+ * the error description.
+ */
+ public void addError(final FormatError err) {
+ errors.add(err);
+ }
+
+ /** @return collection of formatting errors, if any. */
+ public List<FormatError> getErrors() {
+ return errors;
+ }
+
+ /**
* Parse a patch received from an InputStream.
* <p>
* Multiple parse calls on the same instance will concatenate the patch
@@ -149,8 +168,7 @@ private int parseFile(final byte[] buf, int c) {
// have missed a file header previously. The hunk
// isn't valid without knowing where it comes from.
//
-
- // TODO handle a disconnected hunk fragment
+ error(buf, c, "Hunk disconnected from file");
c = nextLF(buf, c);
continue;
}
@@ -218,6 +236,7 @@ private int parseDiffCC(final byte[] buf, final int startOffset) {
// TODO Support parsing diff --cc headers
// TODO parse diff --cc hunks
+ warn(buf, startOffset, "diff --cc format not supported");
fh.endOffset = ptr;
addFile(fh);
return ptr;
@@ -259,12 +278,12 @@ private int parseHunks(final FileHeader fh, int c) {
if (match(buf, c, HUNK_HDR) >= 0) {
final HunkHeader h = new HunkHeader(fh, c);
h.parseHeader();
- c = h.parseBody();
+ c = h.parseBody(this);
h.endOffset = c;
fh.addHunk(h);
if (c < sz && buf[c] != '@' && buf[c] != 'd'
&& match(buf, c, SIG_FOOTER) < 0) {
- // TODO report on noise between hunks, might be an error
+ warn(buf, c, "Unexpected hunk trailer");
}
continue;
}
@@ -308,8 +327,7 @@ private int parseGitBinary(final FileHeader fh, int c) {
if (nEnd < 0) {
// Not a binary hunk.
//
-
- // TODO handle invalid binary hunks
+ error(fh.buf, c, "Missing forward-image in GIT binary patch");
return c;
}
c = nEnd;
@@ -327,6 +345,14 @@ private int parseGitBinary(final FileHeader fh, int c) {
return c;
}
+ void warn(final byte[] buf, final int ptr, final String msg) {
+ addError(new FormatError(buf, ptr, FormatError.Severity.WARNING, msg));
+ }
+
+ void error(final byte[] buf, final int ptr, final String msg) {
+ addError(new FormatError(buf, ptr, FormatError.Severity.ERROR, msg));
+ }
+
private static boolean matchAny(final byte[] buf, final int c,
final byte[][] srcs) {
for (final byte[] s : srcs) {
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 12/15] Correctly handle hunk headers such as "@@ -0,0 +1 @@"
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-12-git-send-email-spearce@spearce.org>
Sometimes these are created for single line file creations.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
| 14 ++++++++++++--
1 files changed, 12 insertions(+), 2 deletions(-)
--git a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
index 4fd9bae..c3bd642 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java
@@ -126,10 +126,20 @@ void parseHeader(final int end) {
final MutableInteger ptr = new MutableInteger();
ptr.value = nextLF(buf, startOffset, ' ');
oldStartLine = -parseBase10(buf, ptr.value, ptr);
- oldLineCount = parseBase10(buf, ptr.value + 1, ptr);
+ if (buf[ptr.value] == ',')
+ oldLineCount = parseBase10(buf, ptr.value + 1, ptr);
+ else {
+ oldLineCount = oldStartLine;
+ oldStartLine = 0;
+ }
newStartLine = parseBase10(buf, ptr.value + 1, ptr);
- newLineCount = parseBase10(buf, ptr.value + 1, ptr);
+ if (buf[ptr.value] == ',')
+ newLineCount = parseBase10(buf, ptr.value + 1, ptr);
+ else {
+ newLineCount = newStartLine;
+ newStartLine = 0;
+ }
}
int parseBody(final Patch script, final int end) {
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 13/15] Patch parse test comparing "git log -p" output to "git log --numstat"
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-13-git-send-email-spearce@spearce.org>
By comparing the output of "git log -p", once parsed by our patch
parser class, to the output of "git log --numstat" we can be quite
certain we are reading the patches from Git with a high degree of
accuracy, at least for typical add/remove sorts of changes (no
rename detection).
Unfortunately two commits in our history produce an off-by-one bug
in git log --numstat. The bug appears to be in log --numstat and
not in JGit as git apply --numstat matches JGit's result, and is
thus also differing from log --numstat. Since this occurs on only
2 commits out of 1,211 processed during the test I'm not worrying
about the difference on these two items. Besides the numbers from
JGit and git apply --numstat look to be more correct.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../spearce/jgit/patch/EGitPatchHistoryTest.java | 221 ++++++++++++++++++++
1 files changed, 221 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.test/exttst/org/spearce/jgit/patch/EGitPatchHistoryTest.java
diff --git a/org.spearce.jgit.test/exttst/org/spearce/jgit/patch/EGitPatchHistoryTest.java b/org.spearce.jgit.test/exttst/org/spearce/jgit/patch/EGitPatchHistoryTest.java
new file mode 100644
index 0000000..d0c2632
--- /dev/null
+++ b/org.spearce.jgit.test/exttst/org/spearce/jgit/patch/EGitPatchHistoryTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.patch;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.util.MutableInteger;
+import org.spearce.jgit.util.RawParseUtils;
+import org.spearce.jgit.util.TemporaryBuffer;
+
+public class EGitPatchHistoryTest extends TestCase {
+ public void testParseHistory() throws Exception {
+ final NumStatReader numstat = new NumStatReader();
+ numstat.read();
+
+ final HashMap<String, HashMap<String, StatInfo>> stats = numstat.stats;
+ assertEquals(1211, stats.size());
+
+ new PatchReader(stats).read();
+ }
+
+ static class StatInfo {
+ int added, deleted;
+ }
+
+ static class PatchReader extends CommitReader {
+ final HashSet<String> offBy1;
+
+ final HashMap<String, HashMap<String, StatInfo>> stats;
+
+ int errors;
+
+ PatchReader(final HashMap<String, HashMap<String, StatInfo>> s)
+ throws IOException {
+ super(new String[] { "-p" });
+ stats = s;
+
+ offBy1 = new HashSet<String>();
+ offBy1.add("9bda5ece6806cd797416eaa47c7b927cc6e9c3b2");
+ }
+
+ @Override
+ void onCommit(String cid, byte[] buf) {
+ final HashMap<String, StatInfo> files = stats.remove(cid);
+ assertNotNull("No files for " + cid, files);
+
+ final Patch p = new Patch();
+ p.parse(buf, 0, buf.length - 1);
+ assertEquals("File count " + cid, files.size(), p.getFiles().size());
+ if (!p.getErrors().isEmpty()) {
+ for (final FormatError e : p.getErrors()) {
+ System.out.println("error " + e.getMessage());
+ System.out.println(" at " + e.getLineText());
+ }
+ dump(buf);
+ fail("Unexpected error in " + cid);
+ }
+
+ for (final FileHeader fh : p.getFiles()) {
+ final String fileName;
+ if (fh.getChangeType() != FileHeader.ChangeType.DELETE)
+ fileName = fh.getNewName();
+ else
+ fileName = fh.getOldName();
+ final StatInfo s = files.remove(fileName);
+ final String nid = fileName + " in " + cid;
+ assertNotNull("No " + nid, s);
+ int added = 0, deleted = 0;
+ for (final HunkHeader h : fh.getHunks()) {
+ added += h.getLinesAdded();
+ deleted += h.getLinesDeleted();
+ }
+
+ if (s.added == added) {
+ //
+ } else if (s.added == added + 1 && offBy1.contains(cid)) {
+ //
+ } else {
+ dump(buf);
+ assertEquals("Added diff in " + nid, s.added, added);
+ }
+
+ if (s.deleted == deleted) {
+ //
+ } else if (s.deleted == deleted + 1 && offBy1.contains(cid)) {
+ //
+ } else {
+ dump(buf);
+ assertEquals("Deleted diff in " + nid, s.deleted, deleted);
+ }
+ }
+ assertTrue("Missed files in " + cid, files.isEmpty());
+ }
+
+ private static void dump(final byte[] buf) {
+ String str;
+ try {
+ str = new String(buf, 0, buf.length - 1, "ISO-8859-1");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ System.out.println("<<" + str + ">>");
+ }
+ }
+
+ static class NumStatReader extends CommitReader {
+ final HashMap<String, HashMap<String, StatInfo>> stats = new HashMap<String, HashMap<String, StatInfo>>();
+
+ NumStatReader() throws IOException {
+ super(new String[] { "--numstat" });
+ }
+
+ @Override
+ void onCommit(String commitId, byte[] buf) {
+ final HashMap<String, StatInfo> files = new HashMap<String, StatInfo>();
+ final MutableInteger ptr = new MutableInteger();
+ while (ptr.value < buf.length) {
+ if (buf[ptr.value] == '\n')
+ break;
+ final StatInfo i = new StatInfo();
+ i.added = RawParseUtils.parseBase10(buf, ptr.value, ptr);
+ i.deleted = RawParseUtils.parseBase10(buf, ptr.value + 1, ptr);
+ final int eol = RawParseUtils.nextLF(buf, ptr.value);
+ final String name = RawParseUtils.decode(Constants.CHARSET,
+ buf, ptr.value + 1, eol - 1);
+ files.put(name, i);
+ ptr.value = eol;
+ }
+ stats.put(commitId, files);
+ }
+ }
+
+ static abstract class CommitReader {
+ private Process proc;
+
+ CommitReader(final String[] args) throws IOException {
+ final String[] realArgs = new String[3 + args.length + 1];
+ realArgs[0] = "git";
+ realArgs[1] = "log";
+ realArgs[2] = "--pretty=format:commit %H";
+ System.arraycopy(args, 0, realArgs, 3, args.length);
+ realArgs[3 + args.length] = "a4b98ed15ea5f165a7aa0f2fd2ea6fcce6710925";
+
+ proc = Runtime.getRuntime().exec(realArgs);
+ proc.getOutputStream().close();
+ proc.getErrorStream().close();
+ }
+
+ void read() throws IOException, InterruptedException {
+ final BufferedReader in = new BufferedReader(new InputStreamReader(
+ proc.getInputStream(), "ISO-8859-1"));
+ String commitId = null;
+ TemporaryBuffer buf = null;
+ for (;;) {
+ String line = in.readLine();
+ if (line == null)
+ break;
+ if (line.startsWith("commit ")) {
+ if (buf != null) {
+ buf.close();
+ onCommit(commitId, buf.toByteArray());
+ buf.destroy();
+ }
+ commitId = line.substring("commit ".length());
+ buf = new TemporaryBuffer();
+ } else if (buf != null) {
+ buf.write(line.getBytes("ISO-8859-1"));
+ buf.write('\n');
+ }
+ }
+ in.close();
+ assertEquals(0, proc.waitFor());
+ proc = null;
+ }
+
+ abstract void onCommit(String commitId, byte[] buf);
+ }
+}
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 14/15] Abstract the hunk header testing into a method
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-14-git-send-email-spearce@spearce.org>
This way we can test for "@@@ -" and "@@@@@@@ -" for combined
diffs in octopus merges. We use the same scan test for the
basic two-way case, as the format is identical but has less
marker characters.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
| 36 +++++++++++++++++--
.../src/org/spearce/jgit/patch/Patch.java | 8 ++--
2 files changed, 36 insertions(+), 8 deletions(-)
--git a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
index a58e978..5fe2acf 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java
@@ -87,8 +87,6 @@
static final byte[] NEW_NAME = encodeASCII("+++ ");
- static final byte[] HUNK_HDR = encodeASCII("@@ -");
-
/** General type of change a single file-level patch describes. */
public static enum ChangeType {
/** Add a new file to the project */
@@ -358,7 +356,7 @@ int parseGitFileName(int ptr, final int end) {
int parseGitHeaders(int ptr, final int end) {
while (ptr < end) {
final int eol = nextLF(buf, ptr);
- if (match(buf, ptr, HUNK_HDR) >= 0) {
+ if (isHunkHdr(buf, ptr, eol) >= 1) {
// First hunk header; break out and parse them later.
break;
@@ -432,7 +430,7 @@ int parseGitHeaders(int ptr, final int end) {
int parseTraditionalHeaders(int ptr, final int end) {
while (ptr < end) {
final int eol = nextLF(buf, ptr);
- if (match(buf, ptr, HUNK_HDR) >= 0) {
+ if (isHunkHdr(buf, ptr, eol) >= 1) {
// First hunk header; break out and parse them later.
break;
@@ -519,4 +517,34 @@ private boolean eq(int aPtr, int aEnd, int bPtr, int bEnd) {
}
return true;
}
+
+ /**
+ * Determine if this is a patch hunk header.
+ *
+ * @param buf
+ * the buffer to scan
+ * @param start
+ * first position in the buffer to evaluate
+ * @param end
+ * last position to consider; usually the end of the buffer (
+ * <code>buf.length</code>) or the first position on the next
+ * line. This is only used to avoid very long runs of '@' from
+ * killing the scan loop.
+ * @return the number of "ancestor revisions" in the hunk header. A
+ * traditional two-way diff ("@@ -...") returns 1; a combined diff
+ * for a 3 way-merge returns 3. If this is not a hunk header, 0 is
+ * returned instead.
+ */
+ static int isHunkHdr(final byte[] buf, final int start, final int end) {
+ int ptr = start;
+ while (ptr < end && buf[ptr] == '@')
+ ptr++;
+ if (ptr - start < 2)
+ return 0;
+ if (ptr == end || buf[ptr++] != ' ')
+ return 0;
+ if (ptr == end || buf[ptr++] != '-')
+ return 0;
+ return (ptr - 3) - start;
+ }
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
index 9aca22d..e1e79b7 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
@@ -38,7 +38,7 @@
package org.spearce.jgit.patch;
import static org.spearce.jgit.lib.Constants.encodeASCII;
-import static org.spearce.jgit.patch.FileHeader.HUNK_HDR;
+import static org.spearce.jgit.patch.FileHeader.isHunkHdr;
import static org.spearce.jgit.patch.FileHeader.NEW_NAME;
import static org.spearce.jgit.patch.FileHeader.OLD_NAME;
import static org.spearce.jgit.util.RawParseUtils.match;
@@ -162,7 +162,7 @@ public void parse(final byte[] buf, int ptr, final int end) {
private int parseFile(final byte[] buf, int c, final int end) {
while (c < end) {
- if (match(buf, c, HUNK_HDR) >= 0) {
+ if (isHunkHdr(buf, c, end) >= 1) {
// If we find a disconnected hunk header we might
// have missed a file header previously. The hunk
// isn't valid without knowing where it comes from.
@@ -205,7 +205,7 @@ private int parseFile(final byte[] buf, int c, final int end) {
final int f = nextLF(buf, n);
if (f >= end)
return end;
- if (match(buf, f, HUNK_HDR) >= 0)
+ if (isHunkHdr(buf, f, end) == 1)
return parseTraditionalPatch(buf, c, end);
}
@@ -274,7 +274,7 @@ private int parseHunks(final FileHeader fh, int c, final int end) {
if (match(buf, c, NEW_NAME) >= 0)
break;
- if (match(buf, c, HUNK_HDR) >= 0) {
+ if (isHunkHdr(buf, c, end) == 1) {
final HunkHeader h = new HunkHeader(fh, c);
h.parseHeader(end);
c = h.parseBody(this, end);
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* [JGIT PATCH 15/15] Treat "diff --combined" the same as "diff --cc"
From: Shawn O. Pearce @ 2008-12-12 2:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1229049981-14152-15-git-send-email-spearce@spearce.org>
According to the git diff manual page these two formats
share the same file structure, so we can parse them with
the same function.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/patch/Patch.java | 15 +++++++++++----
1 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
index e1e79b7..77ae02f 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/Patch.java
@@ -57,6 +57,8 @@
private static final byte[] DIFF_CC = encodeASCII("diff --cc ");
+ private static final byte[] DIFF_COMBINED = encodeASCII("diff --combined ");
+
private static final byte[][] BIN_HEADERS = new byte[][] {
encodeASCII("Binary files "), encodeASCII("Files "), };
@@ -177,7 +179,9 @@ private int parseFile(final byte[] buf, int c, final int end) {
if (match(buf, c, DIFF_GIT) >= 0)
return parseDiffGit(buf, c, end);
if (match(buf, c, DIFF_CC) >= 0)
- return parseDiffCC(buf, c, end);
+ return parseDiffCombined(DIFF_CC, buf, c, end);
+ if (match(buf, c, DIFF_COMBINED) >= 0)
+ return parseDiffCombined(DIFF_COMBINED, buf, c, end);
// Junk between files? Leading junk? Traditional
// (non-git generated) patch?
@@ -227,9 +231,10 @@ private int parseDiffGit(final byte[] buf, final int start, final int end) {
return ptr;
}
- private int parseDiffCC(final byte[] buf, final int start, final int end) {
- final FileHeader fh = new FileHeader(buf, start);
- int ptr = fh.parseGitFileName(start + DIFF_CC.length, end);
+ private int parseDiffCombined(final byte[] hdr, final byte[] buf,
+ final int start, final int end) {
+ final CombinedFileHeader fh = new CombinedFileHeader(buf, start);
+ int ptr = fh.parseGitFileName(start + hdr.length, end);
if (ptr < 0)
return skipFile(buf, start, end);
@@ -269,6 +274,8 @@ private int parseHunks(final FileHeader fh, int c, final int end) {
break;
if (match(buf, c, DIFF_CC) >= 0)
break;
+ if (match(buf, c, DIFF_COMBINED) >= 0)
+ break;
if (match(buf, c, OLD_NAME) >= 0)
break;
if (match(buf, c, NEW_NAME) >= 0)
--
1.6.1.rc2.306.ge5d5e
^ permalink raw reply related
* Re: user-manual.html invalid HTML
From: jidanni @ 2008-12-12 2:47 UTC (permalink / raw)
To: peff; +Cc: git, 507476
In-Reply-To: <20081212023003.GD23128@sigill.intra.peff.net>
>>>>> "JK" == Jeff King <peff@peff.net> writes:
JK> On Fri, Dec 12, 2008 at 04:32:15AM +0800, jidanni@jidanni.org wrote:
>> Please see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=507476
>> Which it turns out didn't get forwarded to git@vger.kernel.org after all.
JK> The versions I build locally have:
JK> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
JK> "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
JK> in each HTML file, which is added by asciidoc. Maybe the package you
JK> are looking at was built with an older version of asciidoc that doesn't
JK> do this (I don't actually know the history of this feature, but it seems
JK> to me that this is something asciidoc should be doing, not git).
JK> -Peff
OK, adding 507476@bugs.debian.org to the CCs.
^ permalink raw reply
* Re: [PATCH 2/3 (edit v2)] gitweb: Cache $parent_commit info in git_blame()
From: Junio C Hamano @ 2008-12-12 3:05 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Nanako Shiraishi, git, Luben Tuikov
In-Reply-To: <200812110133.33124.jnareb@gmail.com>
Jakub Narebski <jnareb@gmail.com> writes:
> ...
> Alternate solutions:
> ~~~~~~~~~~~~~~~~~~~~
> ...
> Acked-by: Luben Tuikov <ltuikov@yahoo.com>
> Signed-off-by: Jakub Narebski <jnareb@gmail.com>
> ---
> On Wed, 10 Dec 2008, Junio C Hamano wrote:
>
>> To recap, I think the commit log for this patch would have been much
>> easier to read if it were presented in this order:
>>
>> a paragraph to establish the context;
>>
>> a paragraph to state what problem it tries to solve;
>>
>> a paragraph (or more) to explain the solution; and finally
>>
>> a paragraph to discuss possible future enhancements.
>
> Like this?
Yes, basically.
The "future possibilities" section might be a bit too heavy, and also
calling it "Alternate solutions" makes it slightly unclear if it is
talking about what is implemented, or only talking about idle speculation
without an actual code (in this case, it is the latter), though.
> Only commit message has changed.
Which is a bit unnice, because it will conflict with the original [3/3]
that I queued already (with a pair of fixes, including but not limited to
the one you sent "Oops, it should have been like this" for).
I can hand wiggle the patch to make it apply, but I'd prefer if I did not
have to do this every time I receive a patch.
I think the conflict was trivial (just a single s/rev/short_rev/) and I
did not make a silly mistake when I fixed it up, but please check the
result on 'pu' after I push the results out.
Thanks.
^ permalink raw reply
* Re: [PATCH v3 3/3] gitweb: Optional grouping of projects by category
From: Sébastien Cevey @ 2008-12-12 3:10 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git, Junio C Hamano, Petr Baudis, Gustavo Sverzut Barbieri
In-Reply-To: <200812120303.56997.jnareb@gmail.com>
At Fri, 12 Dec 2008 03:03:55 +0100, Jakub Narebski wrote:
> And no, we don't need to sort by categories first. Let me explain
> in more detail a bit.
Thanks for the detailed explanation, I understand your preference.
But as you said, it's a bit arbitrary, I think none is completely
obvious.
I don't really have a strong opinion about which is best, but just to
illustrate what made me go for the solution B, let me show another
example:
name / date / cat
1 2006 A
2 2003 B
3 2005 B
4 2003 A
5 2000 A
6 2008 C
7 2007 C
8 2001 B
9 2005 A
We then sort by name and split in pages of N=3 (sorted by cat on each
page):
A:sort(name) split(max=3) subsort(cat)
1 2006 A 4 2003 A 9 2005 A
2 2003 B 5 2000 A 8 2001 B
3 2005 B 6 2008 C 7 2007 C
B:sort(cat) subsort(name) split(max=4)
1 2006 A 9 2005 A 8 2001 B
4 2003 A 2 2003 B 6 2008 C
5 2000 A 3 2005 B 7 2007 C
With B, we have the second top-entry (2) relegated to the second page,
which might be surprising because we ordered by name. But what I find
weird about A is that because of the per-page category sorting, the
"top-sorted entries at the top" isn't true either (page 3). We have
"reshuffled" the result of 'sort(name) split(max=3)' on each page.
To be truly fair to the main sorting, we should not try to group
categories and display the header for each consecutive group of
entries from a distinct category:
A-:sort(name) split(max=3)
1 2006 A 4 2003 A 7 2007 C
2 2003 B 5 2000 A 8 2001 B
3 2005 B 6 2008 C 9 2005 A
Which in this case is painless as it only affects page 3, but it could
lead to a mess of interleaved categories, and we kind of lose the
purpose of category groups in the first place..
The point is that with A, you cannot determine whether you're on the
right page to find project P (even if you know its category) by
checking whether it's in the interval between the top and bottom
entries.
It's perhaps even more apparent if we sort by date:
A:sort(year) split(max=3) subsort(cat)
1 2006 A 9 2005 A 4 2003 A
6 2008 C 3 2005 B 5 2000 A
7 2007 C 2 2003 B 8 2001 B
B:sort(cat) subsort(year) split(max=4)
1 2006 A 4 2003 A 3 2005 B
9 2005 A 8 2001 B 7 2007 C
5 2000 A 2 2003 B 6 2008 C
It feels kind of unnatural that not only projects are not sorted by
date on each page (they are inside categories), but moreover
categories are spread over all pages.
I guess it depends on your use case, and whether categories are
important or known by the user. I personally don't really care (I
never split stuff into pages in the gitweb I use), so I can do a new
version of my patch that does A if you prefer, just let me know. I
just wanted to clarify that both solutions sort of suck :-)
> P.S. It is IMHO better to use
>
> for (my $i = $from; $i <= $to; $i++) {
Ah sorry, I took the words from your earlier email too literally ("we
can [...] use loop $from..$to there"). That's what happens when
pseudocode is actually valid syntax in a language!
Cheers,
--
Sébastien Cevey / inso.cc
^ permalink raw reply
* Re: What's cooking in git.git (Nov 2008, #06; Wed, 26)
From: Junio C Hamano @ 2008-12-12 3:12 UTC (permalink / raw)
To: Daniel Barkalow
Cc: Nguyen Thai Ngoc Duy, Shawn O. Pearce, Johannes Schindelin, git
In-Reply-To: <alpine.LNX.1.00.0812112045120.19665@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
> "git diff" is an ambiguous model for "git grep". It equally describes
> the behavior of "git diff" to say that it treats files outside the
> checkout area as matching the index or to say that it never lists files
> outside the checkout area. On the other hand, there is the question of
> whether "git diff branch1 branch2" shows differences that are outside the
> checkout area, and whether "git log" shows commits that only change things
> outside the checkout area, and "git grep" should match the behavior of
> these.
Sure, but as "sparse" does not (again, "it should not, at least to me")
change the fact that git is about tracking the history of whole tree, not
just a single file, nor just a subset of files, none of these operations
should be affected about what the checkout area is.
^ permalink raw reply
* Re: git-doc CSS dependent, breaks down in text browsers
From: Jeff King @ 2008-12-12 3:33 UTC (permalink / raw)
To: jidanni; +Cc: git, 507475
In-Reply-To: <87wse6zc9x.fsf@jidanni.org>
On Fri, Dec 12, 2008 at 04:29:14AM +0800, jidanni@jidanni.org wrote:
> E.g., pages look like
>
> SYNOPSIS
>
> git-config [<file-option>] [type] [-z|--null] name [value [value_regex]] git-config [<file-option>] [type] --add name
> value git-config [<file-option>] [type] --replace-all name [value [value_regex]] git-config [<file-option>] [type] [-z|
> --null] --get name [value_regex] git-config [<file-option>] [type] [-z|--null] --get-all name [value_regex] git-config...
I think this is another asciidoc issue, as git merely specifies "verse"
format for this section. Probably the most friendly thing to do would be
to use
<pre class="verseblock-content">
instead of
<div class="verseblock-content">
so that non-CSS browsers fall back to preserving the line boundaries
(which is what is making it look so unbearable in your text browser).
But it is definitely something to be fixed in asciidoc, not in the git
documentation.
-Peff
^ permalink raw reply
* Re: What's cooking in git.git (Nov 2008, #06; Wed, 26)
From: Jeff King @ 2008-12-12 3:36 UTC (permalink / raw)
To: Junio C Hamano
Cc: Daniel Barkalow, Nguyen Thai Ngoc Duy, Shawn O. Pearce,
Johannes Schindelin, git
In-Reply-To: <7vmyf29jd6.fsf@gitster.siamese.dyndns.org>
On Thu, Dec 11, 2008 at 07:12:53PM -0800, Junio C Hamano wrote:
> Sure, but as "sparse" does not (again, "it should not, at least to me")
> change the fact that git is about tracking the history of whole tree, not
> just a single file, nor just a subset of files, none of these operations
> should be affected about what the checkout area is.
I agree with Junio here. If you want "git grep foo HEAD^" to ignore
certain files, then sparse _checkout_ is not the right feature. In that
case you want a sparse _repo_, which is not something I think anybody is
seriously working on.
-Peff
^ permalink raw reply
* Saving patches from this list
From: Stefan Näwe @ 2008-12-12 7:27 UTC (permalink / raw)
To: git
I have some kind of a 'meta question' not exactly regarding git.
What's the best way to get patches sent to this list in a form suitable
for 'git am' without subscribing to this list ?
TIA
Stefan
^ permalink raw reply
* Re: Saving patches from this list
From: Johannes Sixt @ 2008-12-12 8:03 UTC (permalink / raw)
To: Stefan Näwe; +Cc: git
In-Reply-To: <loom.20081212T072326-350@post.gmane.org>
Stefan Näwe schrieb:
> What's the best way to get patches sent to this list in a form suitable
> for 'git am' without subscribing to this list ?
Subscribe to gmane.comp.version-control.git on news.gmane.org with your
favorite news reader and browse the list whenever you feel like it.
-- Hannes
^ permalink raw reply
* Re: Saving patches from this list
From: Stefan Näwe @ 2008-12-12 8:28 UTC (permalink / raw)
To: git
In-Reply-To: <49421AEE.8090902@viscovery.net>
Johannes Sixt <j.sixt <at> viscovery.net> writes:
>
> Stefan Näwe schrieb:
> > What's the best way to get patches sent to this list in a form suitable
> > for 'git am' without subscribing to this list ?
>
> Subscribe to gmane.comp.version-control.git on news.gmane.org with your
> favorite news reader and browse the list whenever you feel like it.
Do you know how stubborn firewall administrators can be ?
IOW, that's unfortunately not an option for me.
Regards,
Stefan
^ permalink raw reply
* [PATCH] git-config.txt: fix a typo
From: Jim Meyering @ 2008-12-12 9:00 UTC (permalink / raw)
To: git list
---
Documentation/git-config.txt | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 28e1861..19a8917 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -279,7 +279,7 @@ If you want to know all the values for a multivar, do:
% git config --get-all core.gitproxy
------------
-If you like to live dangerous, you can replace *all* core.gitproxy by a
+If you like to live dangerously, you can replace *all* core.gitproxy by a
new one with
------------
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* Re: Saving patches from this list
From: Mike Ralphson @ 2008-12-12 9:07 UTC (permalink / raw)
To: Stefan Näwe; +Cc: git, Johannes Sixt, Junio C Hamano
In-Reply-To: <loom.20081212T082629-274@post.gmane.org>
2008/12/12 Stefan Näwe <stefan.naewe+git@gmail.com>
>
> Johannes Sixt <j.sixt <at> viscovery.net> writes:
>
> >
> > Stefan Näwe schrieb:
> > > What's the best way to get patches sent to this list in a form suitable
> > > for 'git am' without subscribing to this list ?
> >
> > Subscribe to gmane.comp.version-control.git on news.gmane.org with your
> > favorite news reader and browse the list whenever you feel like it.
>
> Do you know how stubborn firewall administrators can be ?
>
> IOW, that's unfortunately not an option for me.
If it's only the occasional patch - (I see you're on gmail too), show
original and copy-and-paste into an editor with tabs set up
appropriately. Works for me.
Junio's blog[1] shows he's looking at patchwork. Personally I think it
would be fantastic to have a public patchwork server available. It
might avoid the chicken and egg problem in that it's currently easier
(for some people) to get hold of a patch to play with / review only
after it's accepted.
That said, I think including a link to a repo/branch from which the
current version of a patch series could be fetched would be an
amazingly useful addition to most [PATCH 0/n] cover-letters...
Mike
[1] http://gitster.livejournal.com/18696.html
^ permalink raw reply
* Re: [PATCH v3 3/3] gitweb: Optional grouping of projects by category
From: Jakub Narebski @ 2008-12-12 9:26 UTC (permalink / raw)
To: Sébastien Cevey
Cc: git, Junio C Hamano, Petr Baudis, Gustavo Sverzut Barbieri
In-Reply-To: <87y6ymxf4k.wl%seb@cine7.net>
On Fri, 12 Dec 2008, Sébastien Cevey wrote:
> At Fri, 12 Dec 2008 03:03:55 +0100, Jakub Narebski wrote:
>
> > And no, we don't need to sort by categories first. Let me explain
> > in more detail a bit.
>
> Thanks for the detailed explanation, I understand your preference.
> But as you said, it's a bit arbitrary, I think none is completely
> obvious.
First, I feel a bit bad for derailing this patch. Currently gitweb
does not do pagination of projects list; it is not even possible in
a sane way with current way project searching/selecting is implemented.
So the whole build_projlist_by_category() respecting $from and $to is
moot point.
So if we don't use it, even if it is nice to have for the future, we
don't need to pay cost of extra stable sorting.
>
> I don't really have a strong opinion about which is best, but just to
> illustrate what made me go for the solution B, let me show another
> example:
>
> name / date / cat
> 1 2006 A
> 2 2003 B
> 3 2005 B
> 4 2003 A
> 5 2000 A
> 6 2008 C
> 7 2007 C
> 8 2001 B
> 9 2005 A
>
> We then sort by name and split in pages of N=3 (sorted by cat on each
> page):
>
> A:sort(name) split(max=3) subsort(cat)
> 1 2006 A 4 2003 A 9 2005 A
> 2 2003 B 5 2000 A 8 2001 B
> 3 2005 B 6 2008 C 7 2007 C
>
> B:sort(cat) subsort(name) split(max=3)
> 1 2006 A 9 2005 A 8 2001 B
> 4 2003 A 2 2003 B 6 2008 C
> 5 2000 A 3 2005 B 7 2007 C
>
> With B, we have the second top-entry (2) relegated to the second page,
> which might be surprising because we ordered by name. But what I find
> weird about A is that because of the per-page category sorting, the
> "top-sorted entries at the top" isn't true either (page 3). We have
> "reshuffled" the result of 'sort(name) split(max=3)' on each page.
[...]
> It's perhaps even more apparent if we sort by date:
>
> A:sort(year) split(max=3) subsort(cat)
> 1 2006 A 9 2005 A 4 2003 A
> 6 2008 C 3 2005 B 5 2000 A
> 7 2007 C 2 2003 B 8 2001 B
>
> B:sort(cat) subsort(year) split(max=4)
> 1 2006 A 4 2003 A 3 2005 B
> 9 2005 A 8 2001 B 7 2007 C
> 5 2000 A 2 2003 B 6 2008 C
>
> It feels kind of unnatural that not only projects are not sorted by
> date on each page (they are inside categories), but moreover
> categories are spread over all pages.
>
>
> I guess it depends on your use case, and whether categories are
> important or known by the user. I personally don't really care (I
> never split stuff into pages in the gitweb I use), so I can do a new
> version of my patch that does A if you prefer, just let me know. I
> just wanted to clarify that both solutions sort of suck :-)
Well, with version A you can (I think) simply change
foreach my $cat (sort keys %categories) {
to
foreach my $cat (sort
{ cmp_cat($projlist, \%categories, $oi, $a, $b) } keys %categories) {
to have the following output (see the difference on page 3)
A':sort(name) split(max=3) subsort(sort(cat,name))
1 2006 A 4 2003 A 7 2007 C
2 2003 B 5 2000 A 8 2001 B
3 2005 B 6 2008 C 9 2005 A
where sort_cat might be something like (we took advantage that
categories in %categories have at least one project):
sub cmp_cat {
my ($projlist, $cats, $oi, $a, $b) = @_;
my ($aa, $bb);
# projects in categories are sorted, so we can compare first
# project from a category to sort categories in given ordering
$aa = $projlist->{$cats->{$a}[0]};
$bb = $projlist->{$cats->{$b}[0]};
if ($oi->{'type'} eq 'str') {
return $aa->{$oi->{'key'}} cmp $bb->{$oi->{'key'}};
} else {
return $aa->{$oi->{'key'}} <=> $bb->{$oi->{'key'}};
}
}
--
Jakub Narebski
Poland
^ permalink raw reply
* [JGIT PATCH] Fix typos in comments / testcase output
From: Mike Ralphson @ 2008-12-12 10:55 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git, Mike Ralphson, Robin Rosenberg
Signed-off-by: Mike Ralphson <mike@abacus.co.uk>
---
Is it me, or is the actual maintainer of JGIT/EGIT not actually
mentioned anywhere? Apologies if I've got the to and cc round
the wrong way 8-)
This patch is the product of
find . -name "*.java" -type f -exec aspell --mode=ccpp -c {} \;
I would post my aspell wordlists but they're polluted by other
projects...
Possibly also s/packes to/packs so/ in README?
.../org/spearce/egit/core/GitMoveDeleteHook.java | 2 +-
.../org/spearce/jgit/lib/RepositoryTestCase.java | 2 +-
.../spearce/jgit/revwalk/RevCommitParseTest.java | 2 +-
.../spearce/jgit/transport/BundleWriterTest.java | 2 +-
.../spearce/jgit/transport/FetchConnection.java | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/GitMoveDeleteHook.java b/org.spearce.egit.core/src/org/spearce/egit/core/GitMoveDeleteHook.java
index cc4059c..7faa65a 100644
--- a/org.spearce.egit.core/src/org/spearce/egit/core/GitMoveDeleteHook.java
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/GitMoveDeleteHook.java
@@ -122,7 +122,7 @@ public boolean moveFolder(final IResourceTree tree, final IFolder source,
final IFolder destination, final int updateFlags,
final IProgressMonitor monitor) {
// TODO: Implement this. Should be relatively easy, but consider that
- // Eclipse thinks folders are real thinsgs, while Git does not care.
+ // Eclipse thinks folders are real things, while Git does not care.
return FINISH_FOR_ME;
}
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
index 8937145..9e48fde 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/RepositoryTestCase.java
@@ -94,7 +94,7 @@ protected void configure() {
/**
* Utility method to delete a directory recursively. It is
- * also used internally. If a file or directory cannote be removed
+ * also used internally. If a file or directory cannot be removed
* it throws an AssertionFailure.
*
* @param dir
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/revwalk/RevCommitParseTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/revwalk/RevCommitParseTest.java
index 805e29e..9b95924 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/revwalk/RevCommitParseTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/revwalk/RevCommitParseTest.java
@@ -226,7 +226,7 @@ public void testParse_explicit_bad_encoded() throws Exception {
*
* What happens here is that an encoding us given, but data is not encoded
* that way (and we can detect it), so we try other encodings. Here data could
- * actually be decoded in the stated encoding, but we overide using UTF-8.
+ * actually be decoded in the stated encoding, but we override using UTF-8.
*
* @throws Exception
*/
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/BundleWriterTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/BundleWriterTest.java
index 3cfb8b1..f13d25c 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/BundleWriterTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/BundleWriterTest.java
@@ -117,7 +117,7 @@ assertEquals(db.resolve("c").name(), newRepo.resolve("refs/heads/cc")
// Check that we actually needed the first bundle
Repository newRepo2 = createNewEmptyRepo();
fetchResult = fetchFromBundle(newRepo2, bundle);
- fail("We should not be able to fetch from bundle with prerequisistes that are not fulfilled");
+ fail("We should not be able to fetch from bundle with prerequisites that are not fulfilled");
} catch (MissingBundlePrerequisiteException e) {
assertTrue(e.getMessage()
.indexOf(db.resolve("refs/heads/a").name()) >= 0);
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
index 461ad71..a56ca6c 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
@@ -126,7 +126,7 @@ public void fetch(final ProgressMonitor monitor, final Collection<Ref> want)
* able to supply a fully connected graph to the client (although it may
* only be transferring the parts the client does not yet have). Its faster
* to assume such remote peers are well behaved and send the correct
- * response to the client. In such tranports this method returns false.
+ * response to the client. In such transports this method returns false.
*
* @return true if the last fetch had to perform a connectivity check on the
* client side in order to succeed; false if the last fetch assumed
--
1.6.0.2
^ permalink raw reply related
* Re: Clarifying "invalid tag signature file" error message from git filter-branch (and others)
From: Jim Meyering @ 2008-12-12 11:02 UTC (permalink / raw)
To: James Youngman; +Cc: Brandon Casey, git
In-Reply-To: <c5df85930812111559p287ea6afk54a9759302288d5e@mail.gmail.com>
"James Youngman" <jay@gnu.org> wrote:
> On Thu, Dec 11, 2008 at 11:13 PM, Brandon Casey <casey@nrlssc.navy.mil> wrote:
>
>>> Before conversion:
>>> $ git cat-file tag FINDUTILS-4_1-10
>>> object ce25eb352de8dc53a9a7805ba9efc1c9215d28c2
>>> type commit
>>> tag FINDUTILS-4_1-10
>>> tagger Kevin Dalley
>>
>> The tagger field is missing an email address, a timestamp, and a timezone. It
>> should look something like:
>>
>> tagger Kevin Dalley <kevin.dalley@somewhere.com> 1229036026 -0800
>>
>> git-mktag prevents improperly formatted tags from being created by checking
>> that these fields exist and are well formed.
>>
>> If you know the correct values for the missing fields, then you could
>
> Yes for the email address. But as for the timestamp, it's not in
> the tag file; that only contains the sha1.
> There is a timestamp in the object being tagged, is that the timestamp
> you are talking about?
>
> $ git show --pretty=raw ce25eb352de8dc53a9a7805ba9efc1c9215d28c2
> commit ce25eb352de8dc53a9a7805ba9efc1c9215d28c2
> tree 752cca144d39bc55d05fbe304752b274ba22641c
> parent 9a998755249b0c8c47e8657cff712fa506aa30fc
> author Kevin Dalley <kevin@seti.org> 830638152 +0000
> committer Kevin Dalley <kevin@seti.org> 830638152 +0000
>
> *** empty log message ***
>
> diff --git a/debian.Changelog b/debian.Changelog
> index e3541eb..d0cd295 100644
> --- a/debian.Changelog
> +++ b/debian.Changelog
> @@ -1,5 +1,7 @@
> Sat Apr 27 12:29:06 1996 Kevin Dalley
> <kevin@aplysia.iway.aimnet.com (Kevin Dalley)>
>
> + * find.info, find.info-1, find.info-2: updated to match find.texi
> +
> * debian.rules (debian): update debian revision to 10
>
> * getline.c (getstr): verify that nchars_avail is *really* greater
>
>
>
>
>
>> recreate the tags before doing the filter-branch. If they are unknown, it
>> seems valid enough to use the values from the commit that the tag points
>> to.
>>
>> i.e.
>>
>> tagger Kevin Dalley <kevin@seti.org> 830638152 -0000
>>
>> What tool was used to convert this repository to git? It should be corrected
>> to produce valid annotated tags. Especially if it is a tool within git.
>
> I don't know, Jim Meyering will know though, so I CC'ed him.
I used parsecvs, probably with git-master from the date of
the initial conversion (check the archives for actual date).
That was long enough ago that it was almost certainly before
git-mktag learned to be more strict about its inputs.
James, since you're about to rewrite the history, you may want to
start that process from a freshly-cvs-to-git-converted repository.
I'm not very happy about using cvsparse (considering it's not
really being maintained, afaik), so if the git crowd
can recommend something better, I'm all ears.
^ permalink raw reply
* [PATCH] Fix t7606 on Cygwin: for some reasont it does not recognize a "." in PATH
From: Alex Riesen @ 2008-12-12 12:29 UTC (permalink / raw)
To: Git Mailing List; +Cc: Junio C Hamano
[-- Attachment #1: Type: text/plain, Size: 142 bytes --]
The test uses the dot to add custom merge strategies
---
t/t7606-merge-custom.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
[-- Attachment #2: 0001-Fix-t7606-on-Cygwin-it-does-not-recognize-a-.-in.patch --]
[-- Type: application/octet-stream, Size: 759 bytes --]
From 928b2b955bd2ef0e400de698c0c0bcde5e64638b Mon Sep 17 00:00:00 2001
From: Alex Riesen <raa.lkml@gmail.com>
Date: Mon, 29 Sep 2008 17:07:00 +0200
Subject: [PATCH] Fix t7606 on Cygwin: for some reasont it does not recognize a "." in PATH
The test uses the dot to add custom merge strategies
---
t/t7606-merge-custom.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh
index 52a451d..20c0907 100755
--- a/t/t7606-merge-custom.sh
+++ b/t/t7606-merge-custom.sh
@@ -11,7 +11,7 @@ cat >git-merge-theirs <<EOF
eval git read-tree --reset -u \\\$\$#
EOF
chmod +x git-merge-theirs
-PATH=.:$PATH
+PATH=$(pwd):"$PATH"
export PATH
test_expect_success 'setup' '
--
1.6.1.rc2.48.g3c7df
^ permalink raw reply related
* Re: Fwd: after first git clone of linux kernel repository there are changed files in working dir
From: Nick Andrew @ 2008-12-12 13:51 UTC (permalink / raw)
To: rdkrsr; +Cc: git
In-Reply-To: <d304880b0812110958u3da52e4fs7e5154ebe9a353a@mail.gmail.com>
On Thu, Dec 11, 2008 at 06:58:01PM +0100, rdkrsr wrote:
> windows xp and msysgit for this. And the file system is NTFS. I'm
> using dual boot to sporadicly use linux and tried also linux in
> virtual box.
You could use git inside your VirtualBox linux install.
> But both isn't really good. Maybe one day I dare to use
> linux as my primary OS.
It's not scary, really.
Nick.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox