using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Compat;
namespace LibGit2Sharp
{
///
/// Holds the result of the determination of the state of the working directory.
/// Only files that differ from the current index and/or commit will be considered.
///
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class RepositoryStatus : IEnumerable
{
private readonly ICollection statusEntries;
private readonly List added = new List();
private readonly List staged = new List();
private readonly List removed = new List();
private readonly List missing = new List();
private readonly List modified = new List();
private readonly List untracked = new List();
private readonly List ignored = new List();
private readonly bool isDirty;
private readonly IDictionary> dispatcher = Build();
private static IDictionary> Build()
{
return new Dictionary>
{
{ FileStatus.Untracked, (rs, s) => rs.untracked.Add(s) },
{ FileStatus.Modified, (rs, s) => rs.modified.Add(s) },
{ FileStatus.Missing, (rs, s) => rs.missing.Add(s) },
{ FileStatus.Added, (rs, s) => rs.added.Add(s) },
{ FileStatus.Staged, (rs, s) => rs.staged.Add(s) },
{ FileStatus.Removed, (rs, s) => rs.removed.Add(s) },
{ FileStatus.Ignored, (rs, s) => rs.ignored.Add(s) },
};
}
///
/// Needed for mocking purposes.
///
protected RepositoryStatus()
{ }
internal RepositoryStatus(Repository repo)
{
statusEntries = Proxy.git_status_foreach(repo.Handle, StateChanged);
isDirty = statusEntries.Any(entry => entry.State != FileStatus.Ignored);
}
private StatusEntry StateChanged(IntPtr filePathPtr, uint state)
{
var filePath = FilePathMarshaler.FromNative(filePathPtr);
var gitStatus = (FileStatus)state;
foreach (KeyValuePair> kvp in dispatcher)
{
if (!gitStatus.HasFlag(kvp.Key))
{
continue;
}
kvp.Value(this, filePath.Native);
}
return new StatusEntry(filePath.Native, gitStatus);
}
///
/// Gets the for the specified relative path.
///
public virtual FileStatus this[string path]
{
get
{
Ensure.ArgumentNotNullOrEmptyString(path, "path");
var entries = statusEntries.Where(e => string.Equals(e.FilePath, path, StringComparison.Ordinal)).ToList();
Debug.Assert(!(entries.Count > 1));
if (entries.Count == 0)
{
return FileStatus.Nonexistent;
}
return entries.Single().State;
}
}
///
/// Returns an enumerator that iterates through the collection.
///
/// An object that can be used to iterate through the collection.
public virtual IEnumerator GetEnumerator()
{
return statusEntries.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();
}
///
/// List of files added to the index, which are not in the current commit
///
public virtual IEnumerable Added
{
get { return added; }
}
///
/// List of files added to the index, which are already in the current commit with different content
///
public virtual IEnumerable Staged
{
get { return staged; }
}
///
/// List of files removed from the index but are existent in the current commit
///
public virtual IEnumerable Removed
{
get { return removed; }
}
///
/// List of files existent in the index but are missing in the working directory
///
public virtual IEnumerable Missing
{
get { return missing; }
}
///
/// List of files with unstaged modifications. A file may be modified and staged at the same time if it has been modified after adding.
///
public virtual IEnumerable Modified
{
get { return modified; }
}
///
/// List of files existing in the working directory but are neither tracked in the index nor in the current commit.
///
public virtual IEnumerable Untracked
{
get { return untracked; }
}
///
/// List of files existing in the working directory that are ignored.
///
public virtual IEnumerable Ignored
{
get { return ignored; }
}
///
/// True if the index or the working directory has been altered since the last commit. False otherwise.
///
public virtual bool IsDirty
{
get { return isDirty; }
}
private string DebuggerDisplay
{
get
{
return string.Format(
CultureInfo.InvariantCulture,
"+{0} ~{1} -{2} | +{3} ~{4} -{5} | i{6}",
Added.Count(), Staged.Count(), Removed.Count(),
Untracked.Count(), Modified.Count(), Missing.Count(),
Ignored.Count());
}
}
}
}