using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Compat;
using LibGit2Sharp.Core.Handles;
namespace LibGit2Sharp
{
///
/// A Commit
///
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class Commit : GitObject
{
private readonly GitObjectLazyGroup group;
private readonly ILazy lazyTree;
private readonly ILazy lazyAuthor;
private readonly ILazy lazyCommitter;
private readonly ILazy lazyMessage;
private readonly ILazy lazyEncoding;
private readonly ParentsCollection parents;
private readonly Lazy lazyShortMessage;
private readonly Lazy> lazyNotes;
///
/// Needed for mocking purposes.
///
protected Commit()
{ }
internal Commit(Repository repo, ObjectId id)
: base(repo, id)
{
lazyTree = GitObjectLazyGroup.Singleton(this.repo, id, obj => new Tree(this.repo, Proxy.git_commit_tree_oid(obj), null));
group = new GitObjectLazyGroup(this.repo, id);
lazyAuthor = group.AddLazy(Proxy.git_commit_author);
lazyCommitter = group.AddLazy(Proxy.git_commit_committer);
lazyMessage = group.AddLazy(Proxy.git_commit_message);
lazyEncoding = group.AddLazy(RetrieveEncodingOf);
lazyShortMessage = new Lazy(ExtractShortMessage);
lazyNotes = new Lazy>(() => RetrieveNotesOfCommit(id).ToList());
parents = new ParentsCollection(repo, id);
}
///
/// Gets the pointed at by the in the .
///
/// The relative path to the from the working directory.
/// null if nothing has been found, the otherwise.
public virtual TreeEntry this[string relativePath]
{
get { return Tree[relativePath]; }
}
///
/// Gets the commit message.
///
public virtual string Message { get { return lazyMessage.Value; } }
///
/// Gets the short commit message which is usually the first line of the commit.
///
public virtual string MessageShort { get { return lazyShortMessage.Value; } }
///
/// Gets the encoding of the message.
///
public virtual string Encoding { get { return lazyEncoding.Value; } }
///
/// Gets the author of this commit.
///
public virtual Signature Author { get { return lazyAuthor.Value; } }
///
/// Gets the committer.
///
public virtual Signature Committer { get { return lazyCommitter.Value; } }
///
/// Gets the Tree associated to this commit.
///
public virtual Tree Tree { get { return lazyTree.Value; } }
///
/// Gets the parents of this commit. This property is lazy loaded and can throw an exception if the commit no longer exists in the repo.
///
public virtual IEnumerable Parents { get { return parents; } }
///
/// Gets the notes of this commit.
///
public virtual IEnumerable Notes { get { return lazyNotes.Value; } }
private string ExtractShortMessage()
{
if (Message == null)
{
return string.Empty; //TODO: Add some test coverage
}
return Message.Split('\n')[0];
}
private IEnumerable RetrieveNotesOfCommit(ObjectId oid)
{
return repo.Notes[oid];
}
private static string RetrieveEncodingOf(GitObjectSafeHandle obj)
{
string encoding = Proxy.git_commit_message_encoding(obj);
return encoding ?? "UTF-8";
}
private string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"{0} {1}", Id.ToString(7), MessageShort);
}
}
private class ParentsCollection : ICollection
{
private readonly Lazy> _parents;
private readonly Lazy _count;
public ParentsCollection(Repository repo, ObjectId commitId)
{
_count = new Lazy(() => Proxy.git_commit_parentcount(repo.Handle, commitId));
_parents = new Lazy>(() => RetrieveParentsOfCommit(repo, commitId));
}
private ICollection RetrieveParentsOfCommit(Repository repo, ObjectId commitId)
{
using (var obj = new ObjectSafeWrapper(commitId, repo.Handle))
{
int parentsCount = _count.Value;
var parents = new List(parentsCount);
for (uint i = 0; i < parentsCount; i++)
{
ObjectId parentCommitId = Proxy.git_commit_parent_oid(obj.ObjectPtr, i);
parents.Add(new Commit(repo, parentCommitId));
}
return parents;
}
}
public IEnumerator GetEnumerator()
{
return _parents.Value.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(Commit item)
{
throw new NotSupportedException();
}
public void Clear()
{
throw new NotSupportedException();
}
public bool Contains(Commit item)
{
return _parents.Value.Contains(item);
}
public void CopyTo(Commit[] array, int arrayIndex)
{
_parents.Value.CopyTo(array, arrayIndex);
}
public bool Remove(Commit item)
{
throw new NotSupportedException();
}
public int Count
{
get { return _count.Value; }
}
public bool IsReadOnly
{
get { return true; }
}
}
}
}