Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2sharp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornulltoken <emeric.fermas@gmail.com>2012-04-19 12:14:13 +0400
committernulltoken <emeric.fermas@gmail.com>2012-04-28 05:32:17 +0400
commit77fd1e48d22b99dbcac789ae014edaf9328776c2 (patch)
treefbbb10470919d2b31c9c49521570b239edc9e479
parentbd127243515540350875c8fa1d359db82d7411cf (diff)
Add TreeDefinition and TreeEntryDefinition types
-rw-r--r--LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj1
-rw-r--r--LibGit2Sharp.Tests/TreeDefinitionFixture.cs277
-rw-r--r--LibGit2Sharp/LibGit2Sharp.csproj2
-rw-r--r--LibGit2Sharp/TreeDefinition.cs207
-rw-r--r--LibGit2Sharp/TreeEntryDefinition.cs151
5 files changed, 638 insertions, 0 deletions
diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
index 1116d395..9071e3b3 100644
--- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
+++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
@@ -71,6 +71,7 @@
<Compile Include="TestHelpers\SkipException.cs" />
<Compile Include="TestHelpers\SkippableFactAttribute.cs" />
<Compile Include="TestHelpers\TemporaryCloneOfTestRepo.cs" />
+ <Compile Include="TreeDefinitionFixture.cs" />
<Compile Include="TreeFixture.cs" />
<Compile Include="TupleFixture.cs" />
</ItemGroup>
diff --git a/LibGit2Sharp.Tests/TreeDefinitionFixture.cs b/LibGit2Sharp.Tests/TreeDefinitionFixture.cs
new file mode 100644
index 00000000..310b3212
--- /dev/null
+++ b/LibGit2Sharp.Tests/TreeDefinitionFixture.cs
@@ -0,0 +1,277 @@
+using System;
+using LibGit2Sharp.Tests.TestHelpers;
+using Xunit;
+using Xunit.Extensions;
+
+namespace LibGit2Sharp.Tests
+{
+ public class TreeDefinitionFixture : BaseFixture
+ {
+ /*
+ * $ git ls-tree -r HEAD
+ * 100755 blob 45b983be36b73c0788dc9cbcb76cbb80fc7bb057 1/branch_file.txt
+ * 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README
+ * 100644 blob 45b983be36b73c0788dc9cbcb76cbb80fc7bb057 branch_file.txt
+ * 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt
+ */
+
+ [Fact]
+ public void CanBuildATreeDefinitionFromATree()
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+ Assert.NotNull(td);
+ }
+ }
+
+ [Fact]
+ public void BuildingATreeDefinitionWithBadParamsThrows()
+ {
+ Assert.Throws<ArgumentNullException>(() => TreeDefinition.From(null));
+ }
+
+ [Fact]
+ public void RequestingANonExistingEntryReturnsNull()
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+
+ Assert.Null(td["nope"]);
+ Assert.Null(td["not/here"]);
+ Assert.Null(td["neither/in/here"]);
+ Assert.Null(td["README/is/a-Blob/not-a-Tree"]);
+ }
+ }
+
+ [Fact]
+ public void RequestingAnEntryWithBadParamsThrows()
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+
+ Assert.Throws<ArgumentNullException>(() => td[null]);
+ Assert.Throws<ArgumentException>(() => td[string.Empty]);
+ Assert.Throws<ArgumentException>(() => td["/"]);
+ Assert.Throws<ArgumentException>(() => td["/a"]);
+ Assert.Throws<ArgumentException>(() => td["1//branch_file.txt"]);
+ Assert.Throws<ArgumentException>(() => td["README/"]);
+ Assert.Throws<ArgumentException>(() => td["1/"]);
+ }
+ }
+
+ [Theory]
+ [InlineData("1/branch_file.txt", "100755", GitObjectType.Blob, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057")]
+ [InlineData("README", "100644", GitObjectType.Blob, "a8233120f6ad708f843d861ce2b7228ec4e3dec6")]
+ [InlineData("branch_file.txt", "100644", GitObjectType.Blob, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057")]
+ [InlineData("new.txt", "100644", GitObjectType.Blob, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")]
+ [InlineData("1", "040000", GitObjectType.Tree, "7f76480d939dc401415927ea7ef25c676b8ddb8f")]
+ public void CanRetrieveEntries(string path, string expectedAttributes, GitObjectType expectedType, string expectedSha)
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+
+ TreeEntryDefinition ted = td[path];
+
+ Assert.Equal(ToMode(expectedAttributes), ted.Mode);
+ Assert.Equal(expectedType, ted.Type);
+ Assert.Equal(new ObjectId(expectedSha), ted.TargetId);
+ }
+ }
+
+ //TODO: Convert Mode to a static class and add this helper method as 'FromString()'
+ private static Mode ToMode(string expectedAttributes)
+ {
+ return (Mode)Convert.ToInt32(expectedAttributes, 8);
+ }
+
+ [Theory]
+ [InlineData("README", "README_TOO")]
+ [InlineData("README", "1/README")]
+ [InlineData("1/branch_file.txt", "1/another_one.txt")]
+ [InlineData("1/branch_file.txt", "another_one.txt")]
+ [InlineData("1/branch_file.txt", "1/2/another_one.txt")]
+ public void CanAddAnExistingTreeEntryDefinition(string sourcePath, string targetPath)
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+ Assert.Null(td[targetPath]);
+
+ TreeEntryDefinition ted = td[sourcePath];
+ td.Add(targetPath, ted);
+
+ TreeEntryDefinition fetched = td[targetPath];
+ Assert.NotNull(fetched);
+
+ Assert.Equal(ted, fetched);
+ }
+ }
+
+ [Theory]
+ [InlineData("a8233120f6ad708f843d861ce2b7228ec4e3dec6", "README_TOO")]
+ [InlineData("a8233120f6ad708f843d861ce2b7228ec4e3dec6", "1/README")]
+ [InlineData("45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "1/another_one.txt")]
+ [InlineData("45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "another_one.txt")]
+ public void CanAddAnExistingBlob(string blobSha, string targetPath)
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+ Assert.Null(td[targetPath]);
+
+ var objectId = new ObjectId(blobSha);
+ var blob = repo.Lookup<Blob>(objectId);
+
+ td.Add(targetPath, blob, Mode.NonExecutableFile);
+
+ TreeEntryDefinition fetched = td[targetPath];
+ Assert.NotNull(fetched);
+
+ Assert.Equal(objectId, fetched.TargetId);
+ Assert.Equal(Mode.NonExecutableFile, fetched.Mode);
+ }
+ }
+
+ [Fact]
+ public void CanAddAnExistingTree()
+ {
+ const string treeSha = "7f76480d939dc401415927ea7ef25c676b8ddb8f";
+ const string targetPath = "1/2";
+
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+
+ var objectId = new ObjectId(treeSha);
+ var tree = repo.Lookup<Tree>(objectId);
+
+ td.Add(targetPath, tree);
+
+ TreeEntryDefinition fetched = td[targetPath];
+ Assert.NotNull(fetched);
+
+ Assert.Equal(objectId, fetched.TargetId);
+ Assert.Equal(Mode.Directory, fetched.Mode);
+
+ Assert.NotNull(td["1/2/branch_file.txt"]);
+ }
+ }
+
+ [Fact]
+ public void CanReplaceAnExistingTreeWithABlob()
+ {
+ const string blobSha = "a8233120f6ad708f843d861ce2b7228ec4e3dec6";
+ const string targetPath = "1";
+
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+ Assert.Equal(GitObjectType.Tree, td[targetPath].Type);
+
+ var objectId = new ObjectId(blobSha);
+ var blob = repo.Lookup<Blob>(objectId);
+
+ Assert.NotNull(td["1/branch_file.txt"]);
+
+ td.Add(targetPath, blob, Mode.NonExecutableFile);
+
+ TreeEntryDefinition fetched = td[targetPath];
+ Assert.NotNull(fetched);
+
+ Assert.Equal(GitObjectType.Blob, td[targetPath].Type);
+ Assert.Equal(objectId, fetched.TargetId);
+ Assert.Equal(Mode.NonExecutableFile, fetched.Mode);
+
+ Assert.Null(td["1/branch_file.txt"]);
+ }
+ }
+
+ [Theory]
+ [InlineData("README")]
+ [InlineData("1/branch_file.txt")]
+ public void CanReplaceAnExistingBlobWithATree(string targetPath)
+ {
+ const string treeSha = "7f76480d939dc401415927ea7ef25c676b8ddb8f";
+
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+ Assert.NotNull(td[targetPath]);
+ Assert.Equal(GitObjectType.Blob, td[targetPath].Type);
+
+ var objectId = new ObjectId(treeSha);
+ var tree = repo.Lookup<Tree>(objectId);
+
+ td.Add(targetPath, tree);
+
+ TreeEntryDefinition fetched = td[targetPath];
+ Assert.NotNull(fetched);
+
+ Assert.Equal(GitObjectType.Tree, td[targetPath].Type);
+ Assert.Equal(objectId, fetched.TargetId);
+ Assert.Equal(Mode.Directory, fetched.Mode);
+ }
+ }
+
+ [Fact]
+ public void CanNotReplaceAnExistingTreeWithATreeBeingAssembled()
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+ Assert.Equal(GitObjectType.Tree, td["1"].Type);
+
+ td.Add("new/one", repo.Lookup<Blob>("a823312"), Mode.NonExecutableFile)
+ .Add("new/two", repo.Lookup<Blob>("a71586c"), Mode.NonExecutableFile)
+ .Add("new/tree", repo.Lookup<Tree>("7f76480"));
+
+ Assert.Throws<InvalidOperationException>(() => td.Add("1", td["new"]));
+ }
+ }
+
+ [Fact]
+ public void ModifyingTheContentOfATreeSetsItsOidToNull()
+ {
+ const string blobSha = "a8233120f6ad708f843d861ce2b7228ec4e3dec6";
+ const string targetPath = "1/another_branch_file.txt";
+
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+
+ var objectId = new ObjectId(blobSha);
+ var blob = repo.Lookup<Blob>(objectId);
+
+ Assert.NotEqual(ObjectId.Zero, td["1"].TargetId);
+
+ td.Add(targetPath, blob, Mode.NonExecutableFile);
+
+ Assert.Equal(ObjectId.Zero, td["1"].TargetId);
+ }
+ }
+
+ [Fact]
+ public void CanAddAnExistingBlobEntryWithAnExistingTree()
+ {
+ using (var repo = new Repository(BareTestRepoPath))
+ {
+ TreeDefinition td = TreeDefinition.From(repo.Head.Tip.Tree);
+ TreeEntryDefinition original = td["README"];
+
+ td.Add("1/2/README", original);
+
+ TreeEntryDefinition fetched = td["1/2/README"];
+ Assert.NotNull(fetched);
+
+ Assert.Equal(original.TargetId, fetched.TargetId);
+ Assert.Equal(original.Mode, fetched.Mode);
+
+ Assert.NotNull(td["1/branch_file.txt"]);
+ }
+ }
+ }
+}
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index a52b563e..4e6451e2 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -131,7 +131,9 @@
<Compile Include="TagAnnotation.cs" />
<Compile Include="TagCollection.cs" />
<Compile Include="Tree.cs" />
+ <Compile Include="TreeDefinition.cs" />
<Compile Include="TreeEntry.cs" />
+ <Compile Include="TreeEntryDefinition.cs" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="CustomDictionary.xml" />
diff --git a/LibGit2Sharp/TreeDefinition.cs b/LibGit2Sharp/TreeDefinition.cs
new file mode 100644
index 00000000..dddccd25
--- /dev/null
+++ b/LibGit2Sharp/TreeDefinition.cs
@@ -0,0 +1,207 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using LibGit2Sharp.Core;
+using LibGit2Sharp.Core.Compat;
+
+namespace LibGit2Sharp
+{
+ /// <summary>
+ /// Holds the meta data of a <see cref = "Tree" />.
+ /// </summary>
+ public class TreeDefinition
+ {
+ private readonly Dictionary<string, TreeEntryDefinition> entries = new Dictionary<string, TreeEntryDefinition>();
+ private readonly Dictionary<string, TreeDefinition> unwrappedTrees = new Dictionary<string, TreeDefinition>();
+
+ /// <summary>
+ /// Builds a <see cref = "TreeDefinition" /> from an existing <see cref = "Tree" />.
+ /// </summary>
+ /// <param name = "tree">The <see cref = "Tree" /> to be processed.</param>
+ /// <returns>A new <see cref = "TreeDefinition" /> holding the meta data of the <paramref name = "tree" />.</returns>
+ public static TreeDefinition From(Tree tree)
+ {
+ Ensure.ArgumentNotNull(tree, "tree");
+
+ var td = new TreeDefinition();
+
+ foreach (TreeEntry treeEntry in tree)
+ {
+ td.AddEntry(treeEntry.Name, TreeEntryDefinition.From(treeEntry));
+ }
+
+ return td;
+ }
+
+ private void AddEntry(string targetTreeEntryName, TreeEntryDefinition treeEntryDefinition)
+ {
+ if (entries.ContainsKey(targetTreeEntryName))
+ {
+ WrapTree(targetTreeEntryName, treeEntryDefinition);
+ return;
+ }
+
+ entries.Add(targetTreeEntryName, treeEntryDefinition);
+ }
+
+ /// <summary>
+ /// Adds or replaces a <see cref="TreeEntryDefinition"/> at the specified <paramref name="targetTreeEntryPath"/> location.
+ /// </summary>
+ /// <param name="targetTreeEntryPath">The path within this <see cref="TreeDefinition"/>.</param>
+ /// <param name="treeEntryDefinition">The <see cref="TreeEntryDefinition"/> to be stored at the described location.</param>
+ /// <returns>The current <see cref="TreeDefinition"/>.</returns>
+ public TreeDefinition Add(string targetTreeEntryPath, TreeEntryDefinition treeEntryDefinition)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(targetTreeEntryPath, "targetTreeEntryPath");
+ Ensure.ArgumentNotNull(treeEntryDefinition, "treeEntryDefinition");
+
+ if (Path.IsPathRooted(targetTreeEntryPath))
+ {
+ throw new ArgumentException("The provided path is an absolute path.");
+ }
+
+ if (treeEntryDefinition is TransientTreeTreeEntryDefinition)
+ {
+ throw new InvalidOperationException(string.Format("The {0} references a target which hasn't been created in the {1} yet. This situation can occur when the target is a whole new {2} being created, or when an existing {2} is being updated because some of its children were added/removed.", typeof(TreeEntryDefinition).Name, typeof(ObjectDatabase).Name, typeof(Tree).Name));
+ }
+
+ Tuple<string, string> segments = ExtractPosixLeadingSegment(targetTreeEntryPath);
+
+ if (segments.Item2 != null)
+ {
+ TreeDefinition td = RetrieveOrBuildTreeDefinition(segments.Item1, true);
+ td.Add(segments.Item2, treeEntryDefinition);
+ }
+ else
+ {
+ AddEntry(segments.Item1, treeEntryDefinition);
+ }
+
+ return this;
+ }
+
+ /// <summary>
+ /// Adds or replaces a <see cref="TreeEntryDefinition"/>, dynamically built from the provided <see cref="Blob"/>, at the specified <paramref name="targetTreeEntryPath"/> location.
+ /// </summary>
+ /// <param name="targetTreeEntryPath">The path within this <see cref="TreeDefinition"/>.</param>
+ /// <param name="blob">The <see cref="Blob"/> to be stored at the described location.</param>
+ /// <param name="mode">The file related <see cref="Mode"/> attributes.</param>
+ /// <returns>The current <see cref="TreeDefinition"/>.</returns>
+ public TreeDefinition Add(string targetTreeEntryPath, Blob blob, Mode mode)
+ {
+ Ensure.ArgumentNotNull(blob, "blob");
+ Ensure.ArgumentConformsTo(mode,
+ m => m.HasAny(new[] { Mode.ExecutableFile, Mode.NonExecutableFile, Mode.NonExecutableGroupWriteableFile }), "mode");
+
+ TreeEntryDefinition ted = TreeEntryDefinition.From(blob, mode);
+
+ return Add(targetTreeEntryPath, ted);
+ }
+
+ /// <summary>
+ /// Adds or replaces a <see cref="TreeEntryDefinition"/>, dynamically built from the provided <see cref="Tree"/>, at the specified <paramref name="targetTreeEntryPath"/> location.
+ /// </summary>
+ /// <param name="targetTreeEntryPath">The path within this <see cref="TreeDefinition"/>.</param>
+ /// <param name="tree">The <see cref="Tree"/> to be stored at the described location.</param>
+ /// <returns>The current <see cref="TreeDefinition"/>.</returns>
+ public TreeDefinition Add(string targetTreeEntryPath, Tree tree)
+ {
+ Ensure.ArgumentNotNull(tree, "tree");
+
+ TreeEntryDefinition ted = TreeEntryDefinition.From(tree);
+
+ return Add(targetTreeEntryPath, ted);
+ }
+
+ private TreeDefinition RetrieveOrBuildTreeDefinition(string treeName, bool shouldOverWrite)
+ {
+ TreeDefinition td;
+
+ if (unwrappedTrees.TryGetValue(treeName, out td))
+ {
+ return td;
+ }
+
+ TreeEntryDefinition treeEntryDefinition;
+ bool hasAnEntryBeenFound = entries.TryGetValue(treeName, out treeEntryDefinition);
+
+ if (hasAnEntryBeenFound)
+ {
+ switch (treeEntryDefinition.Type)
+ {
+ case GitObjectType.Tree:
+ td = From(treeEntryDefinition.Target as Tree);
+ break;
+
+ case GitObjectType.Blob:
+ if (shouldOverWrite)
+ {
+ td = new TreeDefinition();
+ break;
+ }
+
+ return null;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ else
+ {
+ if (!shouldOverWrite)
+ {
+ return null;
+ }
+
+ td = new TreeDefinition();
+ }
+
+ entries[treeName] = new TransientTreeTreeEntryDefinition();
+
+ unwrappedTrees.Add(treeName, td);
+ return td;
+ }
+
+ private void WrapTree(string entryName, TreeEntryDefinition treeEntryDefinition)
+ {
+ entries[entryName] = treeEntryDefinition;
+ unwrappedTrees.Remove(entryName);
+ }
+
+ /// <summary>
+ /// Retrieves the <see cref="TreeEntryDefinition"/> located the specified <paramref name="treeEntryPath"/> path.
+ /// </summary>
+ /// <param name="treeEntryPath">The path within this <see cref="TreeDefinition"/>.</param>
+ /// <returns>The found <see cref="TreeEntryDefinition"/> if any; null otherwise.</returns>
+ public TreeEntryDefinition this[string treeEntryPath]
+ {
+ get
+ {
+ Ensure.ArgumentNotNullOrEmptyString(treeEntryPath, "treeEntryPath");
+
+ Tuple<string, string> segments = ExtractPosixLeadingSegment(treeEntryPath);
+
+ if (segments.Item2 != null)
+ {
+ TreeDefinition td = RetrieveOrBuildTreeDefinition(segments.Item1, false);
+ return td == null ? null : td[segments.Item2];
+ }
+
+ TreeEntryDefinition treeEntryDefinition;
+ return !entries.TryGetValue(segments.Item1, out treeEntryDefinition) ? null : treeEntryDefinition;
+ }
+ }
+
+ private static Tuple<string, string> ExtractPosixLeadingSegment(FilePath targetPath)
+ {
+ string[] segments = targetPath.Posix.Split(new[] { '/' }, 2);
+
+ if (segments[0] == string.Empty || (segments.Length == 2 && (segments[1] == string.Empty || segments[1].StartsWith("/"))))
+ {
+ throw new ArgumentException(string.Format("'{0}' is not a valid path.", targetPath));
+ }
+
+ return new Tuple<string, string>(segments[0], segments.Length == 2 ? segments[1] : null);
+ }
+ }
+}
diff --git a/LibGit2Sharp/TreeEntryDefinition.cs b/LibGit2Sharp/TreeEntryDefinition.cs
new file mode 100644
index 00000000..ecb2a6a5
--- /dev/null
+++ b/LibGit2Sharp/TreeEntryDefinition.cs
@@ -0,0 +1,151 @@
+using System;
+using LibGit2Sharp.Core;
+using LibGit2Sharp.Core.Compat;
+
+namespace LibGit2Sharp
+{
+ /// <summary>
+ /// Holds the meta data of a <see cref = "TreeEntry" />.
+ /// </summary>
+ public class TreeEntryDefinition
+ {
+ private Lazy<GitObject> target;
+
+ private static readonly LambdaEqualityHelper<TreeEntryDefinition> equalityHelper =
+ new LambdaEqualityHelper<TreeEntryDefinition>(new Func<TreeEntryDefinition, object>[] { x => x.Mode, x => x.Type, x => x.TargetId });
+
+ internal TreeEntryDefinition()
+ {
+ }
+
+ /// <summary>
+ /// Gets file mode.
+ /// </summary>
+ public virtual Mode Mode { get; private set; }
+
+ /// <summary>
+ /// Gets the <see cref = "GitObjectType" /> of the target being pointed at.
+ /// </summary>
+ public virtual GitObjectType Type { get; private set; }
+
+ /// <summary>
+ /// Gets the <see cref = "ObjectId" /> of the target being pointed at.
+ /// </summary>
+ public virtual ObjectId TargetId { get; private set; }
+
+ internal virtual GitObject Target
+ {
+ get { return target.Value; }
+ }
+
+ internal static TreeEntryDefinition From(TreeEntry treeEntry)
+ {
+ return new TreeEntryDefinition
+ {
+ Mode = treeEntry.Mode,
+ Type = treeEntry.Type,
+ TargetId = treeEntry.TargetId,
+ target = new Lazy<GitObject>(() => treeEntry.Target)
+ };
+ }
+
+ internal static TreeEntryDefinition From(Blob blob, Mode mode)
+ {
+ return new TreeEntryDefinition
+ {
+ Mode = mode,
+ Type = GitObjectType.Blob,
+ TargetId = blob.Id,
+ target = new Lazy<GitObject>(() => blob)
+ };
+ }
+
+ internal static TreeEntryDefinition From(Tree tree)
+ {
+ return new TreeEntryDefinition
+ {
+ Mode = Mode.Directory,
+ Type = GitObjectType.Tree,
+ TargetId = tree.Id,
+ target = new Lazy<GitObject>(() => tree)
+ };
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref = "Object" /> is equal to the current <see cref = "TreeEntryDefinition" />.
+ /// </summary>
+ /// <param name = "obj">The <see cref = "Object" /> to compare with the current <see cref = "TreeEntryDefinition" />.</param>
+ /// <returns>True if the specified <see cref = "Object" /> is equal to the current <see cref = "TreeEntryDefinition" />; otherwise, false.</returns>
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as TreeEntryDefinition);
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref = "TreeEntryDefinition" /> is equal to the current <see cref = "TreeEntryDefinition" />.
+ /// </summary>
+ /// <param name = "other">The <see cref = "TreeEntryDefinition" /> to compare with the current <see cref = "TreeEntryDefinition" />.</param>
+ /// <returns>True if the specified <see cref = "TreeEntryDefinition" /> is equal to the current <see cref = "TreeEntryDefinition" />; otherwise, false.</returns>
+ public bool Equals(TreeEntryDefinition other)
+ {
+ return equalityHelper.Equals(this, other);
+ }
+
+ /// <summary>
+ /// Returns the hash code for this instance.
+ /// </summary>
+ /// <returns>A 32-bit signed integer hash code.</returns>
+ public override int GetHashCode()
+ {
+ return equalityHelper.GetHashCode(this);
+ }
+
+ /// <summary>
+ /// Tests if two <see cref = "TreeEntryDefinition" /> are equal.
+ /// </summary>
+ /// <param name = "left">First <see cref = "TreeEntryDefinition" /> to compare.</param>
+ /// <param name = "right">Second <see cref = "TreeEntryDefinition" /> to compare.</param>
+ /// <returns>True if the two objects are equal; false otherwise.</returns>
+ public static bool operator ==(TreeEntryDefinition left, TreeEntryDefinition right)
+ {
+ return Equals(left, right);
+ }
+
+ /// <summary>
+ /// Tests if two <see cref = "TreeEntryDefinition" /> are different.
+ /// </summary>
+ /// <param name = "left">First <see cref = "TreeEntryDefinition" /> to compare.</param>
+ /// <param name = "right">Second <see cref = "TreeEntryDefinition" /> to compare.</param>
+ /// <returns>True if the two objects are different; false otherwise.</returns>
+ public static bool operator !=(TreeEntryDefinition left, TreeEntryDefinition right)
+ {
+ return !Equals(left, right);
+ }
+ }
+
+ internal abstract class TransientTreeEntryDefinition : TreeEntryDefinition
+ {
+ public override ObjectId TargetId
+ {
+ get { return ObjectId.Zero; }
+ }
+
+ internal override GitObject Target
+ {
+ get { return null; }
+ }
+ }
+
+ internal class TransientTreeTreeEntryDefinition : TransientTreeEntryDefinition
+ {
+ public override Mode Mode
+ {
+ get { return Mode.Directory; }
+ }
+
+ public override GitObjectType Type
+ {
+ get { return GitObjectType.Tree; }
+ }
+ }
+}