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