diff --git a/CHANGES.md b/CHANGES.md index 790f7a84f..2d258a3a7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,10 +10,14 @@ - Windows (x86/amd64): - Linux/Mac OS X: -## v0.24 + 1 +## v0.24.1 ### Additions + - `TreeDefinition.Add` can now add a blob to a tree when given its object ID. + - `ObjectDatabase.Write` can now take a readable `Stream` to support writing + large files to the object database. + ### Changes ### Fixes diff --git a/LibGit2Sharp.Tests/ObjectDatabaseFixture.cs b/LibGit2Sharp.Tests/ObjectDatabaseFixture.cs index fc06ef713..067b9dc40 100644 --- a/LibGit2Sharp.Tests/ObjectDatabaseFixture.cs +++ b/LibGit2Sharp.Tests/ObjectDatabaseFixture.cs @@ -121,6 +121,31 @@ public void CanCreateABlobFromAStream(string expectedSha, string hintPath) } } + [Fact] + public void CanWriteABlobFromAByteArray() + { + var ba = Encoding.ASCII.GetBytes("libgit2\r\n"); + + using (var repo = new Repository(InitNewRepository())) + { + var id = repo.ObjectDatabase.Write(ba); + Assert.Equal(new ObjectId("99115ea359379a218c47cffc83cd0af8c91c4061"), id); + } + } + + [Fact] + public void CanWriteABlobFromAStream() + { + var ba = Encoding.ASCII.GetBytes("libgit2\r\n"); + + using (var stream = new MemoryStream(ba)) + using (var repo = new Repository(InitNewRepository())) + { + var id = repo.ObjectDatabase.Write(stream, stream.Length); + Assert.Equal(new ObjectId("99115ea359379a218c47cffc83cd0af8c91c4061"), id); + } + } + Stream PrepareMemoryStream(int contentSize) { var sb = new StringBuilder(); diff --git a/LibGit2Sharp.Tests/SmartSubtransportFixture.cs b/LibGit2Sharp.Tests/SmartSubtransportFixture.cs index d55785baa..8e6aef5c6 100644 --- a/LibGit2Sharp.Tests/SmartSubtransportFixture.cs +++ b/LibGit2Sharp.Tests/SmartSubtransportFixture.cs @@ -19,8 +19,8 @@ public class SmartSubtransportFixture : BaseFixture (sender, certificate, chain, errors) => { return true; }; [Theory] - [InlineData("http", "http://github.com/libgit2/TestGitRepository")] - [InlineData("https", "https://github.com/libgit2/TestGitRepository")] + [InlineData("http", "http://bitbucket.org/edwardthomson/TestGitRepository/")] + [InlineData("https", "https://bitbucket.org/edwardthomson/TestGitRepository/")] public void CustomSmartSubtransportTest(string scheme, string url) { string remoteName = "testRemote"; @@ -259,6 +259,8 @@ public override int Write(Stream dataStream, long length) private static HttpWebRequest CreateWebRequest(string endpointUrl, bool isPost, string contentType) { + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(endpointUrl); webRequest.UserAgent = "git/1.0 (libgit2 custom transport)"; webRequest.ServicePoint.Expect100Continue = false; diff --git a/LibGit2Sharp.Tests/TreeDefinitionFixture.cs b/LibGit2Sharp.Tests/TreeDefinitionFixture.cs index 2a7aba07c..91f144633 100644 --- a/LibGit2Sharp.Tests/TreeDefinitionFixture.cs +++ b/LibGit2Sharp.Tests/TreeDefinitionFixture.cs @@ -222,6 +222,49 @@ public void CanAddAnExistingBlob(string blobSha, string targetPath) } } + [Theory] + [InlineData("a8233120f6ad708f843d861ce2b7228ec4e3dec6", "README_TOO")] + [InlineData("a8233120f6ad708f843d861ce2b7228ec4e3dec6", "1/README")] + [InlineData("45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "1/another_one.txt")] + [InlineData("45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "another_one.txt")] + public void CanAddBlobById(string blobSha, string targetPath) + { + string path = SandboxBareTestRepo(); + using (var repo = new Repository(path)) + { + TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree); + Assert.Null(td[targetPath]); + + var objectId = new ObjectId(blobSha); + + td.Add(targetPath, objectId, Mode.NonExecutableFile); + + TreeEntryDefinition fetched = td[targetPath]; + Assert.NotNull(fetched); + + Assert.Equal(objectId, fetched.TargetId); + Assert.Equal(Mode.NonExecutableFile, fetched.Mode); + } + } + + [Fact] + public void CannotAddTreeById() + { + const string treeSha = "7f76480d939dc401415927ea7ef25c676b8ddb8f"; + const string targetPath = "1/2"; + + string path = SandboxBareTestRepo(); + using (var repo = new Repository(path)) + { + TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree); + Assert.Null(td[targetPath]); + + var objectId = new ObjectId(treeSha); + + Assert.Throws(() => td.Add(targetPath, objectId, Mode.Directory)); + } + } + [Fact] public void CanAddAnExistingSubmodule() { diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 34fb0d630..9708470cc 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -1,6 +1,6 @@  - + Debug AnyCPU @@ -392,6 +392,6 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/LibGit2Sharp/ObjectDatabase.cs b/LibGit2Sharp/ObjectDatabase.cs index c662a478c..532bc47aa 100644 --- a/LibGit2Sharp/ObjectDatabase.cs +++ b/LibGit2Sharp/ObjectDatabase.cs @@ -178,7 +178,7 @@ public int Provider(IntPtr content, int max_length, IntPtr data) } /// - /// Write an object to the object database + /// Writes an object to the object database. /// /// The contents of the object /// The type of object to write @@ -187,6 +187,45 @@ public virtual ObjectId Write(byte[] data) where T : GitObject return Proxy.git_odb_write(handle, data, GitObject.TypeToKindMap[typeof(T)]); } + /// + /// Writes an object to the object database. + /// + /// The contents of the object + /// The number of bytes to consume from the stream + /// The type of object to write + public virtual ObjectId Write(Stream stream, long numberOfBytesToConsume) where T : GitObject + { + Ensure.ArgumentNotNull(stream, "stream"); + + if (!stream.CanRead) + { + throw new ArgumentException("The stream cannot be read from.", "stream"); + } + + using (var odbStream = Proxy.git_odb_open_wstream(handle, numberOfBytesToConsume, GitObjectType.Blob)) + { + var buffer = new byte[4 * 1024]; + long totalRead = 0; + + while (totalRead < numberOfBytesToConsume) + { + long left = numberOfBytesToConsume - totalRead; + int toRead = left < buffer.Length ? (int)left : buffer.Length; + var read = stream.Read(buffer, 0, toRead); + + if (read == 0) + { + throw new EndOfStreamException("The stream ended unexpectedly"); + } + + Proxy.git_odb_stream_write(odbStream, buffer, read); + totalRead += read; + } + + return Proxy.git_odb_stream_finalize_write(odbStream); + } + } + /// /// Inserts a into the object database, created from the content of a stream. /// Optionally, git filters will be applied to the content before storing it. @@ -294,37 +333,8 @@ private unsafe Blob CreateBlob(Stream stream, string hintpath, long? numberOfByt /// The created . public virtual Blob CreateBlob(Stream stream, long numberOfBytesToConsume) { - Ensure.ArgumentNotNull(stream, "stream"); - - if (!stream.CanRead) - { - throw new ArgumentException("The stream cannot be read from.", "stream"); - } - - using (var odbStream = Proxy.git_odb_open_wstream(handle, numberOfBytesToConsume, GitObjectType.Blob)) - { - var buffer = new byte[4 * 1024]; - long totalRead = 0; - - while (totalRead < numberOfBytesToConsume) - { - long left = numberOfBytesToConsume - totalRead; - int toRead = left < buffer.Length ? (int)left : buffer.Length; - var read = stream.Read(buffer, 0, toRead); - - if (read == 0) - { - throw new EndOfStreamException("The stream ended unexpectedly"); - } - - Proxy.git_odb_stream_write(odbStream, buffer, read); - totalRead += read; - } - - var id = Proxy.git_odb_stream_finalize_write(odbStream); - - return repo.Lookup(id); - } + var id = Write(stream, numberOfBytesToConsume); + return repo.Lookup(id); } /// diff --git a/LibGit2Sharp/Properties/AssemblyInfo.cs b/LibGit2Sharp/Properties/AssemblyInfo.cs index 18643022e..0d801bcb3 100644 --- a/LibGit2Sharp/Properties/AssemblyInfo.cs +++ b/LibGit2Sharp/Properties/AssemblyInfo.cs @@ -42,6 +42,6 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.24.0")] -[assembly: AssemblyFileVersion("0.24.0")] -[assembly: AssemblyInformationalVersion("0.24.0-dev00000000000000")] +[assembly: AssemblyVersion("0.24.2")] +[assembly: AssemblyFileVersion("0.24.2")] +[assembly: AssemblyInformationalVersion("0.24.2-dev00000000000000")] diff --git a/LibGit2Sharp/TreeDefinition.cs b/LibGit2Sharp/TreeDefinition.cs index 68f287879..aa4328c3d 100644 --- a/LibGit2Sharp/TreeDefinition.cs +++ b/LibGit2Sharp/TreeDefinition.cs @@ -206,6 +206,23 @@ public virtual TreeDefinition Add(string targetTreeEntryPath, string filePath, M return Add(targetTreeEntryPath, ted); } + /// + /// Adds or replaces a from an existing blob specified by its Object ID at the specified location. + /// + /// The path within this . + /// The object ID for this entry. + /// The file related attributes. + /// The current . + public virtual TreeDefinition Add(string targetTreeEntryPath, ObjectId id, Mode mode) + { + Ensure.ArgumentNotNull(id, "id"); + Ensure.ArgumentConformsTo(mode, m => m.HasAny(TreeEntryDefinition.BlobModes), "mode"); + + TreeEntryDefinition ted = TreeEntryDefinition.From(id, mode); + + return Add(targetTreeEntryPath, ted); + } + /// /// Adds or replaces a , dynamically built from the provided , at the specified location. /// diff --git a/LibGit2Sharp/TreeEntryDefinition.cs b/LibGit2Sharp/TreeEntryDefinition.cs index b89c59306..2a3ceb35f 100644 --- a/LibGit2Sharp/TreeEntryDefinition.cs +++ b/LibGit2Sharp/TreeEntryDefinition.cs @@ -54,6 +54,8 @@ internal static TreeEntryDefinition From(TreeEntry treeEntry) internal static TreeEntryDefinition From(Blob blob, Mode mode) { + Ensure.ArgumentNotNull(blob, "blob"); + return new TreeEntryDefinition { Mode = mode, @@ -63,6 +65,19 @@ internal static TreeEntryDefinition From(Blob blob, Mode mode) }; } + internal static TreeEntryDefinition From(ObjectId id, Mode mode) + { + Ensure.ArgumentNotNull(id, "id"); + Ensure.ArgumentNotNull(mode, "mode"); + + return new TreeEntryDefinition + { + Mode = mode, + TargetType = TreeEntryTargetType.Blob, + TargetId = id + }; + } + internal static TreeEntryDefinition TransientBlobFrom(string filePath, Mode mode) { Ensure.ArgumentConformsTo(mode, m => m.HasAny(BlobModes), "mode"); diff --git a/LibGit2Sharp/packages.config b/LibGit2Sharp/packages.config index 72b9ea358..5aaf75f58 100644 --- a/LibGit2Sharp/packages.config +++ b/LibGit2Sharp/packages.config @@ -1,4 +1,4 @@  - + diff --git a/appveyor.yml b/appveyor.yml index 693cd95ee..342b92e41 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,7 +18,7 @@ environment: secure: nuzUT+HecXGIi3KaPd/1hgFEZJan/j6+oNbPV75JKjk= coverity_email: secure: eGVilNg1Yuq+Xj+SW8r3WCtjnzhoDV0sNJkma4NRq7A= - version : 0.24.0 + version : 0.24.2 matrix: - xunit_runner: xunit.console.x86.exe Arch: 32 @@ -47,7 +47,7 @@ install: Write-Host $BuildDate -ForegroundColor "Green" $VersionSuffix = "" - If ($Env:APPVEYOR_REPO_BRANCH -ne "master") + If ($Env:APPVEYOR_REPO_BRANCH -ne "master" -and ($Env:APPVEYOR_REPO_BRANCH -eq $null -or !$Env:APPVEYOR_REPO_BRANCH.StartsWith("maint/"))) { $VersionSuffix = "-pre$BuildDate" }