* [JGIT PATCH 0/3] Introduce AbbreviatedObjectId @ 2008-12-10 23:18 Shawn O. Pearce 2008-12-10 23:18 ` [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings Shawn O. Pearce 0 siblings, 1 reply; 4+ messages in thread From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw) To: Robin Rosenberg; +Cc: git I'm using this new type to handle the "index" line of a git patch file, where object ids are generally shorter than 40 characters and thus aren't parsable by ObjectId. Reading the short id is important because we can validate that a patch applies correctly by computing the SHA-1 of the result and testing it against the abbreviated id read in the "index" line. If the base object SHA-1 matches the abbreviated line then the result of applying the patch must also match; if it doesn't the patch application logic is broken. Shawn O. Pearce (3): Define an abstraction for handling abbreviated SHA-1 strings Add ObjectId.startsWith(AbbreviatedObjectId) Change AnyObjectId.abbreviate() to return AbbreviatedObjectId .../ui/internal/components/RefContentProposal.java | 2 +- .../egit/ui/internal/fetch/FetchResultTable.java | 12 +- .../egit/ui/internal/push/PushResultTable.java | 21 +- .../src/org/spearce/jgit/pgm/Branch.java | 2 +- .../src/org/spearce/jgit/pgm/Fetch.java | 8 +- .../src/org/spearce/jgit/pgm/Push.java | 5 +- .../spearce/jgit/lib/AbbreviatedObjectIdTest.java | 285 ++++++++++++++++++++ .../org/spearce/jgit/lib/AbbreviatedObjectId.java | 262 ++++++++++++++++++ .../src/org/spearce/jgit/lib/AnyObjectId.java | 39 +++- 9 files changed, 608 insertions(+), 28 deletions(-) create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java ^ permalink raw reply [flat|nested] 4+ messages in thread
* [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings 2008-12-10 23:18 [JGIT PATCH 0/3] Introduce AbbreviatedObjectId Shawn O. Pearce @ 2008-12-10 23:18 ` Shawn O. Pearce 2008-12-10 23:18 ` [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId) Shawn O. Pearce 0 siblings, 1 reply; 4+ messages in thread From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw) To: Robin Rosenberg; +Cc: git The AbbreviatedObjectId class parses an abbreviated SHA-1 string into a binary format, permitting it to be more efficiently matched against existing binary ObjectId fields. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- .../spearce/jgit/lib/AbbreviatedObjectIdTest.java | 227 ++++++++++++++++++++ .../org/spearce/jgit/lib/AbbreviatedObjectId.java | 205 ++++++++++++++++++ .../src/org/spearce/jgit/lib/AnyObjectId.java | 2 +- 3 files changed, 433 insertions(+), 1 deletions(-) create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java new file mode 100644 index 0000000..f540f49 --- /dev/null +++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java @@ -0,0 +1,227 @@ +/* + * 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.lib; + +import junit.framework.TestCase; + +public class AbbreviatedObjectIdTest extends TestCase { + public void testEmpty_FromByteArray() { + final AbbreviatedObjectId i; + i = AbbreviatedObjectId.fromString(new byte[] {}, 0, 0); + assertNotNull(i); + assertEquals(0, i.length()); + assertFalse(i.isComplete()); + assertEquals("", i.name()); + } + + public void testEmpty_FromString() { + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(""); + assertNotNull(i); + assertEquals(0, i.length()); + assertFalse(i.isComplete()); + assertEquals("", i.name()); + } + + public void testFull_FromByteArray() { + final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final byte[] b = Constants.encodeASCII(s); + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(b, 0, + b.length); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertTrue(i.isComplete()); + assertEquals(s, i.name()); + + final ObjectId f = i.toObjectId(); + assertNotNull(f); + assertEquals(ObjectId.fromString(s), f); + assertEquals(f.hashCode(), i.hashCode()); + } + + public void testFull_FromString() { + final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertTrue(i.isComplete()); + assertEquals(s, i.name()); + + final ObjectId f = i.toObjectId(); + assertNotNull(f); + assertEquals(ObjectId.fromString(s), f); + assertEquals(f.hashCode(), i.hashCode()); + } + + public void test1_FromString() { + final String s = "7"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test2_FromString() { + final String s = "7b"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test3_FromString() { + final String s = "7b6"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test4_FromString() { + final String s = "7b6e"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test5_FromString() { + final String s = "7b6e8"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test6_FromString() { + final String s = "7b6e80"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test7_FromString() { + final String s = "7b6e806"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test8_FromString() { + final String s = "7b6e8067"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test9_FromString() { + final String s = "7b6e8067e"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void test17_FromString() { + final String s = "7b6e8067ec96acef9"; + final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s); + assertNotNull(i); + assertEquals(s.length(), i.length()); + assertFalse(i.isComplete()); + assertEquals(s, i.name()); + assertNull(i.toObjectId()); + } + + public void testEquals_Short() { + final String s = "7b6e8067"; + final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s); + final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s); + assertNotSame(a, b); + assertTrue(a.hashCode() == b.hashCode()); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + } + + public void testEquals_Full() { + final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s); + final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s); + assertNotSame(a, b); + assertTrue(a.hashCode() == b.hashCode()); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + } + + public void testNotEquals_SameLength() { + final String sa = "7b6e8067"; + final String sb = "7b6e806e"; + final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa); + final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb); + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + } + + public void testNotEquals_DiffLength() { + final String sa = "7b6e8067abcd"; + final String sb = "7b6e8067"; + final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa); + final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb); + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + } +} diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java new file mode 100644 index 0000000..1a8d296 --- /dev/null +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java @@ -0,0 +1,205 @@ +/* + * 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.lib; + +import java.io.UnsupportedEncodingException; + +/** + * A prefix abbreviation of an {@link ObjectId}. + * <p> + * Sometimes Git produces abbreviated SHA-1 strings, using sufficient leading + * digits from the ObjectId name to still be unique within the repository the + * string was generated from. These ids are likely to be unique for a useful + * period of time, especially if they contain at least 6-10 hex digits. + * <p> + * This class converts the hex string into a binary form, to make it more + * efficient for matching against an object. + */ +public class AbbreviatedObjectId { + /** + * Convert an AbbreviatedObjectId from hex characters (US-ASCII). + * + * @param buf + * the US-ASCII buffer to read from. + * @param offset + * position to read the first character from. + * @param end + * one past the last position to read (<code>end-offset</code> is + * the length of the string). + * @return the converted object id. + */ + public static final AbbreviatedObjectId fromString(final byte[] buf, + final int offset, final int end) { + if (end - offset > AnyObjectId.STR_LEN) + throw new IllegalArgumentException("Invalid id"); + return fromHexString(buf, offset, end); + } + + /** + * Convert an AbbreviatedObjectId from hex characters. + * + * @param str + * the string to read from. Must be <= 40 characters. + * @return the converted object id. + */ + public static final AbbreviatedObjectId fromString(final String str) { + if (str.length() > AnyObjectId.STR_LEN) + throw new IllegalArgumentException("Invalid id: " + str); + final byte[] b = Constants.encodeASCII(str); + return fromHexString(b, 0, b.length); + } + + private static final AbbreviatedObjectId fromHexString(final byte[] bs, + int ptr, final int end) { + try { + final int a = hexUInt32(bs, ptr, end); + final int b = hexUInt32(bs, ptr + 8, end); + final int c = hexUInt32(bs, ptr + 16, end); + final int d = hexUInt32(bs, ptr + 24, end); + final int e = hexUInt32(bs, ptr + 32, end); + return new AbbreviatedObjectId(end - ptr, a, b, c, d, e); + } catch (ArrayIndexOutOfBoundsException e1) { + try { + final String str = new String(bs, ptr, end - ptr, "US-ASCII"); + throw new IllegalArgumentException("Invalid id: " + str); + } catch (UnsupportedEncodingException e2) { + throw new IllegalArgumentException("Invalid id"); + } + } + } + + private static final int hexUInt32(final byte[] bs, int p, final int end) { + if (8 <= end - p) + return AnyObjectId.hexUInt32(bs, p); + + int r = 0, n = 0; + while (n < 8 && p < end) { + final int v = AnyObjectId.fromhex[bs[p++]]; + if (v < 0) + throw new ArrayIndexOutOfBoundsException(); + r <<= 4; + r |= v; + n++; + } + return r << (8 - n) * 4; + } + + /** Number of half-bytes used by this id. */ + final int nibbles; + + final int w1; + + final int w2; + + final int w3; + + final int w4; + + final int w5; + + private AbbreviatedObjectId(final int n, final int new_1, final int new_2, + final int new_3, final int new_4, final int new_5) { + nibbles = n; + w1 = new_1; + w2 = new_2; + w3 = new_3; + w4 = new_4; + w5 = new_5; + } + + /** @return number of hex digits appearing in this id */ + public int length() { + return nibbles; + } + + /** @return true if this ObjectId is actually a complete id. */ + public boolean isComplete() { + return length() == AnyObjectId.RAW_LEN * 2; + } + + /** @return a complete ObjectId; null if {@link #isComplete()} is false */ + public ObjectId toObjectId() { + return isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null; + } + + @Override + public int hashCode() { + return w2; + } + + @Override + public boolean equals(final Object o) { + if (o instanceof AbbreviatedObjectId) { + final AbbreviatedObjectId b = (AbbreviatedObjectId) o; + return nibbles == b.nibbles && w1 == b.w1 && w2 == b.w2 + && w3 == b.w3 && w4 == b.w4 && w5 == b.w5; + } + return false; + } + + /** + * @return string form of the abbreviation, in lower case hexadecimal. + */ + public final String name() { + final char[] b = new char[AnyObjectId.STR_LEN]; + + AnyObjectId.formatHexChar(b, 0, w1); + if (nibbles <= 8) + return new String(b, 0, nibbles); + + AnyObjectId.formatHexChar(b, 8, w2); + if (nibbles <= 16) + return new String(b, 0, nibbles); + + AnyObjectId.formatHexChar(b, 16, w3); + if (nibbles <= 24) + return new String(b, 0, nibbles); + + AnyObjectId.formatHexChar(b, 24, w4); + if (nibbles <= 32) + return new String(b, 0, nibbles); + + AnyObjectId.formatHexChar(b, 32, w5); + return new String(b, 0, nibbles); + } + + @Override + public String toString() { + return "AbbreviatedObjectId[" + name() + "]"; + } +} diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java index a534202..e88e09d 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java @@ -396,7 +396,7 @@ private void toHexCharArray(final char[] dst) { private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - private static void formatHexChar(final char[] dst, final int p, int w) { + static void formatHexChar(final char[] dst, final int p, int w) { int o = p + 7; while (o >= p && w != 0) { dst[o--] = hexchar[w & 0xf]; -- 1.6.1.rc2.299.gead4c ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId) 2008-12-10 23:18 ` [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings Shawn O. Pearce @ 2008-12-10 23:18 ` Shawn O. Pearce 2008-12-10 23:18 ` [JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId Shawn O. Pearce 0 siblings, 1 reply; 4+ messages in thread From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw) To: Robin Rosenberg; +Cc: git This test can be useful to determine if the object id at least begins with an abbreviated id. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- .../spearce/jgit/lib/AbbreviatedObjectIdTest.java | 58 ++++++++++++++++++++ .../org/spearce/jgit/lib/AbbreviatedObjectId.java | 57 +++++++++++++++++++ .../src/org/spearce/jgit/lib/AnyObjectId.java | 11 ++++ 3 files changed, 126 insertions(+), 0 deletions(-) diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java index f540f49..3f82d50 100644 --- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java +++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java @@ -224,4 +224,62 @@ public void testNotEquals_DiffLength() { assertFalse(a.equals(b)); assertFalse(b.equals(a)); } + + public void testPrefixCompare_Full() { + final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s1); + final ObjectId i1 = ObjectId.fromString(s1); + assertEquals(0, a.prefixCompare(i1)); + assertTrue(i1.startsWith(a)); + + final String s2 = "7b6e8067ec96acef9a4184b43210d583b6d2f99b"; + final ObjectId i2 = ObjectId.fromString(s2); + assertTrue(a.prefixCompare(i2) < 0); + assertFalse(i2.startsWith(a)); + + final String s3 = "7b6e8067ec96acef9a4184b43210d583b6d2f999"; + final ObjectId i3 = ObjectId.fromString(s3); + assertTrue(a.prefixCompare(i3) > 0); + assertFalse(i3.startsWith(a)); + } + + public void testPrefixCompare_1() { + final String sa = "7"; + final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa); + + final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final ObjectId i1 = ObjectId.fromString(s1); + assertEquals(0, a.prefixCompare(i1)); + assertTrue(i1.startsWith(a)); + + final String s2 = "8b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final ObjectId i2 = ObjectId.fromString(s2); + assertTrue(a.prefixCompare(i2) < 0); + assertFalse(i2.startsWith(a)); + + final String s3 = "6b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final ObjectId i3 = ObjectId.fromString(s3); + assertTrue(a.prefixCompare(i3) > 0); + assertFalse(i3.startsWith(a)); + } + + public void testPrefixCompare_17() { + final String sa = "7b6e8067ec96acef9"; + final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa); + + final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a"; + final ObjectId i1 = ObjectId.fromString(s1); + assertEquals(0, a.prefixCompare(i1)); + assertTrue(i1.startsWith(a)); + + final String s2 = "7b6e8067eca6acef9a4184b43210d583b6d2f99a"; + final ObjectId i2 = ObjectId.fromString(s2); + assertTrue(a.prefixCompare(i2) < 0); + assertFalse(i2.startsWith(a)); + + final String s3 = "7b6e8067ec86acef9a4184b43210d583b6d2f99a"; + final ObjectId i3 = ObjectId.fromString(s3); + assertTrue(a.prefixCompare(i3) > 0); + assertFalse(i3.startsWith(a)); + } } diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java index 1a8d296..206cc2f 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java @@ -39,6 +39,8 @@ import java.io.UnsupportedEncodingException; +import org.spearce.jgit.util.NB; + /** * A prefix abbreviation of an {@link ObjectId}. * <p> @@ -119,6 +121,24 @@ private static final int hexUInt32(final byte[] bs, int p, final int end) { return r << (8 - n) * 4; } + static int mask(final int nibbles, final int word, final int v) { + final int b = (word - 1) * 8; + if (b + 8 <= nibbles) { + // We have all of the bits required for this word. + // + return v; + } + + if (nibbles < b) { + // We have none of the bits required for this word. + // + return 0; + } + + final int s = 32 - (nibbles - b) * 4; + return (v >>> s) << s; + } + /** Number of half-bytes used by this id. */ final int nibbles; @@ -157,6 +177,43 @@ public ObjectId toObjectId() { return isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null; } + /** + * Compares this abbreviation to a full object id. + * + * @param other + * the other object id. + * @return <0 if this abbreviation names an object that is less than + * <code>other</code>; 0 if this abbreviation exactly matches the + * first {@link #length()} digits of <code>other.name()</code>; + * >0 if this abbreviation names an object that is after + * <code>other</code>. + */ + public int prefixCompare(final AnyObjectId other) { + int cmp; + + cmp = NB.compareUInt32(w1, mask(1, other.w1)); + if (cmp != 0) + return cmp; + + cmp = NB.compareUInt32(w2, mask(2, other.w2)); + if (cmp != 0) + return cmp; + + cmp = NB.compareUInt32(w3, mask(3, other.w3)); + if (cmp != 0) + return cmp; + + cmp = NB.compareUInt32(w4, mask(4, other.w4)); + if (cmp != 0) + return cmp; + + return NB.compareUInt32(w5, mask(5, other.w5)); + } + + private int mask(final int word, final int v) { + return mask(nibbles, word, v); + } + @Override public int hashCode() { return w2; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java index e88e09d..8872017 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java @@ -226,6 +226,17 @@ int compareTo(final int[] bs, final int p) { return NB.compareUInt32(w5, bs[p + 4]); } + /** + * Tests if this ObjectId starts with the given abbreviation. + * + * @param abbr + * the abbreviation. + * @return true if this ObjectId begins with the abbreviation; else false. + */ + public boolean startsWith(final AbbreviatedObjectId abbr) { + return abbr.prefixCompare(this) == 0; + } + public int hashCode() { return w2; } -- 1.6.1.rc2.299.gead4c ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId 2008-12-10 23:18 ` [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId) Shawn O. Pearce @ 2008-12-10 23:18 ` Shawn O. Pearce 0 siblings, 0 replies; 4+ messages in thread From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw) To: Robin Rosenberg; +Cc: git By returning our abstraction type we can reuse the logic inside AbbreviatedObjectId to format the abbreviated string. A result can also be used to test against another ObjectId. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> --- .../ui/internal/components/RefContentProposal.java | 2 +- .../egit/ui/internal/fetch/FetchResultTable.java | 12 ++++---- .../egit/ui/internal/push/PushResultTable.java | 21 ++++++++------- .../src/org/spearce/jgit/pgm/Branch.java | 2 +- .../src/org/spearce/jgit/pgm/Fetch.java | 8 +++--- .../src/org/spearce/jgit/pgm/Push.java | 5 ++- .../org/spearce/jgit/lib/AbbreviatedObjectId.java | 4 +- .../src/org/spearce/jgit/lib/AnyObjectId.java | 26 +++++++++++++++++-- 8 files changed, 51 insertions(+), 29 deletions(-) diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java index 60abaf3..b63c428 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java @@ -111,7 +111,7 @@ public String getDescription() { final StringBuilder sb = new StringBuilder(); sb.append(refName); sb.append('\n'); - sb.append(objectId.abbreviate(db)); + sb.append(objectId.abbreviate(db).name()); sb.append(" - "); if (obj instanceof Commit) { final Commit c = ((Commit) obj); diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java index 868ca94..f1169d1 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java @@ -137,15 +137,15 @@ else if (tru.getLocalName().startsWith(Constants.R_TAGS)) } if (r == RefUpdate.Result.FORCED) { - final String aOld = tru.getOldObjectId().abbreviate(db); - final String aNew = tru.getNewObjectId().abbreviate(db); - return aOld + "..." + aNew; //$NON-NLS-1$ + final String o = tru.getOldObjectId().abbreviate(db).name(); + final String n = tru.getNewObjectId().abbreviate(db).name(); + return o + "..." + n; //$NON-NLS-1$ } if (r == RefUpdate.Result.FAST_FORWARD) { - final String aOld = tru.getOldObjectId().abbreviate(db); - final String aNew = tru.getNewObjectId().abbreviate(db); - return aOld + ".." + aNew; //$NON-NLS-1$ + final String o = tru.getOldObjectId().abbreviate(db).name(); + final String n = tru.getNewObjectId().abbreviate(db).name(); + return o + ".." + n; //$NON-NLS-1$ } if (r == RefUpdate.Result.REJECTED) diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java index c5e476b..6f460dc 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java @@ -233,9 +233,9 @@ public String getText(Object element) { return UIText.PushResultTable_statusOkNewBranch; } - return oldRef.getObjectId().abbreviate(localDb) + return oldRef.getObjectId().abbreviate(localDb).name() + (rru.isFastForward() ? ".." : "...") - + rru.getNewObjectId().abbreviate(localDb); + + rru.getNewObjectId().abbreviate(localDb).name(); case UP_TO_DATE: return UIText.PushResultTable_statusUpToDate; case NON_EXISTING: @@ -289,7 +289,7 @@ public String getToolTipText(Object element) { case OK: if (rru.isDelete()) return NLS.bind(UIText.PushResultTable_statusDetailDeleted, - oldRef.getObjectId().abbreviate(localDb)); + oldRef.getObjectId().abbreviate(localDb).name()); if (oldRef == null) return null; if (rru.isFastForward()) @@ -305,20 +305,21 @@ public String getToolTipText(Object element) { return UIText.PushResultTable_statusDetailNonFastForward; case REJECTED_REMOTE_CHANGED: final Ref remoteRef = oldRef; - final String currentValue; + final String curVal; if (remoteRef == null) - currentValue = UIText.PushResultTable_refNonExisting; + curVal = UIText.PushResultTable_refNonExisting; else - currentValue = remoteRef.getObjectId().abbreviate(localDb); + curVal = remoteRef.getObjectId().abbreviate(localDb).name(); + final ObjectId expectedOldObjectId = rru .getExpectedOldObjectId(); - final String expectedValue; + final String expVal; if (expectedOldObjectId.equals(ObjectId.zeroId())) - expectedValue = UIText.PushResultTable_refNonExisting; + expVal = UIText.PushResultTable_refNonExisting; else - expectedValue = expectedOldObjectId.abbreviate(localDb); + expVal = expectedOldObjectId.abbreviate(localDb).name(); return NLS.bind(UIText.PushResultTable_statusDetailChanged, - currentValue, expectedValue); + curVal, expVal); case REJECTED_OTHER_REASON: return rru.getMessage(); default: diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java index db0aab8..11002f0 100644 --- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java +++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java @@ -167,7 +167,7 @@ private void printHead(final String ref, final boolean isCurrent, final int spaces = maxNameLength - ref.length() + 1; out.print(String.format("%" + spaces + "s", "")); final ObjectId objectId = refObj.getObjectId(); - out.print(objectId.abbreviate(db)); + out.print(objectId.abbreviate(db).name()); out.print(' '); out.print(rw.parseCommit(objectId).getShortMessage()); } diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java index ad7e08f..e9d3260 100644 --- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java +++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java @@ -131,14 +131,14 @@ else if (u.getLocalName().startsWith(Constants.R_TAGS)) } if (r == RefUpdate.Result.FORCED) { - final String aOld = u.getOldObjectId().abbreviate(db); - final String aNew = u.getNewObjectId().abbreviate(db); + final String aOld = u.getOldObjectId().abbreviate(db).name(); + final String aNew = u.getNewObjectId().abbreviate(db).name(); return aOld + "..." + aNew; } if (r == RefUpdate.Result.FAST_FORWARD) { - final String aOld = u.getOldObjectId().abbreviate(db); - final String aNew = u.getNewObjectId().abbreviate(db); + final String aOld = u.getOldObjectId().abbreviate(db).name(); + final String aNew = u.getNewObjectId().abbreviate(db).name(); return aOld + ".." + aNew; } diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java index 53ad080..19d31a1 100644 --- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java +++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java @@ -181,8 +181,9 @@ private void printRefUpdateResult(final URIish uri, boolean fastForward = rru.isFastForward(); final char flag = fastForward ? ' ' : '+'; final String summary = oldRef.getObjectId().abbreviate(db) + .name() + (fastForward ? ".." : "...") - + rru.getNewObjectId().abbreviate(db); + + rru.getNewObjectId().abbreviate(db).name(); final String message = fastForward ? null : "forced update"; printUpdateLine(flag, summary, srcRef, remoteName, message); } @@ -205,7 +206,7 @@ printUpdateLine('!', "[rejected]", srcRef, remoteName, case REJECTED_REMOTE_CHANGED: final String message = "remote ref object changed - is not expected one " - + rru.getExpectedOldObjectId().abbreviate(db); + + rru.getExpectedOldObjectId().abbreviate(db).name(); printUpdateLine('!', "[rejected]", srcRef, remoteName, message); break; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java index 206cc2f..33b62b9 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java @@ -52,7 +52,7 @@ * This class converts the hex string into a binary form, to make it more * efficient for matching against an object. */ -public class AbbreviatedObjectId { +public final class AbbreviatedObjectId { /** * Convert an AbbreviatedObjectId from hex characters (US-ASCII). * @@ -152,7 +152,7 @@ static int mask(final int nibbles, final int word, final int v) { final int w5; - private AbbreviatedObjectId(final int n, final int new_1, final int new_2, + AbbreviatedObjectId(final int n, final int new_1, final int new_2, final int new_3, final int new_4, final int new_5) { nibbles = n; w1 = new_1; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java index 8872017..7d7d61b 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java @@ -432,16 +432,36 @@ public final String name() { /** * Return unique abbreviation (prefix) of this object SHA-1. * <p> + * This method is a utility for <code>abbreviate(repo, 8)</code>. + * + * @param repo + * repository for checking uniqueness within. + * @return SHA-1 abbreviation. + */ + public AbbreviatedObjectId abbreviate(final Repository repo) { + return abbreviate(repo, 8); + } + + /** + * Return unique abbreviation (prefix) of this object SHA-1. + * <p> * Current implementation is not guaranteeing uniqueness, it just returns * fixed-length prefix of SHA-1 string. - * + * * @param repo * repository for checking uniqueness within. + * @param len + * minimum length of the abbreviated string. * @return SHA-1 abbreviation. */ - public String abbreviate(final Repository repo) { + public AbbreviatedObjectId abbreviate(final Repository repo, final int len) { // TODO implement checking for uniqueness - return name().substring(0, 7); + final int a = AbbreviatedObjectId.mask(len, 1, w1); + final int b = AbbreviatedObjectId.mask(len, 2, w2); + final int c = AbbreviatedObjectId.mask(len, 3, w3); + final int d = AbbreviatedObjectId.mask(len, 4, w4); + final int e = AbbreviatedObjectId.mask(len, 5, w5); + return new AbbreviatedObjectId(len, a, b, c, d, e); } /** -- 1.6.1.rc2.299.gead4c ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-12-10 23:20 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-12-10 23:18 [JGIT PATCH 0/3] Introduce AbbreviatedObjectId Shawn O. Pearce 2008-12-10 23:18 ` [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings Shawn O. Pearce 2008-12-10 23:18 ` [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId) Shawn O. Pearce 2008-12-10 23:18 ` [JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId Shawn O. Pearce
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).