using System;
using System.Globalization;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Compat;
namespace LibGit2Sharp
{
///
/// A Reference to another git object
///
public abstract class Reference : IEquatable
{
private static readonly LambdaEqualityHelper equalityHelper =
new LambdaEqualityHelper(new Func[] { x => x.CanonicalName, x => x.TargetIdentifier });
///
/// Gets the full name of this reference.
///
public string CanonicalName { get; protected set; }
internal static T BuildFromPtrAndRelease(IntPtr ptr, Repository repo) where T : Reference
{
var reference = BuildFromPtr(ptr, repo);
NativeMethods.git_reference_free(ptr);
return reference;
}
private static T BuildFromPtr(IntPtr ptr, Repository repo) where T : Reference
{
if (ptr == IntPtr.Zero)
{
return default(T);
}
string name = NativeMethods.git_reference_name(ptr);
GitReferenceType type = NativeMethods.git_reference_type(ptr);
Reference reference;
switch (type)
{
case GitReferenceType.Symbolic:
IntPtr resolveRef;
var targetIdentifier = NativeMethods.git_reference_target(ptr);
int res = NativeMethods.git_reference_resolve(out resolveRef, ptr);
if (res == (int)GitErrorCode.GIT_ENOTFOUND)
{
reference = new SymbolicReference { CanonicalName = name, Target = null, TargetIdentifier = targetIdentifier };
break;
}
Ensure.Success(res);
var targetRef = BuildFromPtrAndRelease(resolveRef, repo);
reference = new SymbolicReference { CanonicalName = name, Target = targetRef, TargetIdentifier = targetIdentifier };
break;
case GitReferenceType.Oid:
IntPtr oidPtr = NativeMethods.git_reference_oid(ptr);
var targetOid = new ObjectId(oidPtr.MarshalAsOid());
var targetBuilder = new Lazy(() => repo.Lookup(targetOid));
reference = new DirectReference(targetBuilder) { CanonicalName = name, TargetIdentifier = targetOid.Sha };
break;
default:
throw new LibGit2Exception(String.Format(CultureInfo.InvariantCulture, "Unable to build a new reference from a type '{0}'.", Enum.GetName(typeof(GitReferenceType), type)));
}
return reference as T;
}
///
/// Recursively peels the target of the reference until a direct reference is encountered.
///
/// The this points to.
public abstract DirectReference ResolveToDirectReference();
///
/// Gets the target declared by the reference.
///
/// If this reference is a , returns the canonical name of the target.
/// Otherwise, if this reference is a , returns the sha of the target.
///
///
// TODO: Maybe find a better name for this property.
public string TargetIdentifier { get; private set; }
///
/// Determines whether the specified is equal to the current .
///
/// The to compare with the current .
/// True if the specified is equal to the current ; otherwise, false.
public override bool Equals(object obj)
{
return Equals(obj as Reference);
}
///
/// Determines whether the specified is equal to the current .
///
/// The to compare with the current .
/// True if the specified is equal to the current ; otherwise, false.
public bool Equals(Reference other)
{
return equalityHelper.Equals(this, other);
}
///
/// Returns the hash code for this instance.
///
/// A 32-bit signed integer hash code.
public override int GetHashCode()
{
return equalityHelper.GetHashCode(this);
}
///
/// Tests if two are equal.
///
/// First to compare.
/// Second to compare.
/// True if the two objects are equal; false otherwise.
public static bool operator ==(Reference left, Reference right)
{
return Equals(left, right);
}
///
/// Tests if two are different.
///
/// First to compare.
/// Second to compare.
/// True if the two objects are different; false otherwise.
public static bool operator !=(Reference left, Reference right)
{
return !Equals(left, right);
}
///
/// Returns the , a representation of the current .
///
/// The that represents the current .
public override string ToString()
{
return CanonicalName;
}
}
}