#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

197 lines
5.6 KiB

// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using ICSharpCode.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using ICSharpCode.SharpDevelop.Util;
namespace ICSharpCode.GitAddIn
{
public enum GitStatus
{
None,
Added,
Modified,
Deleted,
OK,
Ignored
}
public static class GitStatusCache
{
static List<KeyValuePair<string, GitStatusSet>> statusSetDict = new List<KeyValuePair<string, GitStatusSet>>();
public static void ClearCachedStatus(string fileName)
{
lock (statusSetDict) {
for (int i = 0; i < statusSetDict.Count; i++) {
if (FileUtility.IsBaseDirectory(statusSetDict[i].Key, fileName)) {
statusSetDict.RemoveAt(i--);
}
}
}
}
public static GitStatus GetFileStatus(string fileName)
{
string wcroot = Git.FindWorkingCopyRoot(fileName);
if (wcroot == null)
return GitStatus.None;
GitStatusSet gss = GetStatusSet(wcroot);
return gss.GetStatus(Git.AdaptFileNameNoQuotes(wcroot, fileName));
}
public static GitStatusSet GetStatusSet(string wcRoot)
{
lock (statusSetDict) {
GitStatusSet statusSet;
foreach (var pair in statusSetDict) {
if (FileUtility.IsEqualFileName(pair.Key, wcRoot))
return pair.Value;
}
statusSet = new GitStatusSet();
GitGetFiles(wcRoot, statusSet);
GitGetStatus(wcRoot, statusSet);
statusSetDict.Add(new KeyValuePair<string, GitStatusSet>(wcRoot, statusSet));
return statusSet;
}
}
static void GitGetFiles(string wcRoot, GitStatusSet statusSet)
{
ProcessRunner runner = new ProcessRunner();
runner.WorkingDirectory = wcRoot;
runner.LogStandardOutputAndError = false;
runner.OutputLineReceived += delegate(object sender, LineReceivedEventArgs e) {
if (!string.IsNullOrEmpty(e.Line)) {
statusSet.AddEntry(e.Line, GitStatus.OK);
}
};
string command = "git ls-files";
bool hasErrors = false;
runner.ErrorLineReceived += delegate(object sender, LineReceivedEventArgs e) {
if (!hasErrors) {
hasErrors = true;
GitMessageView.AppendLine(runner.WorkingDirectory + "> " + command);
}
GitMessageView.AppendLine(e.Line);
};
runner.Start("cmd", "/c " + command);
runner.WaitForExit();
}
static void GitGetStatus(string wcRoot, GitStatusSet statusSet)
{
string command = "git status --porcelain --untracked-files=no";
bool hasErrors = false;
ProcessRunner runner = new ProcessRunner();
runner.WorkingDirectory = wcRoot;
runner.LogStandardOutputAndError = false;
string commandPrompt = wcRoot + ">@"; // C:\work\SD>@git.exe %*
runner.OutputLineReceived += delegate(object sender, LineReceivedEventArgs e) {
if (!string.IsNullOrEmpty(e.Line)) {
Match m = statusParseRegex.Match(e.Line);
if (m.Success) {
statusSet.AddEntry(m.Groups[2].Value, StatusFromText(m.Groups[1].Value));
} else if (!e.Line.StartsWith(commandPrompt, StringComparison.Ordinal)) {
// Suppress "unknown output" produced by git.cmd when git is installed
// in the PATH but the git unix tools aren't
if (!hasErrors) {
// in front of first output line, print the command line we invoked
hasErrors = true;
GitMessageView.AppendLine(runner.WorkingDirectory + "> " + command);
}
GitMessageView.AppendLine("unknown output: " + e.Line);
}
}
};
runner.ErrorLineReceived += delegate(object sender, LineReceivedEventArgs e) {
if (!hasErrors) {
hasErrors = true;
GitMessageView.AppendLine(runner.WorkingDirectory + "> " + command);
}
GitMessageView.AppendLine(e.Line);
};
runner.Start("cmd", "/c " + command);
runner.WaitForExit();
}
static GitStatus StatusFromText(string text)
{
if (text.Contains("A"))
return GitStatus.Added;
else if (text.Contains("D"))
return GitStatus.Deleted;
else if (text.Contains("M"))
return GitStatus.Modified;
else
return GitStatus.None;
}
static readonly Regex statusParseRegex = new Regex(@"^([DMA ][DMA ])\s(\S.*)$");
}
public class GitStatusSet
{
Dictionary<string, GitStatusSet> entries;
GitStatus status = GitStatus.OK;
public GitStatus AddEntry(string path, GitStatus status)
{
if (string.IsNullOrEmpty(path) || path == ".") {
this.status = status;
return status;
}
if (entries == null)
entries = new Dictionary<string, GitStatusSet>();
string entry;
string subpath;
int pos = path.IndexOf('/');
if (pos < 0) {
entry = path;
subpath = null;
} else {
entry = path.Substring(0, pos);
subpath = path.Substring(pos + 1);
}
GitStatusSet subset;
if (!entries.TryGetValue(entry, out subset))
entries[entry] = subset = new GitStatusSet();
status = subset.AddEntry(subpath, status);
if (status == GitStatus.Added || status == GitStatus.Deleted || status == GitStatus.Modified) {
this.status = GitStatus.Modified;
}
return this.status;
}
public GitStatus GetStatus(string path)
{
if (string.IsNullOrEmpty(path) || path == ".")
return status;
if (entries == null)
return GitStatus.None;
string entry;
string subpath;
int pos = path.IndexOf('/');
if (pos < 0) {
entry = path;
subpath = null;
} else {
entry = path.Substring(0, pos);
subpath = path.Substring(pos + 1);
}
GitStatusSet subset;
if (!entries.TryGetValue(entry, out subset))
return GitStatus.None;
else
return subset.GetStatus(subpath);
}
}
}