using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;
namespace LibGit2Sharp
{
///
/// The collection of Branches in a
///
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class BranchCollection : IEnumerable
{
internal readonly Repository repo;
///
/// Needed for mocking purposes.
///
protected BranchCollection()
{ }
///
/// Initializes a new instance of the class.
///
/// The repo.
internal BranchCollection(Repository repo)
{
this.repo = repo;
}
///
/// Gets the with the specified name.
///
public virtual Branch this[string name]
{
get
{
Ensure.ArgumentNotNullOrEmptyString(name, "name");
if (LooksLikeABranchName(name))
{
return BuildFromReferenceName(name);
}
Branch branch = BuildFromReferenceName(ShortToLocalName(name));
if (branch != null)
{
return branch;
}
branch = BuildFromReferenceName(ShortToRemoteName(name));
if (branch != null)
{
return branch;
}
return BuildFromReferenceName(ShortToRefName(name));
}
}
private static string ShortToLocalName(string name)
{
return string.Format(CultureInfo.InvariantCulture, "{0}{1}", Reference.LocalBranchPrefix, name);
}
private static string ShortToRemoteName(string name)
{
return string.Format(CultureInfo.InvariantCulture, "{0}{1}", Reference.RemoteTrackingBranchPrefix, name);
}
private static string ShortToRefName(string name)
{
return string.Format(CultureInfo.InvariantCulture, "{0}{1}", "refs/", name);
}
private Branch BuildFromReferenceName(string canonicalName)
{
var reference = repo.Refs.Resolve(canonicalName);
return reference == null ? null : new Branch(repo, reference, canonicalName);
}
#region IEnumerable Members
///
/// Returns an enumerator that iterates through the collection.
///
/// An object that can be used to iterate through the collection.
public virtual IEnumerator GetEnumerator()
{
return Proxy.git_branch_foreach(repo.Handle, GitBranchType.GIT_BRANCH_LOCAL | GitBranchType.GIT_BRANCH_REMOTE, branchToCanoncialName)
.Select(n => this[n])
.GetEnumerator();
}
///
/// Returns an enumerator that iterates through the collection.
///
/// An object that can be used to iterate through the collection.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
///
/// Create a new local branch with the specified name
///
/// The name of the branch.
/// The target commit.
/// True to allow silent overwriting a potentially existing branch, false otherwise.
/// A new .
public virtual Branch Add(string name, Commit commit, bool allowOverwrite = false)
{
Ensure.ArgumentNotNullOrEmptyString(name, "name");
Ensure.ArgumentNotNull(commit, "commit");
using (Proxy.git_branch_create(repo.Handle, name, commit.Id, allowOverwrite)) {}
return this[ShortToLocalName(name)];
}
///
/// Deletes the specified branch.
///
/// The branch to delete.
public virtual void Remove(Branch branch)
{
Ensure.ArgumentNotNull(branch, "branch");
using (ReferenceSafeHandle referencePtr = repo.Refs.RetrieveReferencePtr(branch.CanonicalName))
{
Proxy.git_branch_delete(referencePtr);
}
}
///
/// Renames an existing local branch with a new name.
///
/// The current local branch.
/// The new name the existing branch should bear.
/// True to allow silent overwriting a potentially existing branch, false otherwise.
/// A new .
public virtual Branch Move(Branch branch, string newName, bool allowOverwrite = false)
{
Ensure.ArgumentNotNull(branch, "branch");
Ensure.ArgumentNotNullOrEmptyString(newName, "newName");
if (branch.IsRemote)
{
throw new LibGit2SharpException(
string.Format(CultureInfo.InvariantCulture,
"Cannot rename branch '{0}'. It's a remote tracking branch.", branch.Name));
}
using (ReferenceSafeHandle referencePtr = repo.Refs.RetrieveReferencePtr(Reference.LocalBranchPrefix + branch.Name))
{
using (ReferenceSafeHandle ref_out = Proxy.git_branch_move(referencePtr, newName, allowOverwrite))
{
}
}
return this[newName];
}
///
/// Update properties of a branch.
///
/// The branch to update.
/// Delegate to perform updates on the branch.
/// The updated branch.
public virtual Branch Update(Branch branch, params Action[] actions)
{
var updater = new BranchUpdater(repo, branch);
foreach (Action action in actions)
{
action(updater);
}
return this[branch.Name];
}
private static bool LooksLikeABranchName(string referenceName)
{
return referenceName == "HEAD" ||
referenceName.LooksLikeLocalBranch() ||
referenceName.LooksLikeRemoteTrackingBranch();
}
private static string branchToCanoncialName(IntPtr namePtr, GitBranchType branchType)
{
string shortName = Utf8Marshaler.FromNative(namePtr);
switch (branchType)
{
case GitBranchType.GIT_BRANCH_LOCAL:
return ShortToLocalName(shortName);
case GitBranchType.GIT_BRANCH_REMOTE:
return ShortToRemoteName(shortName);
default:
return shortName;
}
}
private string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"Count = {0}", this.Count());
}
}
}
}