using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
namespace SourceGit.Commands {
///
/// 用于取消命令执行的上下文对象
///
public class Context {
public bool IsCancelRequested { get; set; } = false;
}
///
/// 命令接口
///
public class Command {
///
/// 读取全部输出时的结果
///
public class ReadToEndResult {
public bool IsSuccess { get; set; }
public string Output { get; set; }
public string Error { get; set; }
}
///
/// 上下文
///
public Context Ctx { get; set; } = null;
///
/// 运行路径
///
public string Cwd { get; set; } = "";
///
/// 参数
///
public string Args { get; set; } = "";
///
/// 是否忽略错误
///
public bool DontRaiseError { get; set; } = false;
///
/// 使用标准错误输出
///
public bool TraitErrorAsOutput { get; set; } = false;
///
/// 运行
///
public bool Exec() {
var start = new ProcessStartInfo();
start.FileName = Models.Preference.Instance.Git.Path;
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
start.UseShellExecute = false;
start.CreateNoWindow = true;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.StandardOutputEncoding = Encoding.UTF8;
start.StandardErrorEncoding = Encoding.UTF8;
if (!string.IsNullOrEmpty(Cwd)) start.WorkingDirectory = Cwd;
var progressFilter = new Regex(@"\s\d+%\s");
var errs = new List();
var proc = new Process() { StartInfo = start };
var isCancelled = false;
proc.OutputDataReceived += (o, e) => {
if (Ctx != null && Ctx.IsCancelRequested) {
isCancelled = true;
proc.CancelErrorRead();
proc.CancelOutputRead();
if (!proc.HasExited) proc.Kill();
return;
}
if (e.Data == null) return;
OnReadline(e.Data);
};
proc.ErrorDataReceived += (o, e) => {
if (Ctx != null && Ctx.IsCancelRequested) {
isCancelled = true;
proc.CancelErrorRead();
proc.CancelOutputRead();
if (!proc.HasExited) proc.Kill();
return;
}
if (string.IsNullOrEmpty(e.Data)) return;
if (TraitErrorAsOutput) OnReadline(e.Data);
if (progressFilter.IsMatch(e.Data)) return;
if (e.Data.StartsWith("remote: Counting objects:", StringComparison.Ordinal)) return;
errs.Add(e.Data);
};
try {
proc.Start();
} catch (Exception e) {
if (!DontRaiseError) OnException(e.Message);
return false;
}
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
int exitCode = proc.ExitCode;
proc.Close();
if (!isCancelled && exitCode != 0 && errs.Count > 0) {
if (!DontRaiseError) OnException(string.Join("\n", errs));
return false;
} else {
return true;
}
}
///
/// 直接读取全部标准输出
///
public ReadToEndResult ReadToEnd() {
var start = new ProcessStartInfo();
start.FileName = Models.Preference.Instance.Git.Path;
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
start.UseShellExecute = false;
start.CreateNoWindow = true;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.StandardOutputEncoding = Encoding.UTF8;
start.StandardErrorEncoding = Encoding.UTF8;
if (!string.IsNullOrEmpty(Cwd)) start.WorkingDirectory = Cwd;
var proc = new Process() { StartInfo = start };
try {
proc.Start();
} catch (Exception e) {
return new ReadToEndResult() {
Output = string.Empty,
Error = e.Message,
IsSuccess = false,
};
}
var rs = new ReadToEndResult();
rs.Output = proc.StandardOutput.ReadToEnd();
rs.Error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
rs.IsSuccess = proc.ExitCode == 0;
proc.Close();
return rs;
}
///
/// 调用Exec时的读取函数
///
///
public virtual void OnReadline(string line) {
}
///
/// 默认异常处理函数
///
///
public virtual void OnException(string message) {
Models.Exception.Raise(message);
}
}
}