using System; using System.Globalization; using LibGit2Sharp.Core; using LibGit2Sharp.Core.Handles; namespace LibGit2Sharp { /// /// Provides helper overloads to a . /// public static class ReferenceCollectionExtensions { private enum RefState { Exists, DoesNotExistButLooksValid, DoesNotLookValid, } private static RefState TryResolveReference(out Reference reference, ReferenceCollection refsColl, string canonicalName) { if (!refsColl.IsValidName(canonicalName)) { reference = null; return RefState.DoesNotLookValid; } reference = refsColl[canonicalName]; return reference != null ? RefState.Exists : RefState.DoesNotExistButLooksValid; } /// /// Creates a direct or symbolic reference with the specified name and target /// /// The name of the reference to create. /// The target which can be either the canonical name of a reference or a revparse spec. /// True to allow silent overwriting a potentially existing reference, false otherwise. /// The being worked with. /// The optional message to log in the when adding the /// A new . public static Reference Add(this ReferenceCollection refsColl, string name, string canonicalRefNameOrObjectish, bool allowOverwrite = false, string logMessage = null) { Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNullOrEmptyString(canonicalRefNameOrObjectish, "canonicalRefNameOrObjectish"); Reference reference; RefState refState = TryResolveReference(out reference, refsColl, canonicalRefNameOrObjectish); var gitObject = refsColl.repo.Lookup(canonicalRefNameOrObjectish, GitObjectType.Any, LookUpOptions.None); if (refState == RefState.Exists) { return refsColl.Add(name, reference, allowOverwrite, logMessage); } if (refState == RefState.DoesNotExistButLooksValid && gitObject == null) { using (ReferenceSafeHandle handle = Proxy.git_reference_symbolic_create(refsColl.repo.Handle, name, canonicalRefNameOrObjectish, allowOverwrite)) { return Reference.BuildFromPtr(handle, refsColl.repo); } } Ensure.GitObjectIsNotNull(gitObject, canonicalRefNameOrObjectish); return refsColl.Add(name, gitObject.Id, allowOverwrite, logMessage); } /// /// Updates the target of a direct reference. /// /// The direct reference which target should be updated. /// The revparse spec of the target. /// The being worked with. /// The optional message to log in the of the reference. /// A new . public static Reference UpdateTarget(this ReferenceCollection refsColl, Reference directRef, string objectish, string logMessage = null) { Ensure.ArgumentNotNull(directRef, "directRef"); Ensure.ArgumentNotNull(objectish, "objectish"); GitObject target = refsColl.repo.Lookup(objectish); Ensure.GitObjectIsNotNull(target, objectish); return refsColl.UpdateTarget(directRef, target.Id, logMessage); } /// /// Rename an existing reference with a new name /// /// The canonical name of the reference to rename. /// The new canonical name. /// True to allow silent overwriting a potentially existing reference, false otherwise. /// The being worked with. /// A new . public static Reference Move(this ReferenceCollection refsColl, string currentName, string newName, bool allowOverwrite = false) { Ensure.ArgumentNotNullOrEmptyString(currentName, "currentName"); Reference reference = refsColl[currentName]; if (reference == null) { throw new LibGit2SharpException( string.Format(CultureInfo.InvariantCulture, "Reference '{0}' doesn't exist. One cannot move a non existing reference.", currentName)); } return refsColl.Move(reference, newName, allowOverwrite); } /// /// Updates the target of a reference. /// /// The canonical name of the reference. /// The target which can be either the canonical name of a reference or a revparse spec. /// The being worked with. /// The optional message to log in the of the reference. /// A new . public static Reference UpdateTarget(this ReferenceCollection refsColl, string name, string canonicalRefNameOrObjectish, string logMessage = null) { Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNullOrEmptyString(canonicalRefNameOrObjectish, "canonicalRefNameOrObjectish"); if (name == "HEAD") { return refsColl.Add("HEAD", canonicalRefNameOrObjectish, true); } Reference reference = refsColl[name]; var directReference = reference as DirectReference; if (directReference != null) { return refsColl.UpdateTarget(directReference, canonicalRefNameOrObjectish, logMessage); } var symbolicReference = reference as SymbolicReference; if (symbolicReference != null) { Reference targetRef; RefState refState = TryResolveReference(out targetRef, refsColl, canonicalRefNameOrObjectish); if (refState == RefState.DoesNotLookValid) { throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is a Symbolic reference, you must provide a reference canonical name as the target.", name), "canonicalRefNameOrObjectish"); } return refsColl.UpdateTarget(symbolicReference, targetRef, logMessage); } throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture, "Reference '{0}' has an unexpected type ('{1}').", name, reference.GetType())); } /// /// Delete a reference with the specified name /// /// The being worked with. /// The canonical name of the reference to delete. public static void Remove(this ReferenceCollection refsColl, string name) { Ensure.ArgumentNotNullOrEmptyString(name, "name"); Reference reference = refsColl[name]; if (reference == null) { return; } refsColl.Remove(reference); } } }