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; } } } }