using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;
namespace LibGit2Sharp
{
///
/// A Commit
///
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class Commit : GitObject
{
private readonly GitObjectLazyGroup group1;
private readonly GitObjectLazyGroup group2;
private readonly ILazy lazyTree;
private readonly ILazy lazyAuthor;
private readonly ILazy lazyCommitter;
private readonly ILazy lazyMessage;
private readonly ILazy lazyMessageShort;
private readonly ILazy lazyEncoding;
private readonly ParentsCollection parents;
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_id(obj), null));
group1 = new GitObjectLazyGroup(this.repo, id);
lazyAuthor = group1.AddLazy(Proxy.git_commit_author);
lazyCommitter = group1.AddLazy(Proxy.git_commit_committer);
group2 = new GitObjectLazyGroup(this.repo, id);
lazyMessage = group2.AddLazy(Proxy.git_commit_message);
lazyMessageShort = group2.AddLazy(Proxy.git_commit_summary);
lazyEncoding = group2.AddLazy(RetrieveEncodingOf);
lazyNotes = new Lazy>(() => RetrieveNotesOfCommit(id).ToList());
parents = new ParentsCollection(repo, id);
}
///
/// Gets the pointed at by the in the .
///
/// Path to the from the tree in this
/// 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 lazyMessageShort.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 IEnumerable RetrieveNotesOfCommit(ObjectId oid)
{
return repo.Notes[oid];
}
private static string RetrieveEncodingOf(ObjectHandle obj)
{
string encoding = Proxy.git_commit_message_encoding(obj);
return encoding ?? "UTF-8";
}
///
/// Prettify a commit message
///
/// Remove comment lines and trailing lines
///
///
/// The prettified message
/// The message to prettify.
/// Comment character. Lines starting with it will be removed
public static string PrettifyMessage(string message, char commentChar)
{
return Proxy.git_message_prettify(message, commentChar);
}
private string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"{0} {1}",
Id.ToString(7),
MessageShort);
}
}
///
/// Extract the signature data from this commit
///
/// The signature and the signed data
/// The repository in which the object lives
/// The commit to extract the signature from
/// The header field which contains the signature; use null for the default of "gpgsig"
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id, string field)
{
return Proxy.git_commit_extract_signature(repo.Handle, id, field);
}
///
/// Extract the signature data from this commit
///
/// The overload uses the default header field "gpgsig"
///
///
/// The signature and the signed data
/// The repository in which the object lives
/// The commit to extract the signature from
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id)
{
return Proxy.git_commit_extract_signature(repo.Handle, id, null);
}
///
/// Create a commit in-memory
///
/// Prettifing the message includes:
/// * Removing empty lines from the beginning and end.
/// * Removing trailing spaces from every line.
/// * Turning multiple consecutive empty lines between paragraphs into just one empty line.
/// * Ensuring the commit message ends with a newline.
/// * Removing every line starting with the .
///
///
/// The of who made the change.
/// The of who added the change to the repository.
/// The description of why a change was made to the repository.
/// The of the to be created.
/// The parents of the to be created.
/// True to prettify the message, or false to leave it as is.
/// When non null, lines starting with this character will be stripped if prettifyMessage is true.
/// The contents of the commit object.
public static string CreateBuffer(Signature author, Signature committer, string message, Tree tree, IEnumerable parents, bool prettifyMessage, char? commentChar)
{
Ensure.ArgumentNotNull(message, "message");
Ensure.ArgumentDoesNotContainZeroByte(message, "message");
Ensure.ArgumentNotNull(author, "author");
Ensure.ArgumentNotNull(committer, "committer");
Ensure.ArgumentNotNull(tree, "tree");
Ensure.ArgumentNotNull(parents, "parents");
if (prettifyMessage)
{
message = Proxy.git_message_prettify(message, commentChar);
}
return Proxy.git_commit_create_buffer(tree.repo.Handle, author, committer, message, tree, parents.ToArray());
}
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_id(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; }
}
}
}
}