Skip to content

Commit e24b4d0

Browse files
committed
Teach OdbBackend to expose ExistsPrefix
1 parent dc815f8 commit e24b4d0

File tree

3 files changed

+145
-2
lines changed

3 files changed

+145
-2
lines changed

LibGit2Sharp.Tests/OdbBackendFixture.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,50 @@ public void CanPushWithACustomBackend()
177177
}
178178
}
179179

180+
[Fact]
181+
public void CanShortenObjectIdentifier()
182+
{
183+
/*
184+
* $ echo "aabqhq" | git hash-object -t blob --stdin
185+
* dea509d0b3cb8ee0650f6ca210bc83f4678851ba
186+
*
187+
* $ echo "aaazvc" | git hash-object -t blob --stdin
188+
* dea509d097ce692e167dfc6a48a7a280cc5e877e
189+
*/
190+
191+
string path = CloneBareTestRepo();
192+
using (var repo = new Repository(path))
193+
{
194+
repo.ObjectDatabase.AddBackend(new MockOdbBackend(), 5);
195+
196+
repo.Config.Set("core.abbrev", 4);
197+
198+
Blob blob1 = CreateBlob(repo, "aabqhq\n");
199+
Assert.Equal("dea509d0b3cb8ee0650f6ca210bc83f4678851ba", blob1.Sha);
200+
201+
Assert.Equal("dea5", repo.ObjectDatabase.ShortenObjectId(blob1));
202+
Assert.Equal("dea509d0b3cb", repo.ObjectDatabase.ShortenObjectId(blob1, 12));
203+
Assert.Equal("dea509d0b3cb8ee0650f6ca210bc83f4678851b", repo.ObjectDatabase.ShortenObjectId(blob1, 39));
204+
205+
Blob blob2 = CreateBlob(repo, "aaazvc\n");
206+
Assert.Equal("dea509d09", repo.ObjectDatabase.ShortenObjectId(blob2));
207+
Assert.Equal("dea509d09", repo.ObjectDatabase.ShortenObjectId(blob2, 4));
208+
Assert.Equal("dea509d0b", repo.ObjectDatabase.ShortenObjectId(blob1));
209+
Assert.Equal("dea509d0b", repo.ObjectDatabase.ShortenObjectId(blob1, 7));
210+
211+
Assert.Equal("dea509d0b3cb", repo.ObjectDatabase.ShortenObjectId(blob1, 12));
212+
Assert.Equal("dea509d097ce", repo.ObjectDatabase.ShortenObjectId(blob2, 12));
213+
}
214+
}
215+
216+
private static Blob CreateBlob(Repository repo, string content)
217+
{
218+
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
219+
{
220+
return repo.ObjectDatabase.CreateBlob(stream);
221+
}
222+
}
223+
180224
#region MockOdbBackend
181225

182226
private class MockOdbBackend : OdbBackend
@@ -190,6 +234,7 @@ protected override OdbBackendOperations SupportedOperations
190234
OdbBackendOperations.Write |
191235
OdbBackendOperations.WriteStream |
192236
OdbBackendOperations.Exists |
237+
OdbBackendOperations.ExistsPrefix |
193238
OdbBackendOperations.ForEach |
194239
OdbBackendOperations.ReadHeader;
195240
}
@@ -301,6 +346,37 @@ public override bool Exists(ObjectId oid)
301346
return m_objectIdToContent.ContainsKey(oid);
302347
}
303348

