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 collection of exposed in the .
///
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class NoteCollection : IEnumerable
{
internal readonly Repository repo;
private readonly Lazy defaultNamespace;
///
/// Needed for mocking purposes.
///
protected NoteCollection()
{ }
internal NoteCollection(Repository repo)
{
this.repo = repo;
defaultNamespace = new Lazy(RetrieveDefaultNamespace);
}
#region Implementation of IEnumerable
///
/// Returns an enumerator that iterates through the collection.
///
/// An object that can be used to iterate through the collection.
public virtual IEnumerator GetEnumerator()
{
return this[DefaultNamespace].GetEnumerator();
}
///
/// Returns an enumerator that iterates through the collection.
///
/// An object that can be used to iterate through the collection.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
///
/// The default namespace for notes.
///
public virtual string DefaultNamespace
{
get { return defaultNamespace.Value; }
}
///
/// The list of canonicalized namespaces related to notes.
///
public virtual IEnumerable Namespaces
{
get
{
return NamespaceRefs.Select(UnCanonicalizeName);
}
}
internal IEnumerable NamespaceRefs
{
get
{
return new[] { NormalizeToCanonicalName(DefaultNamespace) }.Concat(
from reference in repo.Refs
select reference.CanonicalName into refCanonical
where refCanonical.StartsWith(Reference.NotePrefix, StringComparison.Ordinal) && refCanonical != NormalizeToCanonicalName(DefaultNamespace)
select refCanonical);
}
}
///
/// Gets the collection of associated with the specified .
///
public virtual IEnumerable this[ObjectId id]
{
get
{
Ensure.ArgumentNotNull(id, "id");
return NamespaceRefs
.Select(ns => this[ns, id])
.Where(n => n != null);
}
}
///
/// Gets the collection of associated with the specified namespace.
/// This is similar to the 'get notes list' command.
///
public virtual IEnumerable this[string @namespace]
{
get
{
Ensure.ArgumentNotNull(@namespace, "@namespace");
string canonicalNamespace = NormalizeToCanonicalName(@namespace);
return Proxy.git_note_foreach(repo.Handle, canonicalNamespace,
(blobId,annotatedObjId) => this[canonicalNamespace, annotatedObjId]);
}
}
///
/// Gets the associated with the specified objectId and the specified namespace.
///
public virtual Note this[string @namespace, ObjectId id]
{
get
{
Ensure.ArgumentNotNull(id, "id");
Ensure.ArgumentNotNull(@namespace, "@namespace");
string canonicalNamespace = NormalizeToCanonicalName(@namespace);
using (NoteSafeHandle noteHandle = Proxy.git_note_read(repo.Handle, canonicalNamespace, id))
{
return noteHandle == null
? null
: Note.BuildFromPtr(noteHandle, UnCanonicalizeName(canonicalNamespace), id);
}
}
}
private string RetrieveDefaultNamespace()
{
string notesRef = Proxy.git_note_default_ref(repo.Handle);
return UnCanonicalizeName(notesRef);
}
internal static string NormalizeToCanonicalName(string name)
{
Ensure.ArgumentNotNullOrEmptyString(name, "name");
if (name.LooksLikeNote())
{
return name;
}
return string.Concat(Reference.NotePrefix, name);
}
internal string UnCanonicalizeName(string name)
{
Ensure.ArgumentNotNullOrEmptyString(name, "name");
if (!name.LooksLikeNote())
{
return name;
}
return name.Substring(Reference.NotePrefix.Length);
}
///
/// Creates or updates a on the specified object, and for the given namespace.
///
/// The target , for which the note will be created.
/// The note message.
/// The author.
/// The committer.
/// The namespace on which the note will be created. It can be either a canonical namespace or an abbreviated namespace ('refs/notes/myNamespace' or just 'myNamespace').
/// The note which was just saved.
public virtual Note Add(ObjectId targetId, string message, Signature author, Signature committer, string @namespace)
{
Ensure.ArgumentNotNull(targetId, "targetId");
Ensure.ArgumentNotNullOrEmptyString(message, "message");
Ensure.ArgumentNotNull(author, "author");
Ensure.ArgumentNotNull(committer, "committer");
Ensure.ArgumentNotNullOrEmptyString(@namespace, "@namespace");
string canonicalNamespace = NormalizeToCanonicalName(@namespace);
Remove(targetId, author, committer, @namespace);
Proxy.git_note_create(repo.Handle, author, committer, canonicalNamespace, targetId, message, true);
return this[canonicalNamespace, targetId];
}
///
/// Deletes the note on the specified object, and for the given namespace.
///
/// The target , for which the note will be created.
/// The author.
/// The committer.
/// The namespace on which the note will be removed. It can be either a canonical namespace or an abbreviated namespace ('refs/notes/myNamespace' or just 'myNamespace').
public virtual void Remove(ObjectId targetId, Signature author, Signature committer, string @namespace)
{
Ensure.ArgumentNotNull(targetId, "targetId");
Ensure.ArgumentNotNull(author, "author");
Ensure.ArgumentNotNull(committer, "committer");
Ensure.ArgumentNotNullOrEmptyString(@namespace, "@namespace");
string canonicalNamespace = NormalizeToCanonicalName(@namespace);
Proxy.git_note_remove(repo.Handle, canonicalNamespace, author, committer, targetId);
}
private string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"Count = {0}", this.Count());
}
}
}
}