using System;
using System.Diagnostics;
using System.Globalization;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;
namespace LibGit2Sharp
{
///
/// A Reference to another git object
///
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public abstract class Reference : IEquatable, IBelongToARepository
{
private static readonly LambdaEqualityHelper equalityHelper =
new LambdaEqualityHelper(x => x.CanonicalName, x => x.TargetIdentifier);
private readonly IRepository repo;
private readonly string canonicalName;
private readonly string targetIdentifier;
///
/// Needed for mocking purposes.
///
protected Reference()
{ }
///
/// This would be protected+internal, were that supported by C#.
/// Do not use except in subclasses.
///
internal Reference(IRepository repo, string canonicalName, string targetIdentifier)
{
this.repo = repo;
this.canonicalName = canonicalName;
this.targetIdentifier = targetIdentifier;
}
internal static T BuildFromPtr(ReferenceSafeHandle handle, Repository repo) where T : Reference
{
GitReferenceType type = Proxy.git_reference_type(handle);
string name = Proxy.git_reference_name(handle);
Reference reference;
switch (type)
{
case GitReferenceType.Symbolic:
string targetIdentifier = Proxy.git_reference_symbolic_target(handle);
var targetRef = repo.Refs[targetIdentifier];
reference = new SymbolicReference(repo, name, targetIdentifier, targetRef);
break;
case GitReferenceType.Oid:
ObjectId targetOid = Proxy.git_reference_target(handle);
reference = new DirectReference(name, repo, targetOid);
break;
default:
throw new LibGit2SharpException(String.Format(CultureInfo.InvariantCulture, "Unable to build a new reference from a type '{0}'.", type));
}
return reference as T;
}
///
/// Determines if the proposed reference name is well-formed.
///
///
/// - Top-level names must contain only capital letters and underscores,
/// and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD").
///
/// - Names prefixed with "refs/" can be almost anything. You must avoid
/// the characters '~', '^', ':', '\\', '?', '[', and '*', and the
/// sequences ".." and "@{" which have special meaning to revparse.
///
/// The name to be checked.
/// true is the name is valid; false otherwise.
public static bool IsValidName(string canonicalName)
{
return Proxy.git_reference_is_valid_name(canonicalName);
}
///
/// Gets the full name of this reference.
///
public virtual string CanonicalName
{
get { return canonicalName; }
}
///
/// 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 virtual string TargetIdentifier
{
get { return targetIdentifier; }
}
///
/// 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;
}
internal static string LocalBranchPrefix
{
get { return "refs/heads/"; }
}
internal static string RemoteTrackingBranchPrefix
{
get { return "refs/remotes/"; }
}
internal static string TagPrefix
{
get { return "refs/tags/"; }
}
internal static string NotePrefix
{
get { return "refs/notes/"; }
}
private string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"{0} => \"{1}\"", CanonicalName, TargetIdentifier);
}
}
IRepository IBelongToARepository.Repository { get { return repo; } }
}
}