diff --git a/LibGit2Sharp.Tests/BlobFixture.cs b/LibGit2Sharp.Tests/BlobFixture.cs index 7afbe255f..3c5a3208a 100644 --- a/LibGit2Sharp.Tests/BlobFixture.cs +++ b/LibGit2Sharp.Tests/BlobFixture.cs @@ -15,6 +15,7 @@ public void CanGetBlobAsText() using (var repo = new Repository(path)) { var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); + Assert.False(blob.IsMissing); var text = blob.GetContentText(); @@ -36,6 +37,7 @@ public void CanGetBlobAsFilteredText(string autocrlf, string expectedText) repo.Config.Set("core.autocrlf", autocrlf); var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); + Assert.False(blob.IsMissing); var text = blob.GetContentText(new FilteringOptions("foo.txt")); @@ -67,6 +69,7 @@ public void CanGetBlobAsTextWithVariousEncodings(string encodingName, int expect var commit = repo.Commit("bom", Constants.Signature, Constants.Signature); var blob = (Blob)commit.Tree[bomFile].Target; + Assert.False(blob.IsMissing); Assert.Equal(expectedContentBytes, blob.Size); using (var stream = blob.GetContentStream()) { @@ -92,6 +95,7 @@ public void CanGetBlobSize() using (var repo = new Repository(path)) { var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); + Assert.False(blob.IsMissing); Assert.Equal(10, blob.Size); } } @@ -104,6 +108,7 @@ public void CanLookUpBlob() { var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); Assert.NotNull(blob); + Assert.False(blob.IsMissing); } } @@ -114,6 +119,7 @@ public void CanReadBlobStream() using (var repo = new Repository(path)) { var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); + Assert.False(blob.IsMissing); var contentStream = blob.GetContentStream(); Assert.Equal(blob.Size, contentStream.Length); @@ -140,6 +146,7 @@ public void CanReadBlobFilteredStream(string autocrlf, string expectedContent) repo.Config.Set("core.autocrlf", autocrlf); var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); + Assert.False(blob.IsMissing); var contentStream = blob.GetContentStream(new FilteringOptions("foo.txt")); Assert.Equal(expectedContent.Length, contentStream.Length); @@ -164,6 +171,7 @@ public void CanReadBlobFilteredStreamOfUnmodifiedBinary() using (var stream = new MemoryStream(binaryContent)) { Blob blob = repo.ObjectDatabase.CreateBlob(stream); + Assert.False(blob.IsMissing); using (var filtered = blob.GetContentStream(new FilteringOptions("foo.txt"))) { @@ -196,6 +204,7 @@ public void CanStageAFileGeneratedFromABlobContentStream() Assert.Equal("baae1fb3760a73481ced1fa03dc15614142c19ef", entry.Id.Sha); var blob = repo.Lookup(entry.Id.Sha); + Assert.False(blob.IsMissing); using (Stream stream = blob.GetContentStream()) using (Stream file = File.OpenWrite(Path.Combine(repo.Info.WorkingDirectory, "small.fromblob.txt"))) @@ -217,10 +226,35 @@ public void CanTellIfTheBlobContentLooksLikeBinary() using (var repo = new Repository(path)) { var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); + Assert.False(blob.IsMissing); Assert.False(blob.IsBinary); } } + [Fact] + public void CanTellIsABlobIsMissing() + { + string repoPath = SandboxBareTestRepo(); + + // Manually delete the objects directory to simulate a partial clone + Directory.Delete(Path.Combine(repoPath, "objects", "a8"), true); + + using (var repo = new Repository(repoPath)) + { + // Look for the commit that reference the blob which is now missing + var commit = repo.Lookup("4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); + var blob = (Blob) commit.Tree["README"].Target; + + Assert.Equal("a8233120f6ad708f843d861ce2b7228ec4e3dec6", blob.Sha); + Assert.NotNull(blob); + Assert.True(blob.IsMissing); + Assert.Throws(() => blob.Size); + Assert.Throws(() => blob.IsBinary); + Assert.Throws(() => blob.GetContentText()); + Assert.Throws(() => blob.GetContentText(new FilteringOptions("foo.txt"))); + } + } + private static void SkipIfNotSupported(string autocrlf) { InconclusiveIf(() => autocrlf == "true" && Constants.IsRunningOnUnix, "Non-Windows does not support core.autocrlf = true"); diff --git a/LibGit2Sharp/Blob.cs b/LibGit2Sharp/Blob.cs index aa02925ec..73ddbda87 100644 --- a/LibGit2Sharp/Blob.cs +++ b/LibGit2Sharp/Blob.cs @@ -28,7 +28,7 @@ internal Blob(Repository repo, ObjectId id) { lazySize = GitObjectLazyGroup.Singleton(repo, id, Proxy.git_blob_rawsize); lazyIsBinary = GitObjectLazyGroup.Singleton(repo, id, Proxy.git_blob_is_binary); - lazyIsMissing = GitObjectLazyGroup.Singleton(repo, id, handle => handle == null); + lazyIsMissing = GitObjectLazyGroup.Singleton(repo, id, handle => handle == null, throwsIfMissing: false); } /// diff --git a/LibGit2Sharp/Core/GitObjectLazyGroup.cs b/LibGit2Sharp/Core/GitObjectLazyGroup.cs index 8f6bbf888..d6beeb6af 100644 --- a/LibGit2Sharp/Core/GitObjectLazyGroup.cs +++ b/LibGit2Sharp/Core/GitObjectLazyGroup.cs @@ -18,20 +18,20 @@ protected override void EvaluateInternal(Action evaluator) using (var osw = new ObjectSafeWrapper(id, repo.Handle)) { if (osw.ObjectPtr == null) - throw new NotFoundException($"Object {id} is not available"); + throw new NotFoundException($"No valid git object identified by '{id}' exists in the repository."); evaluator(osw.ObjectPtr); } } - public static ILazy Singleton(Repository repo, ObjectId id, Func resultSelector) + public static ILazy Singleton(Repository repo, ObjectId id, Func resultSelector, bool throwsIfMissing = true) { return Singleton(() => { using (var osw = new ObjectSafeWrapper(id, repo.Handle)) { - if (osw.ObjectPtr == null) - throw new NotFoundException($"Object {id} is not available"); + if (throwsIfMissing && osw.ObjectPtr == null) + throw new NotFoundException($"No valid git object identified by '{id}' exists in the repository."); return resultSelector(osw.ObjectPtr); }