349+
public override int ExistsPrefix(string shortSha, out ObjectId found)
350+
{
351+
found = null;
352+
int numFound = 0;
353+
354+
foreach (ObjectId id in m_objectIdToContent.Keys)
355+
{
356+
if (!id.Sha.StartsWith(shortSha))
357+
{
358+
continue;
359+
}
360+
361+
found = id;
362+
numFound++;
363+
364+
if (numFound > 1)
365+
{
366+
found = null;
367+
return (int) ReturnCode.GIT_EAMBIGUOUS;
368+
}
369+
}
370+
371+
if (numFound == 0)
372+
{
373+
found = null;
374+
return (int)ReturnCode.GIT_ENOTFOUND;
375+
}
376+
377+
return (int)ReturnCode.GIT_OK;
378+
}
379+
304380
public override int ReadHeader(ObjectId oid, out int length, out ObjectType objectType)
305381
{
306382
objectType = default(ObjectType);

LibGit2Sharp/Core/GitOdbBackend.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static GitOdbBackend()
3030
public writestream_callback WriteStream;
3131
public readstream_callback ReadStream;
3232
public exists_callback Exists;
33-
public IntPtr ExistsPrefix;
33+
public exists_prefix_callback ExistsPrefix;
3434
public IntPtr Refresh;
3535
public foreach_callback Foreach;
3636
public IntPtr Writepack;
@@ -157,6 +157,23 @@ public delegate bool exists_callback(
157157
IntPtr backend,
158158
ref GitOid oid);
159159

160+
/// <summary>
161+
/// The backend is passed a short OID and the number of characters in that short OID.
162+
/// The backend is asked to return a value that indicates whether or not
163+
/// the object exists in the backing store. The short OID might not be long enough to resolve
164+
/// to just one object. In that case the backend should return GIT_EAMBIGUOUS.
165+
/// </summary>
166+
/// <param name="found_oid">[out] If the call is successful, the backend will write the full OID if the object here.</param>
167+
/// <param name="backend">[in] A pointer to the backend which is being asked to perform the task.</param>
168+
/// <param name="short_oid">[in] The short-form OID which the backend is being asked to look up.</param>
169+
/// <param name="len">[in] The length of the short-form OID (short_oid).</param>
170+
/// <returns>1 if the object exists, 0 if the object doesn't; an error code otherwise.</returns>
171+
public delegate int exists_prefix_callback(
172+
ref GitOid found_oid,
173+
IntPtr backend,
174+
ref GitOid short_oid,
175+
UIntPtr len);
176+
160177
/// <summary>
161178
/// The backend is passed a callback function and a void* to pass through to the callback. The backend is
162179
/// asked to iterate through all objects in the backing store, invoking the callback for each item.

LibGit2Sharp/OdbBackend.cs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ public abstract int WriteStream(
106106
/// </summary>
107107
public abstract bool Exists(ObjectId id);
108108

109+
/// <summary>
110+
/// Requests that this backend check if an object ID exists. The object ID may not be complete (may be a prefix).
111+
/// </summary>
112+
public abstract int ExistsPrefix(string shortSha, out ObjectId found);
113+
109114
/// <summary>
110115
/// Requests that this backend enumerate all items in the backing store.
111116
/// </summary>
@@ -169,6 +174,11 @@ internal IntPtr GitOdbBackendPointer
169174
nativeBackend.Exists = BackendEntryPoints.ExistsCallback;
170175
}
171176

177+
if ((supportedOperations & OdbBackendOperations.ExistsPrefix) != 0)
178+
{
179+
nativeBackend.ExistsPrefix = BackendEntryPoints.ExistsPrefixCallback;
180+
}
181+
172182
if ((supportedOperations & OdbBackendOperations.ForEach) != 0)
173183
{
174184
nativeBackend.Foreach = BackendEntryPoints.ForEachCallback;
@@ -196,6 +206,7 @@ private static class BackendEntryPoints
196206
public static readonly GitOdbBackend.write_callback WriteCallback = Write;
197207
public static readonly GitOdbBackend.writestream_callback WriteStreamCallback = WriteStream;
198208
public static readonly GitOdbBackend.exists_callback ExistsCallback = Exists;
209+
public static readonly GitOdbBackend.exists_prefix_callback ExistsPrefixCallback = ExistsPrefix;
199210
public static readonly GitOdbBackend.foreach_callback ForEachCallback = Foreach;
200211
public static readonly GitOdbBackend.free_callback FreeCallback = Free;
201212

@@ -498,6 +509,40 @@ private static bool Exists(
498509
}
499510
}
500511

512+
private static int ExistsPrefix(
513+
ref GitOid found_oid,
514+
IntPtr backend,
515+
ref GitOid short_oid,
516+
UIntPtr len)
517+
{
518+
OdbBackend odbBackend = MarshalOdbBackend(backend);
519+
if (odbBackend == null)
520+
{
521+
return (int)GitErrorCode.Error;
522+
}
523+
524+
try
525+
{
526+
ObjectId found;
527+
var shortSha = ObjectId.ToString(short_oid.Id, (int)len);
528+
529+
found_oid.Id = ObjectId.Zero.RawId;
530+
int result = odbBackend.ExistsPrefix(shortSha, out found);
531+
532+
if (result == (int) GitErrorCode.Ok)
533+
{
534+
found_oid.Id = found.RawId;
535+
}
536+
537+
return result;
538+
}
539+
catch (Exception ex)
540+
{
541+
Proxy.giterr_set_str(GitErrorCategory.Odb, ex);
542+
return (int)GitErrorCode.Error;
543+
}
544+
}
545+
501546
private static int Foreach(
502547
IntPtr backend,
503548
GitOdbBackend.foreach_callback_callback cb,
@@ -620,10 +665,15 @@ protected enum OdbBackendOperations
620665
/// </summary>
621666
Exists = 64,
622667

668+
/// <summary>
669+
/// This OdbBackend declares that it supports the ExistsPrefix method.
670+
/// </summary>
671+
ExistsPrefix = 128,
672+
623673
/// <summary>
624674
/// This OdbBackend declares that it supports the Foreach method.
625675
/// </summary>
626-
ForEach = 128,
676+
ForEach = 256,
627677
}
628678

629679
/// <summary>

0 commit comments

Comments
 (0)