mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-05-23 13:14:59 +00:00
style: add .editorconfig for code formatting. see issu #25
This commit is contained in:
parent
a8eeea4f78
commit
18aaa0a143
225 changed files with 7781 additions and 3911 deletions
|
@ -1,18 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Add : Command {
|
||||
public Add(string repo, List<Models.Change> changes = null) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Add : Command
|
||||
{
|
||||
public Add(string repo, List<Models.Change> changes = null)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
||||
if (changes == null || changes.Count == 0) {
|
||||
if (changes == null || changes.Count == 0)
|
||||
{
|
||||
Args = "add .";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("add --");
|
||||
foreach (var c in changes) {
|
||||
foreach (var c in changes)
|
||||
{
|
||||
builder.Append(" \"");
|
||||
builder.Append(c.Path);
|
||||
builder.Append("\"");
|
||||
|
@ -21,4 +28,4 @@ namespace SourceGit.Commands {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class Apply : Command {
|
||||
public Apply(string repo, string file, bool ignoreWhitespace, string whitespaceMode, string extra) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Apply : Command
|
||||
{
|
||||
public Apply(string repo, string file, bool ignoreWhitespace, string whitespaceMode, string extra)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "apply ";
|
||||
|
@ -10,4 +13,4 @@
|
|||
Args += $"\"{file}\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Archive : Command {
|
||||
public Archive(string repo, string revision, string saveTo, Action<string> outputHandler) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Archive : Command
|
||||
{
|
||||
public Archive(string repo, string revision, string saveTo, Action<string> outputHandler)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"archive --format=zip --verbose --output=\"{saveTo}\" {revision}";
|
||||
|
@ -10,10 +13,11 @@ namespace SourceGit.Commands {
|
|||
_outputHandler = outputHandler;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +1,47 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class AssumeUnchanged {
|
||||
partial class ViewCommand : Command {
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class AssumeUnchanged
|
||||
{
|
||||
partial class ViewCommand : Command
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"^(\w)\s+(.+)$")]
|
||||
private static partial Regex REG();
|
||||
|
||||
public ViewCommand(string repo) {
|
||||
public ViewCommand(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Args = "ls-files -v";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public List<string> Result() {
|
||||
public List<string> Result()
|
||||
{
|
||||
Exec();
|
||||
return _outs;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG().Match(line);
|
||||
if (!match.Success) return;
|
||||
|
||||
if (match.Groups[1].Value == "h") {
|
||||
if (match.Groups[1].Value == "h")
|
||||
{
|
||||
_outs.Add(match.Groups[2].Value);
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> _outs = new List<string>();
|
||||
private readonly List<string> _outs = new List<string>();
|
||||
}
|
||||
|
||||
class ModCommand : Command {
|
||||
public ModCommand(string repo, string file, bool bAdd) {
|
||||
class ModCommand : Command
|
||||
{
|
||||
public ModCommand(string repo, string file, bool bAdd)
|
||||
{
|
||||
var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
|
||||
|
||||
WorkingDirectory = repo;
|
||||
|
@ -41,22 +50,26 @@ namespace SourceGit.Commands {
|
|||
}
|
||||
}
|
||||
|
||||
public AssumeUnchanged(string repo) {
|
||||
public AssumeUnchanged(string repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
public List<string> View() {
|
||||
public List<string> View()
|
||||
{
|
||||
return new ViewCommand(_repo).Result();
|
||||
}
|
||||
|
||||
public void Add(string file) {
|
||||
public void Add(string file)
|
||||
{
|
||||
new ModCommand(_repo, file, true).Exec();
|
||||
}
|
||||
|
||||
public void Remove(string file) {
|
||||
public void Remove(string file)
|
||||
{
|
||||
new ModCommand(_repo, file, false).Exec();
|
||||
}
|
||||
|
||||
private string _repo;
|
||||
private readonly string _repo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,17 @@
|
|||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class Blame : Command {
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class Blame : Command
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"^\^?([0-9a-f]+)\s+.*\((.*)\s+(\d+)\s+[\-\+]?\d+\s+\d+\) (.*)")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
private static readonly DateTime UTC_START = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
|
||||
|
||||
public Blame(string repo, string file, string revision) {
|
||||
public Blame(string repo, string file, string revision)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"blame -t {revision} -- \"{file}\"";
|
||||
|
@ -18,15 +21,20 @@ namespace SourceGit.Commands {
|
|||
_result.File = file;
|
||||
}
|
||||
|
||||
public Models.BlameData Result() {
|
||||
public Models.BlameData Result()
|
||||
{
|
||||
var succ = Exec();
|
||||
if (!succ) {
|
||||
if (!succ)
|
||||
{
|
||||
return new Models.BlameData();
|
||||
}
|
||||
|
||||
if (_needUnifyCommitSHA) {
|
||||
foreach (var line in _result.LineInfos) {
|
||||
if (line.CommitSHA.Length > _minSHALen) {
|
||||
if (_needUnifyCommitSHA)
|
||||
{
|
||||
foreach (var line in _result.LineInfos)
|
||||
{
|
||||
if (line.CommitSHA.Length > _minSHALen)
|
||||
{
|
||||
line.CommitSHA = line.CommitSHA.Substring(0, _minSHALen);
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +44,13 @@ namespace SourceGit.Commands {
|
|||
return _result;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
if (_result.IsBinary) return;
|
||||
if (string.IsNullOrEmpty(line)) return;
|
||||
|
||||
if (line.IndexOf('\0', StringComparison.Ordinal) >= 0) {
|
||||
if (line.IndexOf('\0', StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
_result.IsBinary = true;
|
||||
_result.LineInfos.Clear();
|
||||
return;
|
||||
|
@ -51,12 +61,13 @@ namespace SourceGit.Commands {
|
|||
|
||||
_content.AppendLine(match.Groups[4].Value);
|
||||
|
||||
var commit = match.Groups[1].Value;
|
||||
var commit = match.Groups[1].Value;
|
||||
var author = match.Groups[2].Value;
|
||||
var timestamp = int.Parse(match.Groups[3].Value);
|
||||
var when = UTC_START.AddSeconds(timestamp).ToString("yyyy/MM/dd");
|
||||
|
||||
var info = new Models.BlameLineInfo() {
|
||||
var info = new Models.BlameLineInfo()
|
||||
{
|
||||
IsFirstInGroup = commit != _lastSHA,
|
||||
CommitSHA = commit,
|
||||
Author = author,
|
||||
|
@ -66,16 +77,17 @@ namespace SourceGit.Commands {
|
|||
_result.LineInfos.Add(info);
|
||||
_lastSHA = commit;
|
||||
|
||||
if (line[0] == '^') {
|
||||
if (line[0] == '^')
|
||||
{
|
||||
_needUnifyCommitSHA = true;
|
||||
_minSHALen = Math.Min(_minSHALen, commit.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private Models.BlameData _result = new Models.BlameData();
|
||||
private StringBuilder _content = new StringBuilder();
|
||||
private readonly Models.BlameData _result = new Models.BlameData();
|
||||
private readonly StringBuilder _content = new StringBuilder();
|
||||
private string _lastSHA = string.Empty;
|
||||
private bool _needUnifyCommitSHA = false;
|
||||
private int _minSHALen = 64;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
namespace SourceGit.Commands {
|
||||
public static class Branch {
|
||||
public static bool Create(string repo, string name, string basedOn) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class Branch
|
||||
{
|
||||
public static bool Create(string repo, string name, string basedOn)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
|
@ -8,7 +11,8 @@
|
|||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool Rename(string repo, string name, string to) {
|
||||
public static bool Rename(string repo, string name, string to)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
|
@ -16,19 +20,24 @@
|
|||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool SetUpstream(string repo, string name, string upstream) {
|
||||
public static bool SetUpstream(string repo, string name, string upstream)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
if (string.IsNullOrEmpty(upstream)) {
|
||||
if (string.IsNullOrEmpty(upstream))
|
||||
{
|
||||
cmd.Args = $"branch {name} --unset-upstream";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Args = $"branch {name} -u {upstream}";
|
||||
}
|
||||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool Delete(string repo, string name) {
|
||||
public static bool Delete(string repo, string name)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
|
@ -36,4 +45,4 @@
|
|||
return cmd.Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,46 +2,58 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Checkout : Command {
|
||||
public Checkout(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Checkout : Command
|
||||
{
|
||||
public Checkout(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Branch(string branch, Action<string> onProgress) {
|
||||
public bool Branch(string branch, Action<string> onProgress)
|
||||
{
|
||||
Args = $"checkout --progress {branch}";
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = onProgress;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Branch(string branch, string basedOn, Action<string> onProgress) {
|
||||
public bool Branch(string branch, string basedOn, Action<string> onProgress)
|
||||
{
|
||||
Args = $"checkout --progress -b {branch} {basedOn}";
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = onProgress;
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool File(string file, bool useTheirs) {
|
||||
if (useTheirs) {
|
||||
public bool File(string file, bool useTheirs)
|
||||
{
|
||||
if (useTheirs)
|
||||
{
|
||||
Args = $"checkout --theirs -- \"{file}\"";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = $"checkout --ours -- \"{file}\"";
|
||||
}
|
||||
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool FileWithRevision(string file, string revision) {
|
||||
public bool FileWithRevision(string file, string revision)
|
||||
{
|
||||
Args = $"checkout {revision} -- \"{file}\"";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Files(List<string> files) {
|
||||
public bool Files(List<string> files)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append("checkout -f -q --");
|
||||
foreach (var f in files) {
|
||||
foreach (var f in files)
|
||||
{
|
||||
builder.Append(" \"");
|
||||
builder.Append(f);
|
||||
builder.Append("\"");
|
||||
|
@ -50,10 +62,11 @@ namespace SourceGit.Commands {
|
|||
return Exec();
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class CherryPick : Command {
|
||||
public CherryPick(string repo, string commit, bool noCommit) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class CherryPick : Command
|
||||
{
|
||||
public CherryPick(string repo, string commit, bool noCommit)
|
||||
{
|
||||
var mode = noCommit ? "-n" : "--ff";
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"cherry-pick {mode} {commit}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,23 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Clean : Command {
|
||||
public Clean(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Clean : Command
|
||||
{
|
||||
public Clean(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "clean -qfd";
|
||||
}
|
||||
|
||||
public Clean(string repo, List<string> files) {
|
||||
public Clean(string repo, List<string> files)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append("clean -qfd --");
|
||||
foreach (var f in files) {
|
||||
foreach (var f in files)
|
||||
{
|
||||
builder.Append(" \"");
|
||||
builder.Append(f);
|
||||
builder.Append("\"");
|
||||
|
@ -23,4 +28,4 @@ namespace SourceGit.Commands {
|
|||
Args = builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,23 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Clone : Command {
|
||||
private Action<string> _notifyProgress;
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Clone : Command
|
||||
{
|
||||
private readonly Action<string> _notifyProgress;
|
||||
|
||||
public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action<string> ouputHandler) {
|
||||
public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action<string> ouputHandler)
|
||||
{
|
||||
Context = ctx;
|
||||
WorkingDirectory = path;
|
||||
TraitErrorAsOutput = true;
|
||||
|
||||
if (string.IsNullOrEmpty(sshKey)) {
|
||||
if (string.IsNullOrEmpty(sshKey))
|
||||
{
|
||||
Args = "-c credential.helper=manager ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" ";
|
||||
}
|
||||
|
||||
|
@ -24,8 +30,9 @@ namespace SourceGit.Commands {
|
|||
_notifyProgress = ouputHandler;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_notifyProgress?.Invoke(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,22 @@
|
|||
using Avalonia.Threading;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class Command {
|
||||
public class CancelToken {
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class Command
|
||||
{
|
||||
public class CancelToken
|
||||
{
|
||||
public bool Requested { get; set; } = false;
|
||||
}
|
||||
|
||||
public class ReadToEndResult {
|
||||
public class ReadToEndResult
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
public string StdOut { get; set; }
|
||||
public string StdErr { get; set; }
|
||||
|
@ -24,7 +29,8 @@ namespace SourceGit.Commands {
|
|||
public bool RaiseError { get; set; } = true;
|
||||
public bool TraitErrorAsOutput { get; set; } = false;
|
||||
|
||||
public bool Exec() {
|
||||
public bool Exec()
|
||||
{
|
||||
var start = new ProcessStartInfo();
|
||||
start.FileName = Native.OS.GitInstallPath;
|
||||
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
|
||||
|
@ -41,8 +47,10 @@ namespace SourceGit.Commands {
|
|||
var proc = new Process() { StartInfo = start };
|
||||
var isCancelled = false;
|
||||
|
||||
proc.OutputDataReceived += (_, e) => {
|
||||
if (Cancel != null && Cancel.Requested) {
|
||||
proc.OutputDataReceived += (_, e) =>
|
||||
{
|
||||
if (Cancel != null && Cancel.Requested)
|
||||
{
|
||||
isCancelled = true;
|
||||
proc.CancelErrorRead();
|
||||
proc.CancelOutputRead();
|
||||
|
@ -53,8 +61,10 @@ namespace SourceGit.Commands {
|
|||
if (e.Data != null) OnReadline(e.Data);
|
||||
};
|
||||
|
||||
proc.ErrorDataReceived += (_, e) => {
|
||||
if (Cancel != null && Cancel.Requested) {
|
||||
proc.ErrorDataReceived += (_, e) =>
|
||||
{
|
||||
if (Cancel != null && Cancel.Requested)
|
||||
{
|
||||
isCancelled = true;
|
||||
proc.CancelErrorRead();
|
||||
proc.CancelOutputRead();
|
||||
|
@ -74,11 +84,16 @@ namespace SourceGit.Commands {
|
|||
errs.Add(e.Data);
|
||||
};
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
proc.Start();
|
||||
} catch (Exception e) {
|
||||
if (RaiseError) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (RaiseError)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(Context, e.Message);
|
||||
});
|
||||
}
|
||||
|
@ -92,19 +107,25 @@ namespace SourceGit.Commands {
|
|||
int exitCode = proc.ExitCode;
|
||||
proc.Close();
|
||||
|
||||
if (!isCancelled && exitCode != 0 && errs.Count > 0) {
|
||||
if (RaiseError) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
if (!isCancelled && exitCode != 0 && errs.Count > 0)
|
||||
{
|
||||
if (RaiseError)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(Context, string.Join("\n", errs));
|
||||
});
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public ReadToEndResult ReadToEnd() {
|
||||
public ReadToEndResult ReadToEnd()
|
||||
{
|
||||
var start = new ProcessStartInfo();
|
||||
start.FileName = Native.OS.GitInstallPath;
|
||||
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
|
||||
|
@ -118,17 +139,22 @@ namespace SourceGit.Commands {
|
|||
if (!string.IsNullOrEmpty(WorkingDirectory)) start.WorkingDirectory = WorkingDirectory;
|
||||
|
||||
var proc = new Process() { StartInfo = start };
|
||||
try {
|
||||
try
|
||||
{
|
||||
proc.Start();
|
||||
} catch (Exception e) {
|
||||
return new ReadToEndResult() {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new ReadToEndResult()
|
||||
{
|
||||
IsSuccess = false,
|
||||
StdOut = string.Empty,
|
||||
StdErr = e.Message,
|
||||
};
|
||||
}
|
||||
|
||||
var rs = new ReadToEndResult() {
|
||||
var rs = new ReadToEndResult()
|
||||
{
|
||||
StdOut = proc.StandardOutput.ReadToEnd(),
|
||||
StdErr = proc.StandardError.ReadToEnd(),
|
||||
};
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Commit : Command {
|
||||
public Commit(string repo, string message, bool amend, bool allowEmpty = false) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Commit : Command
|
||||
{
|
||||
public Commit(string repo, string message, bool amend, bool allowEmpty = false)
|
||||
{
|
||||
var file = Path.GetTempFileName();
|
||||
File.WriteAllText(file, message);
|
||||
|
||||
|
@ -13,4 +16,4 @@ namespace SourceGit.Commands {
|
|||
if (allowEmpty) Args += " --allow-empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +1,45 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class CompareRevisions : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class CompareRevisions : Command
|
||||
{
|
||||
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
|
||||
public CompareRevisions(string repo, string start, string end) {
|
||||
public CompareRevisions(string repo, string start, string end)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"diff --name-status {start} {end}";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result() {
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
_changes.Sort((l, r) => l.Path.CompareTo(r.Path));
|
||||
return _changes;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success) return;
|
||||
|
||||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
||||
switch (status[0]) {
|
||||
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break;
|
||||
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break;
|
||||
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break;
|
||||
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break;
|
||||
case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break;
|
||||
switch (status[0])
|
||||
{
|
||||
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break;
|
||||
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break;
|
||||
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break;
|
||||
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break;
|
||||
case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Models.Change> _changes = new List<Models.Change>();
|
||||
private readonly List<Models.Change> _changes = new List<Models.Change>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Config : Command {
|
||||
public Config(string repository) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Config : Command
|
||||
{
|
||||
public Config(string repository)
|
||||
{
|
||||
WorkingDirectory = repository;
|
||||
Context = repository;
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public Dictionary<string, string> ListAll() {
|
||||
public Dictionary<string, string> ListAll()
|
||||
{
|
||||
Args = "config -l";
|
||||
|
||||
var output = ReadToEnd();
|
||||
var rs = new Dictionary<string, string>();
|
||||
if (output.IsSuccess) {
|
||||
if (output.IsSuccess)
|
||||
{
|
||||
var lines = output.StdOut.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines) {
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var idx = line.IndexOf('=', StringComparison.Ordinal);
|
||||
if (idx != -1) {
|
||||
if (idx != -1)
|
||||
{
|
||||
var key = line.Substring(0, idx).Trim();
|
||||
var val = line.Substring(idx+1).Trim();
|
||||
if (rs.ContainsKey(key)) {
|
||||
var val = line.Substring(idx + 1).Trim();
|
||||
if (rs.ContainsKey(key))
|
||||
{
|
||||
rs[key] = val;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
rs.Add(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,22 +43,33 @@ namespace SourceGit.Commands {
|
|||
return rs;
|
||||
}
|
||||
|
||||
public string Get(string key) {
|
||||
public string Get(string key)
|
||||
{
|
||||
Args = $"config {key}";
|
||||
return ReadToEnd().StdOut.Trim();
|
||||
}
|
||||
|
||||
public bool Set(string key, string value, bool allowEmpty = false) {
|
||||
if (!allowEmpty && string.IsNullOrWhiteSpace(value)) {
|
||||
if (string.IsNullOrEmpty(WorkingDirectory)) {
|
||||
public bool Set(string key, string value, bool allowEmpty = false)
|
||||
{
|
||||
if (!allowEmpty && string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
if (string.IsNullOrEmpty(WorkingDirectory))
|
||||
{
|
||||
Args = $"config --global --unset {key}";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = $"config --unset {key}";
|
||||
}
|
||||
} else {
|
||||
if (string.IsNullOrWhiteSpace(WorkingDirectory)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(WorkingDirectory))
|
||||
{
|
||||
Args = $"config --global {key} \"{value}\"";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = $"config {key} \"{value}\"";
|
||||
}
|
||||
}
|
||||
|
@ -56,4 +77,4 @@ namespace SourceGit.Commands {
|
|||
return Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,64 +2,89 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class Diff : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class Diff : Command
|
||||
{
|
||||
[GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")]
|
||||
private static partial Regex REG_INDICATOR();
|
||||
private static readonly string PREFIX_LFS_NEW = "+version https://git-lfs.github.com/spec/";
|
||||
private static readonly string PREFIX_LFS_DEL = "-version https://git-lfs.github.com/spec/";
|
||||
private static readonly string PREFIX_LFS_MODIFY = " version https://git-lfs.github.com/spec/";
|
||||
|
||||
public Diff(string repo, Models.DiffOption opt) {
|
||||
public Diff(string repo, Models.DiffOption opt)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"diff --ignore-cr-at-eol --unified=4 {opt}";
|
||||
}
|
||||
|
||||
public Models.DiffResult Result() {
|
||||
public Models.DiffResult Result()
|
||||
{
|
||||
Exec();
|
||||
|
||||
if (_result.IsBinary || _result.IsLFS) {
|
||||
if (_result.IsBinary || _result.IsLFS)
|
||||
{
|
||||
_result.TextDiff = null;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessInlineHighlights();
|
||||
|
||||
if (_result.TextDiff.Lines.Count == 0) {
|
||||
if (_result.TextDiff.Lines.Count == 0)
|
||||
{
|
||||
_result.TextDiff = null;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_result.TextDiff.MaxLineNumber = Math.Max(_newLine, _oldLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _result;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
if (_result.IsBinary) return;
|
||||
|
||||
if (_result.IsLFS) {
|
||||
if (_result.IsLFS)
|
||||
{
|
||||
var ch = line[0];
|
||||
if (ch == '-') {
|
||||
if (line.StartsWith("-oid sha256:", StringComparison.Ordinal)) {
|
||||
if (ch == '-')
|
||||
{
|
||||
if (line.StartsWith("-oid sha256:", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.Old.Oid = line.Substring(12);
|
||||
} else if (line.StartsWith("-size ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith("-size ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.Old.Size = long.Parse(line.Substring(6));
|
||||
}
|
||||
} else if (ch == '+') {
|
||||
if (line.StartsWith("+oid sha256:", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (ch == '+')
|
||||
{
|
||||
if (line.StartsWith("+oid sha256:", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.New.Oid = line.Substring(12);
|
||||
} else if (line.StartsWith("+size ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith("+size ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.New.Size = long.Parse(line.Substring(6));
|
||||
}
|
||||
} else if (line.StartsWith(" size ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith(" size ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.Substring(6));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_result.TextDiff.Lines.Count == 0) {
|
||||
if (_result.TextDiff.Lines.Count == 0)
|
||||
{
|
||||
var match = REG_INDICATOR().Match(line);
|
||||
if (!match.Success) {
|
||||
if (!match.Success)
|
||||
{
|
||||
if (line.StartsWith("Binary", StringComparison.Ordinal)) _result.IsBinary = true;
|
||||
return;
|
||||
}
|
||||
|
@ -67,8 +92,11 @@ namespace SourceGit.Commands {
|
|||
_oldLine = int.Parse(match.Groups[1].Value);
|
||||
_newLine = int.Parse(match.Groups[2].Value);
|
||||
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
|
||||
} else {
|
||||
if (line.Length == 0) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line.Length == 0)
|
||||
{
|
||||
ProcessInlineHighlights();
|
||||
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", _oldLine, _newLine));
|
||||
_oldLine++;
|
||||
|
@ -77,8 +105,10 @@ namespace SourceGit.Commands {
|
|||
}
|
||||
|
||||
var ch = line[0];
|
||||
if (ch == '-') {
|
||||
if (_oldLine == 1 && _newLine == 0 && line.StartsWith(PREFIX_LFS_DEL, StringComparison.Ordinal)) {
|
||||
if (ch == '-')
|
||||
{
|
||||
if (_oldLine == 1 && _newLine == 0 && line.StartsWith(PREFIX_LFS_DEL, StringComparison.Ordinal))
|
||||
{
|
||||
_result.IsLFS = true;
|
||||
_result.LFSDiff = new Models.LFSDiff();
|
||||
return;
|
||||
|
@ -86,8 +116,11 @@ namespace SourceGit.Commands {
|
|||
|
||||
_deleted.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), _oldLine, 0));
|
||||
_oldLine++;
|
||||
} else if (ch == '+') {
|
||||
if (_oldLine == 0 && _newLine == 1 && line.StartsWith(PREFIX_LFS_NEW, StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (ch == '+')
|
||||
{
|
||||
if (_oldLine == 0 && _newLine == 1 && line.StartsWith(PREFIX_LFS_NEW, StringComparison.Ordinal))
|
||||
{
|
||||
_result.IsLFS = true;
|
||||
_result.LFSDiff = new Models.LFSDiff();
|
||||
return;
|
||||
|
@ -95,15 +128,21 @@ namespace SourceGit.Commands {
|
|||
|
||||
_added.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), 0, _newLine));
|
||||
_newLine++;
|
||||
} else if (ch != '\\') {
|
||||
}
|
||||
else if (ch != '\\')
|
||||
{
|
||||
ProcessInlineHighlights();
|
||||
var match = REG_INDICATOR().Match(line);
|
||||
if (match.Success) {
|
||||
if (match.Success)
|
||||
{
|
||||
_oldLine = int.Parse(match.Groups[1].Value);
|
||||
_newLine = int.Parse(match.Groups[2].Value);
|
||||
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
|
||||
} else {
|
||||
if (_oldLine == 1 && _newLine == 1 && line.StartsWith(PREFIX_LFS_MODIFY, StringComparison.Ordinal)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_oldLine == 1 && _newLine == 1 && line.StartsWith(PREFIX_LFS_MODIFY, StringComparison.Ordinal))
|
||||
{
|
||||
_result.IsLFS = true;
|
||||
_result.LFSDiff = new Models.LFSDiff();
|
||||
return;
|
||||
|
@ -117,10 +156,14 @@ namespace SourceGit.Commands {
|
|||
}
|
||||
}
|
||||
|
||||
private void ProcessInlineHighlights() {
|
||||
if (_deleted.Count > 0) {
|
||||
if (_added.Count == _deleted.Count) {
|
||||
for (int i = _added.Count - 1; i >= 0; i--) {
|
||||
private void ProcessInlineHighlights()
|
||||
{
|
||||
if (_deleted.Count > 0)
|
||||
{
|
||||
if (_added.Count == _deleted.Count)
|
||||
{
|
||||
for (int i = _added.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var left = _deleted[i];
|
||||
var right = _added[i];
|
||||
|
||||
|
@ -129,12 +172,15 @@ namespace SourceGit.Commands {
|
|||
var chunks = Models.TextInlineChange.Compare(left.Content, right.Content);
|
||||
if (chunks.Count > 4) continue;
|
||||
|
||||
foreach (var chunk in chunks) {
|
||||
if (chunk.DeletedCount > 0) {
|
||||
foreach (var chunk in chunks)
|
||||
{
|
||||
if (chunk.DeletedCount > 0)
|
||||
{
|
||||
left.Highlights.Add(new Models.TextInlineRange(chunk.DeletedStart, chunk.DeletedCount));
|
||||
}
|
||||
|
||||
if (chunk.AddedCount > 0) {
|
||||
if (chunk.AddedCount > 0)
|
||||
{
|
||||
right.Highlights.Add(new Models.TextInlineRange(chunk.AddedStart, chunk.AddedCount));
|
||||
}
|
||||
}
|
||||
|
@ -145,16 +191,17 @@ namespace SourceGit.Commands {
|
|||
_deleted.Clear();
|
||||
}
|
||||
|
||||
if (_added.Count > 0) {
|
||||
if (_added.Count > 0)
|
||||
{
|
||||
_result.TextDiff.Lines.AddRange(_added);
|
||||
_added.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private Models.DiffResult _result = new Models.DiffResult() { TextDiff = new Models.TextDiff() };
|
||||
private List<Models.TextDiffLine> _deleted = new List<Models.TextDiffLine>();
|
||||
private List<Models.TextDiffLine> _added = new List<Models.TextDiffLine>();
|
||||
private readonly Models.DiffResult _result = new Models.DiffResult() { TextDiff = new Models.TextDiff() };
|
||||
private readonly List<Models.TextDiffLine> _deleted = new List<Models.TextDiffLine>();
|
||||
private readonly List<Models.TextDiffLine> _added = new List<Models.TextDiffLine>();
|
||||
private int _oldLine = 0;
|
||||
private int _newLine = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public static class Discard {
|
||||
public static void All(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class Discard
|
||||
{
|
||||
public static void All(string repo)
|
||||
{
|
||||
new Reset(repo, "HEAD", "--hard").Exec();
|
||||
new Clean(repo).Exec();
|
||||
}
|
||||
|
||||
public static void ChangesInWorkTree(string repo, List<Models.Change> changes) {
|
||||
public static void ChangesInWorkTree(string repo, List<Models.Change> changes)
|
||||
{
|
||||
var needClean = new List<string>();
|
||||
var needCheckout = new List<string>();
|
||||
|
||||
foreach (var c in changes) {
|
||||
if (c.WorkTree == Models.ChangeState.Untracked || c.WorkTree == Models.ChangeState.Added) {
|
||||
foreach (var c in changes)
|
||||
{
|
||||
if (c.WorkTree == Models.ChangeState.Untracked || c.WorkTree == Models.ChangeState.Added)
|
||||
{
|
||||
needClean.Add(c.Path);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
needCheckout.Add(c.Path);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < needClean.Count; i += 10) {
|
||||
for (int i = 0; i < needClean.Count; i += 10)
|
||||
{
|
||||
var count = Math.Min(10, needClean.Count - i);
|
||||
new Clean(repo, needClean.GetRange(i, count)).Exec();
|
||||
}
|
||||
|
||||
for (int i = 0; i < needCheckout.Count; i += 10) {
|
||||
for (int i = 0; i < needCheckout.Count; i += 10)
|
||||
{
|
||||
var count = Math.Min(10, needCheckout.Count - i);
|
||||
new Checkout(repo).Files(needCheckout.GetRange(i, count));
|
||||
}
|
||||
}
|
||||
|
||||
public static void ChangesInStaged(string repo, List<Models.Change> changes) {
|
||||
for (int i = 0; i < changes.Count; i += 10) {
|
||||
public static void ChangesInStaged(string repo, List<Models.Change> changes)
|
||||
{
|
||||
for (int i = 0; i < changes.Count; i += 10)
|
||||
{
|
||||
var count = Math.Min(10, changes.Count - i);
|
||||
var files = new List<string>();
|
||||
for (int j = 0; j < count; j++) files.Add(changes[i + j].Path);
|
||||
|
@ -40,4 +52,4 @@ namespace SourceGit.Commands {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,18 +3,24 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Fetch : Command {
|
||||
public Fetch(string repo, string remote, bool prune, Action<string> outputHandler) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Fetch : Command
|
||||
{
|
||||
public Fetch(string repo, string remote, bool prune, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
|
||||
var sshKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
if (!string.IsNullOrEmpty(sshKey)) {
|
||||
if (!string.IsNullOrEmpty(sshKey))
|
||||
{
|
||||
Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = "-c credential.helper=manager ";
|
||||
}
|
||||
|
||||
|
@ -25,59 +31,75 @@ namespace SourceGit.Commands {
|
|||
AutoFetch.MarkFetched(repo);
|
||||
}
|
||||
|
||||
public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action<string> outputHandler) {
|
||||
public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
|
||||
var sshKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
if (!string.IsNullOrEmpty(sshKey)) {
|
||||
if (!string.IsNullOrEmpty(sshKey))
|
||||
{
|
||||
Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = "-c credential.helper=manager ";
|
||||
}
|
||||
|
||||
Args += $"fetch --progress --verbose {remote} {remoteBranch}:{localBranch}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
|
||||
public class AutoFetch {
|
||||
public static bool IsEnabled {
|
||||
public class AutoFetch
|
||||
{
|
||||
public static bool IsEnabled
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = false;
|
||||
|
||||
class Job {
|
||||
class Job
|
||||
{
|
||||
public Fetch Cmd = null;
|
||||
public DateTime NextRunTimepoint = DateTime.MinValue;
|
||||
}
|
||||
|
||||
static AutoFetch() {
|
||||
Task.Run(() => {
|
||||
while (true) {
|
||||
if (!IsEnabled) {
|
||||
static AutoFetch()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!IsEnabled)
|
||||
{
|
||||
Thread.Sleep(10000);
|
||||
continue;
|
||||
}
|
||||
|
||||
var now = DateTime.Now;
|
||||
var uptodate = new List<Job>();
|
||||
lock (_lock) {
|
||||
foreach (var job in _jobs) {
|
||||
if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0) {
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var job in _jobs)
|
||||
{
|
||||
if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0)
|
||||
{
|
||||
uptodate.Add(job.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var job in uptodate) {
|
||||
foreach (var job in uptodate)
|
||||
{
|
||||
job.Cmd.Exec();
|
||||
job.NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval);
|
||||
}
|
||||
|
@ -87,37 +109,48 @@ namespace SourceGit.Commands {
|
|||
});
|
||||
}
|
||||
|
||||
public static void AddRepository(string repo) {
|
||||
var job = new Job {
|
||||
public static void AddRepository(string repo)
|
||||
{
|
||||
var job = new Job
|
||||
{
|
||||
Cmd = new Fetch(repo, "--all", true, null) { RaiseError = false },
|
||||
NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval),
|
||||
};
|
||||
|
||||
lock (_lock) {
|
||||
if (_jobs.ContainsKey(repo)) {
|
||||
lock (_lock)
|
||||
{
|
||||
if (_jobs.ContainsKey(repo))
|
||||
{
|
||||
_jobs[repo] = job;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_jobs.Add(repo, job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveRepository(string repo) {
|
||||
lock (_lock) {
|
||||
public static void RemoveRepository(string repo)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_jobs.Remove(repo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarkFetched(string repo) {
|
||||
lock (_lock) {
|
||||
if (_jobs.ContainsKey(repo)) {
|
||||
public static void MarkFetched(string repo)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_jobs.ContainsKey(repo))
|
||||
{
|
||||
_jobs[repo].NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, Job> _jobs = new Dictionary<string, Job>();
|
||||
private static object _lock = new object();
|
||||
private static double _fetchInterval = 10 * 60;
|
||||
private static readonly Dictionary<string, Job> _jobs = new Dictionary<string, Job>();
|
||||
private static readonly object _lock = new object();
|
||||
private static readonly double _fetchInterval = 10 * 60;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class FormatPatch : Command {
|
||||
public FormatPatch(string repo, string commit, string saveTo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class FormatPatch : Command
|
||||
{
|
||||
public FormatPatch(string repo, string commit, string saveTo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"format-patch {commit} -1 -o \"{saveTo}\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class GC : Command {
|
||||
public GC(string repo, Action<string> outputHandler) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class GC : Command
|
||||
{
|
||||
public GC(string repo, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
@ -10,10 +13,11 @@ namespace SourceGit.Commands {
|
|||
Args = "gc";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,19 @@
|
|||
using Avalonia.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class GitFlow : Command {
|
||||
public GitFlow(string repo) {
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class GitFlow : Command
|
||||
{
|
||||
public GitFlow(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Init(List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version) {
|
||||
public bool Init(List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version)
|
||||
{
|
||||
var current = branches.Find(x => x.IsCurrent);
|
||||
|
||||
var masterBranch = branches.Find(x => x.Name == master);
|
||||
|
@ -31,47 +36,53 @@ namespace SourceGit.Commands {
|
|||
return Exec();
|
||||
}
|
||||
|
||||
public bool Start(Models.GitFlowBranchType type, string name) {
|
||||
switch (type) {
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
Args = $"flow feature start {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
Args = $"flow release start {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Hotfix:
|
||||
Args = $"flow hotfix start {name}";
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
App.RaiseException(Context, "Bad branch type!!!");
|
||||
});
|
||||
return false;
|
||||
public bool Start(Models.GitFlowBranchType type, string name)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
Args = $"flow feature start {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
Args = $"flow release start {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Hotfix:
|
||||
Args = $"flow hotfix start {name}";
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(Context, "Bad branch type!!!");
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Finish(Models.GitFlowBranchType type, string name, bool keepBranch) {
|
||||
public bool Finish(Models.GitFlowBranchType type, string name, bool keepBranch)
|
||||
{
|
||||
var option = keepBranch ? "-k" : string.Empty;
|
||||
switch (type) {
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
Args = $"flow feature finish {option} {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
Args = $"flow release finish {option} {name} -m \"RELEASE_DONE\"";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Hotfix:
|
||||
Args = $"flow hotfix finish {option} {name} -m \"HOTFIX_DONE\"";
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
App.RaiseException(Context, "Bad branch type!!!");
|
||||
});
|
||||
return false;
|
||||
switch (type)
|
||||
{
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
Args = $"flow feature finish {option} {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
Args = $"flow release finish {option} {name} -m \"RELEASE_DONE\"";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Hotfix:
|
||||
Args = $"flow hotfix finish {option} {name} -m \"HOTFIX_DONE\"";
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(Context, "Bad branch type!!!");
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class Init : Command {
|
||||
public Init(string ctx, string dir) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Init : Command
|
||||
{
|
||||
public Init(string ctx, string dir)
|
||||
{
|
||||
Context = ctx;
|
||||
WorkingDirectory = dir;
|
||||
Args = "init -q";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +1,23 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class IsBinary : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class IsBinary : Command
|
||||
{
|
||||
[GeneratedRegex(@"^\-\s+\-\s+.*$")]
|
||||
private static partial Regex REG_TEST();
|
||||
|
||||
public IsBinary(string repo, string commit, string path) {
|
||||
public IsBinary(string repo, string commit, string path)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {commit} --numstat -- \"{path}\"";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public bool Result() {
|
||||
public bool Result()
|
||||
{
|
||||
return REG_TEST().IsMatch(ReadToEnd().StdOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,19 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class IsLFSFiltered : Command {
|
||||
public IsLFSFiltered(string repo, string path) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class IsLFSFiltered : Command
|
||||
{
|
||||
public IsLFSFiltered(string repo, string path)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"check-attr -a -z \"{path}\"";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public bool Result() {
|
||||
public bool Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class LFS {
|
||||
class PruneCmd : Command {
|
||||
public PruneCmd(string repo, Action<string> onProgress) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class LFS
|
||||
{
|
||||
class PruneCmd : Command
|
||||
{
|
||||
public PruneCmd(string repo, Action<string> onProgress)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "lfs prune";
|
||||
|
@ -12,18 +16,21 @@ namespace SourceGit.Commands {
|
|||
_outputHandler = onProgress;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
|
||||
public LFS(string repo) {
|
||||
public LFS(string repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
public bool IsEnabled() {
|
||||
public bool IsEnabled()
|
||||
{
|
||||
var path = Path.Combine(_repo, ".git", "hooks", "pre-push");
|
||||
if (!File.Exists(path)) return false;
|
||||
|
||||
|
@ -31,10 +38,11 @@ namespace SourceGit.Commands {
|
|||
return content.Contains("git lfs pre-push");
|
||||
}
|
||||
|
||||
public void Prune(Action<string> outputHandler) {
|
||||
public void Prune(Action<string> outputHandler)
|
||||
{
|
||||
new PruneCmd(_repo, outputHandler).Exec();
|
||||
}
|
||||
|
||||
private string _repo;
|
||||
private readonly string _repo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Merge : Command {
|
||||
public Merge(string repo, string source, string mode, Action<string> outputHandler) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Merge : Command
|
||||
{
|
||||
public Merge(string repo, string source, string mode, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
@ -10,10 +13,11 @@ namespace SourceGit.Commands {
|
|||
Args = $"merge --progress {source} {mode}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler = null;
|
||||
private readonly Action<string> _outputHandler = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +1,28 @@
|
|||
using Avalonia.Threading;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public static class MergeTool {
|
||||
public static bool OpenForMerge(string repo, string tool, string mergeCmd, string file) {
|
||||
if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(mergeCmd)) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class MergeTool
|
||||
{
|
||||
public static bool OpenForMerge(string repo, string tool, string mergeCmd, string file)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(mergeCmd))
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Invalid external merge tool settings!");
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File.Exists(tool)) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
if (!File.Exists(tool))
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, $"Can NOT found external merge tool in '{tool}'!");
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -25,16 +33,21 @@ namespace SourceGit.Commands {
|
|||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool OpenForDiff(string repo, string tool, string diffCmd, Models.DiffOption option) {
|
||||
if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(diffCmd)) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
public static bool OpenForDiff(string repo, string tool, string diffCmd, Models.DiffOption option)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(diffCmd))
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Invalid external merge tool settings!");
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File.Exists(tool)) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
if (!File.Exists(tool))
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, $"Can NOT found external merge tool in '{tool}'!");
|
||||
});
|
||||
return false;
|
||||
|
@ -42,9 +55,9 @@ namespace SourceGit.Commands {
|
|||
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.RaiseError = false;
|
||||
cmd.RaiseError = false;
|
||||
cmd.Args = $"-c difftool.sourcegit.cmd=\"\\\"{tool}\\\" {diffCmd}\" difftool --tool=sourcegit --no-prompt {option}";
|
||||
return cmd.Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,23 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Pull : Command {
|
||||
public Pull(string repo, string remote, string branch, bool useRebase, Action<string> outputHandler) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Pull : Command
|
||||
{
|
||||
public Pull(string repo, string remote, string branch, bool useRebase, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
|
||||
var sshKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
if (!string.IsNullOrEmpty(sshKey)) {
|
||||
if (!string.IsNullOrEmpty(sshKey))
|
||||
{
|
||||
Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = "-c credential.helper=manager ";
|
||||
}
|
||||
|
||||
|
@ -20,10 +26,11 @@ namespace SourceGit.Commands {
|
|||
Args += $"{remote} {branch}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
private readonly Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,23 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Push : Command {
|
||||
public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool force, bool track, Action<string> onProgress) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Push : Command
|
||||
{
|
||||
public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool force, bool track, Action<string> onProgress)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
_outputHandler = onProgress;
|
||||
|
||||
var sshKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
if (!string.IsNullOrEmpty(sshKey)) {
|
||||
if (!string.IsNullOrEmpty(sshKey))
|
||||
{
|
||||
Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = "-c credential.helper=manager ";
|
||||
}
|
||||
|
||||
|
@ -30,29 +36,37 @@ namespace SourceGit.Commands {
|
|||
/// <param name="repo"></param>
|
||||
/// <param name="remote"></param>
|
||||
/// <param name="branch"></param>
|
||||
public Push(string repo, string remote, string branch) {
|
||||
public Push(string repo, string remote, string branch)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
TraitErrorAsOutput = true;
|
||||
|
||||
var sshKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
if (!string.IsNullOrEmpty(sshKey)) {
|
||||
if (!string.IsNullOrEmpty(sshKey))
|
||||
{
|
||||
Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = "-c credential.helper=manager ";
|
||||
}
|
||||
|
||||
Args += $"push {remote} --delete {branch}";
|
||||
}
|
||||
|
||||
public Push(string repo, string remote, string tag, bool isDelete) {
|
||||
public Push(string repo, string remote, string tag, bool isDelete)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
||||
var sshKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
if (!string.IsNullOrEmpty(sshKey)) {
|
||||
if (!string.IsNullOrEmpty(sshKey))
|
||||
{
|
||||
Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = "-c credential.helper=manager ";
|
||||
}
|
||||
|
||||
|
@ -61,10 +75,11 @@ namespace SourceGit.Commands {
|
|||
Args += $"{remote} refs/tags/{tag}";
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler = null;
|
||||
private readonly Action<string> _outputHandler = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,28 +2,37 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryBranches : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryBranches : Command
|
||||
{
|
||||
private static readonly string PREFIX_LOCAL = "refs/heads/";
|
||||
private static readonly string PREFIX_REMOTE = "refs/remotes/";
|
||||
|
||||
|
||||
[GeneratedRegex(@"^(\d+)\s(\d+)$")]
|
||||
private static partial Regex REG_AHEAD_BEHIND();
|
||||
|
||||
public QueryBranches(string repo) {
|
||||
public QueryBranches(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "branch -l --all -v --format=\"%(refname)$%(objectname)$%(HEAD)$%(upstream)$%(upstream:trackshort)\"";
|
||||
}
|
||||
|
||||
public List<Models.Branch> Result() {
|
||||
public List<Models.Branch> Result()
|
||||
{
|
||||
Exec();
|
||||
|
||||
foreach (var b in _branches) {
|
||||
if (b.IsLocal && !string.IsNullOrEmpty(b.UpstreamTrackStatus)) {
|
||||
if (b.UpstreamTrackStatus == "=") {
|
||||
foreach (var b in _branches)
|
||||
{
|
||||
if (b.IsLocal && !string.IsNullOrEmpty(b.UpstreamTrackStatus))
|
||||
{
|
||||
if (b.UpstreamTrackStatus == "=")
|
||||
{
|
||||
b.UpstreamTrackStatus = string.Empty;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
b.UpstreamTrackStatus = ParseTrackStatus(b.Name, b.Upstream);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +41,8 @@ namespace SourceGit.Commands {
|
|||
return _branches;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var parts = line.Split('$');
|
||||
if (parts.Length != 5) return;
|
||||
|
||||
|
@ -40,10 +50,13 @@ namespace SourceGit.Commands {
|
|||
var refName = parts[0];
|
||||
if (refName.EndsWith("/HEAD", StringComparison.Ordinal)) return;
|
||||
|
||||
if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal)) {
|
||||
if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal))
|
||||
{
|
||||
branch.Name = refName.Substring(PREFIX_LOCAL.Length);
|
||||
branch.IsLocal = true;
|
||||
} else if (refName.StartsWith(PREFIX_REMOTE, StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (refName.StartsWith(PREFIX_REMOTE, StringComparison.Ordinal))
|
||||
{
|
||||
var name = refName.Substring(PREFIX_REMOTE.Length);
|
||||
var shortNameIdx = name.IndexOf('/', StringComparison.Ordinal);
|
||||
if (shortNameIdx < 0) return;
|
||||
|
@ -51,7 +64,9 @@ namespace SourceGit.Commands {
|
|||
branch.Remote = name.Substring(0, shortNameIdx);
|
||||
branch.Name = name.Substring(branch.Remote.Length + 1);
|
||||
branch.IsLocal = false;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
branch.Name = refName;
|
||||
branch.IsLocal = true;
|
||||
}
|
||||
|
@ -64,7 +79,8 @@ namespace SourceGit.Commands {
|
|||
_branches.Add(branch);
|
||||
}
|
||||
|
||||
private string ParseTrackStatus(string local, string upstream) {
|
||||
private string ParseTrackStatus(string local, string upstream)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = WorkingDirectory;
|
||||
cmd.Context = Context;
|
||||
|
@ -84,6 +100,6 @@ namespace SourceGit.Commands {
|
|||
return track.Trim();
|
||||
}
|
||||
|
||||
private List<Models.Branch> _branches = new List<Models.Branch>();
|
||||
private readonly List<Models.Branch> _branches = new List<Models.Branch>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +1,45 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryCommitChanges : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryCommitChanges : Command
|
||||
{
|
||||
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
|
||||
public QueryCommitChanges(string repo, string commitSHA) {
|
||||
public QueryCommitChanges(string repo, string commitSHA)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"show --name-status {commitSHA}";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result() {
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
_changes.Sort((l, r) => l.Path.CompareTo(r.Path));
|
||||
return _changes;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success) return;
|
||||
|
||||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
||||
switch (status[0]) {
|
||||
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break;
|
||||
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break;
|
||||
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break;
|
||||
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break;
|
||||
case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break;
|
||||
switch (status[0])
|
||||
{
|
||||
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break;
|
||||
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break;
|
||||
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break;
|
||||
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break;
|
||||
case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Models.Change> _changes = new List<Models.Change>();
|
||||
private readonly List<Models.Change> _changes = new List<Models.Change>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class QueryCommits : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryCommits : Command
|
||||
{
|
||||
private static readonly string GPGSIG_START = "gpgsig -----BEGIN PGP SIGNATURE-----";
|
||||
private static readonly string GPGSIG_END = " -----END PGP SIGNATURE-----";
|
||||
|
||||
private List<Models.Commit> commits = new List<Models.Commit>();
|
||||
private readonly List<Models.Commit> commits = new List<Models.Commit>();
|
||||
private Models.Commit current = null;
|
||||
private bool isSkipingGpgsig = false;
|
||||
private bool isHeadFounded = false;
|
||||
private bool findFirstMerged = true;
|
||||
private readonly bool findFirstMerged = true;
|
||||
|
||||
public QueryCommits(string repo, string limits, bool needFindHead = true) {
|
||||
public QueryCommits(string repo, string limits, bool needFindHead = true)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Args = "log --date-order --decorate=full --pretty=raw " + limits;
|
||||
findFirstMerged = needFindHead;
|
||||
}
|
||||
|
||||
public List<Models.Commit> Result() {
|
||||
public List<Models.Commit> Result()
|
||||
{
|
||||
Exec();
|
||||
|
||||
if (current != null) {
|
||||
if (current != null)
|
||||
{
|
||||
current.Message = current.Message.Trim();
|
||||
commits.Add(current);
|
||||
}
|
||||
|
||||
if (findFirstMerged && !isHeadFounded && commits.Count > 0) {
|
||||
if (findFirstMerged && !isHeadFounded && commits.Count > 0)
|
||||
{
|
||||
MarkFirstMerged();
|
||||
}
|
||||
|
||||
return commits;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
if (isSkipingGpgsig) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
if (isSkipingGpgsig)
|
||||
{
|
||||
if (line.StartsWith(GPGSIG_END, StringComparison.Ordinal)) isSkipingGpgsig = false;
|
||||
return;
|
||||
} else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal))
|
||||
{
|
||||
isSkipingGpgsig = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.StartsWith("commit ", StringComparison.Ordinal)) {
|
||||
if (current != null) {
|
||||
if (line.StartsWith("commit ", StringComparison.Ordinal))
|
||||
{
|
||||
if (current != null)
|
||||
{
|
||||
current.Message = current.Message.Trim();
|
||||
commits.Add(current);
|
||||
}
|
||||
|
@ -52,9 +64,12 @@ namespace SourceGit.Commands {
|
|||
line = line.Substring(7);
|
||||
|
||||
var decoratorStart = line.IndexOf('(', StringComparison.Ordinal);
|
||||
if (decoratorStart < 0) {
|
||||
if (decoratorStart < 0)
|
||||
{
|
||||
current.SHA = line.Trim();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
current.SHA = line.Substring(0, decoratorStart).Trim();
|
||||
current.IsMerged = ParseDecorators(current.Decorators, line.Substring(decoratorStart + 1));
|
||||
if (!isHeadFounded) isHeadFounded = current.IsMerged;
|
||||
|
@ -65,65 +80,95 @@ namespace SourceGit.Commands {
|
|||
|
||||
if (current == null) return;
|
||||
|
||||
if (line.StartsWith("tree ", StringComparison.Ordinal)) {
|
||||
if (line.StartsWith("tree ", StringComparison.Ordinal))
|
||||
{
|
||||
return;
|
||||
} else if (line.StartsWith("parent ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith("parent ", StringComparison.Ordinal))
|
||||
{
|
||||
current.Parents.Add(line.Substring("parent ".Length));
|
||||
} else if (line.StartsWith("author ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith("author ", StringComparison.Ordinal))
|
||||
{
|
||||
Models.User user = Models.User.Invalid;
|
||||
ulong time = 0;
|
||||
Models.Commit.ParseUserAndTime(line.Substring(7), ref user, ref time);
|
||||
current.Author = user;
|
||||
current.AuthorTime = time;
|
||||
} else if (line.StartsWith("committer ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith("committer ", StringComparison.Ordinal))
|
||||
{
|
||||
Models.User user = Models.User.Invalid;
|
||||
ulong time = 0;
|
||||
Models.Commit.ParseUserAndTime(line.Substring(10), ref user, ref time);
|
||||
current.Committer = user;
|
||||
current.CommitterTime = time;
|
||||
} else if (string.IsNullOrEmpty(current.Subject)) {
|
||||
}
|
||||
else if (string.IsNullOrEmpty(current.Subject))
|
||||
{
|
||||
current.Subject = line.Trim();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
current.Message += (line.Trim() + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private bool ParseDecorators(List<Models.Decorator> decorators, string data) {
|
||||
private bool ParseDecorators(List<Models.Decorator> decorators, string data)
|
||||
{
|
||||
bool isHeadOfCurrent = false;
|
||||
|
||||
var subs = data.Split(new char[] { ',', ')', '(' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var sub in subs) {
|
||||
foreach (var sub in subs)
|
||||
{
|
||||
var d = sub.Trim();
|
||||
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal)) {
|
||||
decorators.Add(new Models.Decorator() {
|
||||
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
|
||||
{
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.Tag,
|
||||
Name = d.Substring(15).Trim(),
|
||||
});
|
||||
} else if (d.EndsWith("/HEAD", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (d.EndsWith("/HEAD", StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
} else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
|
||||
{
|
||||
isHeadOfCurrent = true;
|
||||
decorators.Add(new Models.Decorator() {
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.CurrentBranchHead,
|
||||
Name = d.Substring(19).Trim(),
|
||||
});
|
||||
} else if (d.StartsWith("refs/heads/", StringComparison.Ordinal)) {
|
||||
decorators.Add(new Models.Decorator() {
|
||||
}
|
||||
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
|
||||
{
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.LocalBranchHead,
|
||||
Name = d.Substring(11).Trim(),
|
||||
});
|
||||
} else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal)) {
|
||||
decorators.Add(new Models.Decorator() {
|
||||
}
|
||||
else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal))
|
||||
{
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.RemoteBranchHead,
|
||||
Name = d.Substring(13).Trim(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
decorators.Sort((l, r) => {
|
||||
if (l.Type != r.Type) {
|
||||
decorators.Sort((l, r) =>
|
||||
{
|
||||
if (l.Type != r.Type)
|
||||
{
|
||||
return (int)l.Type - (int)r.Type;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return l.Name.CompareTo(r.Name);
|
||||
}
|
||||
});
|
||||
|
@ -131,7 +176,8 @@ namespace SourceGit.Commands {
|
|||
return isHeadOfCurrent;
|
||||
}
|
||||
|
||||
private void MarkFirstMerged() {
|
||||
private void MarkFirstMerged()
|
||||
{
|
||||
Args = $"log --since=\"{commits[commits.Count - 1].CommitterTimeStr}\" --format=\"%H\"";
|
||||
|
||||
var rs = ReadToEnd();
|
||||
|
@ -141,12 +187,14 @@ namespace SourceGit.Commands {
|
|||
var set = new HashSet<string>();
|
||||
foreach (var sha in shas) set.Add(sha);
|
||||
|
||||
foreach (var c in commits) {
|
||||
if (set.Contains(c.SHA)) {
|
||||
foreach (var c in commits)
|
||||
{
|
||||
if (set.Contains(c.SHA))
|
||||
{
|
||||
c.IsMerged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +1,28 @@
|
|||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class QueryFileContent : Command {
|
||||
public QueryFileContent(string repo, string revision, string file) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryFileContent : Command
|
||||
{
|
||||
public QueryFileContent(string repo, string revision, string file)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"show {revision}:\"{file}\"";
|
||||
}
|
||||
|
||||
public string Result() {
|
||||
public string Result()
|
||||
{
|
||||
Exec();
|
||||
return _builder.ToString();
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_builder.Append(line);
|
||||
_builder.Append('\n');
|
||||
}
|
||||
|
||||
private StringBuilder _builder = new StringBuilder();
|
||||
private readonly StringBuilder _builder = new StringBuilder();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,30 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryFileSize : Command {
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryFileSize : Command
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"^\d+\s+\w+\s+[0-9a-f]+\s+(\d+)\s+.*$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
|
||||
public QueryFileSize(string repo, string file, string revision) {
|
||||
public QueryFileSize(string repo, string file, string revision)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"ls-tree {revision} -l -- {file}";
|
||||
}
|
||||
|
||||
public long Result() {
|
||||
public long Result()
|
||||
{
|
||||
if (_result != 0) return _result;
|
||||
|
||||
var rs = ReadToEnd();
|
||||
if (rs.IsSuccess) {
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var match = REG_FORMAT().Match(rs.StdOut);
|
||||
if (match.Success) {
|
||||
if (match.Success)
|
||||
{
|
||||
return long.Parse(match.Groups[1].Value);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +32,6 @@ namespace SourceGit.Commands {
|
|||
return 0;
|
||||
}
|
||||
|
||||
private long _result = 0;
|
||||
private readonly long _result = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,18 @@
|
|||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class QueryGitDir : Command {
|
||||
public QueryGitDir(string workDir) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryGitDir : Command
|
||||
{
|
||||
public QueryGitDir(string workDir)
|
||||
{
|
||||
WorkingDirectory = workDir;
|
||||
Args = "rev-parse --git-dir";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public string Result() {
|
||||
public string Result()
|
||||
{
|
||||
var rs = ReadToEnd().StdOut;
|
||||
if (string.IsNullOrEmpty(rs)) return null;
|
||||
|
||||
|
@ -17,4 +21,4 @@ namespace SourceGit.Commands {
|
|||
return Path.GetFullPath(Path.Combine(WorkingDirectory, rs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,24 +2,29 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryLocalChanges : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryLocalChanges : Command
|
||||
{
|
||||
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
private static readonly string[] UNTRACKED = [ "no", "all" ];
|
||||
private static readonly string[] UNTRACKED = ["no", "all"];
|
||||
|
||||
public QueryLocalChanges(string repo, bool includeUntracked = true) {
|
||||
public QueryLocalChanges(string repo, bool includeUntracked = true)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result() {
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
return _changes;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success) return;
|
||||
if (line.EndsWith("/", StringComparison.Ordinal)) return; // Ignore changes with git-worktree
|
||||
|
@ -27,41 +32,42 @@ namespace SourceGit.Commands {
|
|||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
||||
switch (status) {
|
||||
case " M": change.Set(Models.ChangeState.None, Models.ChangeState.Modified); break;
|
||||
case " A": change.Set(Models.ChangeState.None, Models.ChangeState.Added); break;
|
||||
case " D": change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); break;
|
||||
case " R": change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); break;
|
||||
case " C": change.Set(Models.ChangeState.None, Models.ChangeState.Copied); break;
|
||||
case "M": change.Set(Models.ChangeState.Modified, Models.ChangeState.None); break;
|
||||
case "MM": change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); break;
|
||||
case "MD": change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); break;
|
||||
case "A": change.Set(Models.ChangeState.Added, Models.ChangeState.None); break;
|
||||
case "AM": change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); break;
|
||||
case "AD": change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); break;
|
||||
case "D": change.Set(Models.ChangeState.Deleted, Models.ChangeState.None); break;
|
||||
case "R": change.Set(Models.ChangeState.Renamed, Models.ChangeState.None); break;
|
||||
case "RM": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); break;
|
||||
case "RD": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); break;
|
||||
case "C": change.Set(Models.ChangeState.Copied, Models.ChangeState.None); break;
|
||||
case "CM": change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); break;
|
||||
case "CD": change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); break;
|
||||
case "DR": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed); break;
|
||||
case "DC": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); break;
|
||||
case "DD": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); break;
|
||||
case "AU": change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); break;
|
||||
case "UD": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); break;
|
||||
case "UA": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); break;
|
||||
case "DU": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); break;
|
||||
case "AA": change.Set(Models.ChangeState.Added, Models.ChangeState.Added); break;
|
||||
case "UU": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); break;
|
||||
case "??": change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); break;
|
||||
default: return;
|
||||
switch (status)
|
||||
{
|
||||
case " M": change.Set(Models.ChangeState.None, Models.ChangeState.Modified); break;
|
||||
case " A": change.Set(Models.ChangeState.None, Models.ChangeState.Added); break;
|
||||
case " D": change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); break;
|
||||
case " R": change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); break;
|
||||
case " C": change.Set(Models.ChangeState.None, Models.ChangeState.Copied); break;
|
||||
case "M": change.Set(Models.ChangeState.Modified, Models.ChangeState.None); break;
|
||||
case "MM": change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); break;
|
||||
case "MD": change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); break;
|
||||
case "A": change.Set(Models.ChangeState.Added, Models.ChangeState.None); break;
|
||||
case "AM": change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); break;
|
||||
case "AD": change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); break;
|
||||
case "D": change.Set(Models.ChangeState.Deleted, Models.ChangeState.None); break;
|
||||
case "R": change.Set(Models.ChangeState.Renamed, Models.ChangeState.None); break;
|
||||
case "RM": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); break;
|
||||
case "RD": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); break;
|
||||
case "C": change.Set(Models.ChangeState.Copied, Models.ChangeState.None); break;
|
||||
case "CM": change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); break;
|
||||
case "CD": change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); break;
|
||||
case "DR": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed); break;
|
||||
case "DC": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); break;
|
||||
case "DD": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); break;
|
||||
case "AU": change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); break;
|
||||
case "UD": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); break;
|
||||
case "UA": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); break;
|
||||
case "DU": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); break;
|
||||
case "AA": change.Set(Models.ChangeState.Added, Models.ChangeState.Added); break;
|
||||
case "UU": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); break;
|
||||
case "??": change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
_changes.Add(change);
|
||||
}
|
||||
|
||||
private List<Models.Change> _changes = new List<Models.Change>();
|
||||
private readonly List<Models.Change> _changes = new List<Models.Change>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,33 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryRemotes : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryRemotes : Command
|
||||
{
|
||||
[GeneratedRegex(@"^([\w\.\-]+)\s*(\S+).*$")]
|
||||
private static partial Regex REG_REMOTE();
|
||||
|
||||
public QueryRemotes(string repo) {
|
||||
public QueryRemotes(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "remote -v";
|
||||
}
|
||||
|
||||
public List<Models.Remote> Result() {
|
||||
public List<Models.Remote> Result()
|
||||
{
|
||||
Exec();
|
||||
return _loaded;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_REMOTE().Match(line);
|
||||
if (!match.Success) return;
|
||||
|
||||
var remote = new Models.Remote() {
|
||||
var remote = new Models.Remote()
|
||||
{
|
||||
Name = match.Groups[1].Value,
|
||||
URL = match.Groups[2].Value,
|
||||
};
|
||||
|
@ -30,6 +36,6 @@ namespace SourceGit.Commands {
|
|||
_loaded.Add(remote);
|
||||
}
|
||||
|
||||
private List<Models.Remote> _loaded = new List<Models.Remote>();
|
||||
private readonly List<Models.Remote> _loaded = new List<Models.Remote>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,19 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class QueryRepositoryRootPath : Command {
|
||||
public QueryRepositoryRootPath(string path) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryRepositoryRootPath : Command
|
||||
{
|
||||
public QueryRepositoryRootPath(string path)
|
||||
{
|
||||
WorkingDirectory = path;
|
||||
Args = "rev-parse --show-toplevel";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public string Result() {
|
||||
public string Result()
|
||||
{
|
||||
var rs = ReadToEnd().StdOut;
|
||||
if (string.IsNullOrEmpty(rs)) return null;
|
||||
return rs.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +1,30 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryRevisionObjects : Command {
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryRevisionObjects : Command
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"^\d+\s+(\w+)\s+([0-9a-f]+)\s+(.*)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
private List<Models.Object> objects = new List<Models.Object>();
|
||||
private readonly List<Models.Object> objects = new List<Models.Object>();
|
||||
|
||||
public QueryRevisionObjects(string repo, string sha) {
|
||||
public QueryRevisionObjects(string repo, string sha)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"ls-tree -r {sha}";
|
||||
}
|
||||
|
||||
public List<Models.Object> Result() {
|
||||
public List<Models.Object> Result()
|
||||
{
|
||||
Exec();
|
||||
return objects;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success) return;
|
||||
|
||||
|
@ -28,14 +33,15 @@ namespace SourceGit.Commands {
|
|||
obj.Type = Models.ObjectType.Blob;
|
||||
obj.Path = match.Groups[3].Value;
|
||||
|
||||
switch (match.Groups[1].Value) {
|
||||
case "blob": obj.Type = Models.ObjectType.Blob; break;
|
||||
case "tree": obj.Type = Models.ObjectType.Tree; break;
|
||||
case "tag": obj.Type = Models.ObjectType.Tag; break;
|
||||
case "commit": obj.Type = Models.ObjectType.Commit; break;
|
||||
switch (match.Groups[1].Value)
|
||||
{
|
||||
case "blob": obj.Type = Models.ObjectType.Blob; break;
|
||||
case "tree": obj.Type = Models.ObjectType.Tree; break;
|
||||
case "tag": obj.Type = Models.ObjectType.Tag; break;
|
||||
case "commit": obj.Type = Models.ObjectType.Commit; break;
|
||||
}
|
||||
|
||||
objects.Add(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,29 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryStagedFileBlobGuid : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryStagedFileBlobGuid : Command
|
||||
{
|
||||
[GeneratedRegex(@"^\d+\s+([0-9a-f]+)\s+.*$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
|
||||
public QueryStagedFileBlobGuid(string repo, string file) {
|
||||
public QueryStagedFileBlobGuid(string repo, string file)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"ls-files -s -- \"{file}\"";
|
||||
}
|
||||
|
||||
public string Result() {
|
||||
public string Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var match = REG_FORMAT().Match(rs.StdOut.Trim());
|
||||
if (match.Success) {
|
||||
if (match.Success)
|
||||
{
|
||||
return match.Groups[1].Value;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +1,45 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryStashChanges : Command {
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryStashChanges : Command
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
|
||||
private static partial Regex REG_FORMAT();
|
||||
|
||||
public QueryStashChanges(string repo, string sha) {
|
||||
public QueryStashChanges(string repo, string sha)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"diff --name-status --pretty=format: {sha}^ {sha}";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result() {
|
||||
public List<Models.Change> Result()
|
||||
{
|
||||
Exec();
|
||||
return _changes;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success) return;
|
||||
|
||||
var change = new Models.Change() { Path = match.Groups[2].Value };
|
||||
var status = match.Groups[1].Value;
|
||||
|
||||
switch (status[0]) {
|
||||
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break;
|
||||
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break;
|
||||
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break;
|
||||
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break;
|
||||
case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break;
|
||||
switch (status[0])
|
||||
{
|
||||
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break;
|
||||
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break;
|
||||
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break;
|
||||
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break;
|
||||
case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Models.Change> _changes = new List<Models.Change>();
|
||||
private readonly List<Models.Change> _changes = new List<Models.Change>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,26 +2,32 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QueryStashes : Command {
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QueryStashes : Command
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"^Reflog: refs/(stash@\{\d+\}).*$")]
|
||||
private static partial Regex REG_STASH();
|
||||
|
||||
public QueryStashes(string repo) {
|
||||
|
||||
public QueryStashes(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "stash list --pretty=raw";
|
||||
}
|
||||
|
||||
public List<Models.Stash> Result() {
|
||||
public List<Models.Stash> Result()
|
||||
{
|
||||
Exec();
|
||||
if (_current != null) _stashes.Add(_current);
|
||||
return _stashes;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
if (line.StartsWith("commit ", StringComparison.Ordinal)) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
if (line.StartsWith("commit ", StringComparison.Ordinal))
|
||||
{
|
||||
if (_current != null && !string.IsNullOrEmpty(_current.Name)) _stashes.Add(_current);
|
||||
_current = new Models.Stash() { SHA = line.Substring(7, 8) };
|
||||
return;
|
||||
|
@ -29,12 +35,17 @@ namespace SourceGit.Commands {
|
|||
|
||||
if (_current == null) return;
|
||||
|
||||
if (line.StartsWith("Reflog: refs/stash@", StringComparison.Ordinal)) {
|
||||
if (line.StartsWith("Reflog: refs/stash@", StringComparison.Ordinal))
|
||||
{
|
||||
var match = REG_STASH().Match(line);
|
||||
if (match.Success) _current.Name = match.Groups[1].Value;
|
||||
} else if (line.StartsWith("Reflog message: ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith("Reflog message: ", StringComparison.Ordinal))
|
||||
{
|
||||
_current.Message = line.Substring(16);
|
||||
} else if (line.StartsWith("author ", StringComparison.Ordinal)) {
|
||||
}
|
||||
else if (line.StartsWith("author ", StringComparison.Ordinal))
|
||||
{
|
||||
Models.User user = Models.User.Invalid;
|
||||
ulong time = 0;
|
||||
Models.Commit.ParseUserAndTime(line.Substring(7), ref user, ref time);
|
||||
|
@ -43,7 +54,7 @@ namespace SourceGit.Commands {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Models.Stash> _stashes = new List<Models.Stash>();
|
||||
private readonly List<Models.Stash> _stashes = new List<Models.Stash>();
|
||||
private Models.Stash _current = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +1,44 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public partial class QuerySubmodules : Command {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class QuerySubmodules : Command
|
||||
{
|
||||
[GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)\s\(.*\)$")]
|
||||
private static partial Regex REG_FORMAT1();
|
||||
[GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)$")]
|
||||
private static partial Regex REG_FORMAT2();
|
||||
|
||||
public QuerySubmodules(string repo) {
|
||||
public QuerySubmodules(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "submodule status";
|
||||
}
|
||||
|
||||
public List<string> Result() {
|
||||
public List<string> Result()
|
||||
{
|
||||
Exec();
|
||||
return _submodules;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var match = REG_FORMAT1().Match(line);
|
||||
if (match.Success) {
|
||||
if (match.Success)
|
||||
{
|
||||
_submodules.Add(match.Groups[1].Value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
match = REG_FORMAT2().Match(line);
|
||||
if (match.Success) {
|
||||
if (match.Success)
|
||||
{
|
||||
_submodules.Add(match.Groups[1].Value);
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> _submodules = new List<string>();
|
||||
private readonly List<string> _submodules = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +1,44 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class QueryTags : Command {
|
||||
public QueryTags(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryTags : Command
|
||||
{
|
||||
public QueryTags(string repo)
|
||||
{
|
||||
Context = repo;
|
||||
WorkingDirectory = repo;
|
||||
Args = "for-each-ref --sort=-creatordate --format=\"$%(refname:short)$%(objectname)$%(*objectname)\" refs/tags";
|
||||
}
|
||||
|
||||
public List<Models.Tag> Result() {
|
||||
public List<Models.Tag> Result()
|
||||
{
|
||||
Exec();
|
||||
return _loaded;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var subs = line.Split(new char[] { '$' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (subs.Length == 2) {
|
||||
_loaded.Add(new Models.Tag() {
|
||||
if (subs.Length == 2)
|
||||
{
|
||||
_loaded.Add(new Models.Tag()
|
||||
{
|
||||
Name = subs[0],
|
||||
SHA = subs[1],
|
||||
});
|
||||
} else if (subs.Length == 3) {
|
||||
_loaded.Add(new Models.Tag() {
|
||||
}
|
||||
else if (subs.Length == 3)
|
||||
{
|
||||
_loaded.Add(new Models.Tag()
|
||||
{
|
||||
Name = subs[0],
|
||||
SHA = subs[2],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private List<Models.Tag> _loaded = new List<Models.Tag>();
|
||||
private readonly List<Models.Tag> _loaded = new List<Models.Tag>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class Rebase : Command {
|
||||
public Rebase(string repo, string basedOn, bool autoStash) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Rebase : Command
|
||||
{
|
||||
public Rebase(string repo, string basedOn, bool autoStash)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "rebase ";
|
||||
|
@ -8,4 +11,4 @@
|
|||
Args += basedOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +1,41 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class Remote : Command {
|
||||
public Remote(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Remote : Command
|
||||
{
|
||||
public Remote(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Add(string name, string url) {
|
||||
public bool Add(string name, string url)
|
||||
{
|
||||
Args = $"remote add {name} {url}";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Delete(string name) {
|
||||
public bool Delete(string name)
|
||||
{
|
||||
Args = $"remote remove {name}";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Rename(string name, string to) {
|
||||
public bool Rename(string name, string to)
|
||||
{
|
||||
Args = $"remote rename {name} {to}";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Prune(string name) {
|
||||
public bool Prune(string name)
|
||||
{
|
||||
Args = $"remote prune {name}";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool SetURL(string name, string url) {
|
||||
public bool SetURL(string name, string url)
|
||||
{
|
||||
Args = $"remote set-url {name} {url}";
|
||||
return Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +1,26 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Reset : Command {
|
||||
public Reset(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Reset : Command
|
||||
{
|
||||
public Reset(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "reset";
|
||||
}
|
||||
|
||||
public Reset(string repo, List<Models.Change> changes) {
|
||||
public Reset(string repo, List<Models.Change> changes)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("reset --");
|
||||
foreach (var c in changes) {
|
||||
foreach (var c in changes)
|
||||
{
|
||||
builder.Append(" \"");
|
||||
builder.Append(c.Path);
|
||||
builder.Append("\"");
|
||||
|
@ -23,10 +28,11 @@ namespace SourceGit.Commands {
|
|||
Args = builder.ToString();
|
||||
}
|
||||
|
||||
public Reset(string repo, string revision, string mode) {
|
||||
public Reset(string repo, string revision, string mode)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"reset {mode} {revision}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Restore : Command {
|
||||
public Restore(string repo, List<string> files, string extra) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Restore : Command
|
||||
{
|
||||
public Restore(string repo, List<string> files, string extra)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
||||
|
@ -13,6 +16,6 @@ namespace SourceGit.Commands {
|
|||
builder.Append("--");
|
||||
foreach (var f in files) builder.Append(' ').Append('"').Append(f).Append('"');
|
||||
Args = builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class Revert : Command {
|
||||
public Revert(string repo, string commit, bool autoCommit) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Revert : Command
|
||||
{
|
||||
public Revert(string repo, string commit, bool autoCommit)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"revert {commit} --no-edit";
|
||||
if (!autoCommit) Args += " --no-commit";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,20 @@
|
|||
using Avalonia.Threading;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public static class SaveChangesAsPatch {
|
||||
public static bool Exec(string repo, List<Models.Change> changes, bool isUnstaged, string saveTo) {
|
||||
using (var sw = File.Create(saveTo)) {
|
||||
foreach (var change in changes) {
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class SaveChangesAsPatch
|
||||
{
|
||||
public static bool Exec(string repo, List<Models.Change> changes, bool isUnstaged, string saveTo)
|
||||
{
|
||||
using (var sw = File.Create(saveTo))
|
||||
{
|
||||
foreach (var change in changes)
|
||||
{
|
||||
if (!ProcessSingleChange(repo, new Models.DiffOption(change, isUnstaged), sw)) return false;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +22,8 @@ namespace SourceGit.Commands {
|
|||
return true;
|
||||
}
|
||||
|
||||
private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer) {
|
||||
private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer)
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
starter.WorkingDirectory = repo;
|
||||
starter.FileName = Native.OS.GitInstallPath;
|
||||
|
@ -26,7 +33,8 @@ namespace SourceGit.Commands {
|
|||
starter.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
starter.RedirectStandardOutput = true;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
var proc = new Process() { StartInfo = starter };
|
||||
proc.Start();
|
||||
proc.StandardOutput.BaseStream.CopyTo(writer);
|
||||
|
@ -35,12 +43,15 @@ namespace SourceGit.Commands {
|
|||
proc.Close();
|
||||
|
||||
return rs;
|
||||
} catch (Exception e) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Save change to patch failed: " + e.Message);
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,33 @@
|
|||
using Avalonia.Threading;
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public static class SaveRevisionFile {
|
||||
public static void Run(string repo, string revision, string file, string saveTo) {
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class SaveRevisionFile
|
||||
{
|
||||
public static void Run(string repo, string revision, string file, string saveTo)
|
||||
{
|
||||
var isLFSFiltered = new IsLFSFiltered(repo, file).Result();
|
||||
if (isLFSFiltered) {
|
||||
if (isLFSFiltered)
|
||||
{
|
||||
var tmpFile = saveTo + ".tmp";
|
||||
if (ExecCmd(repo, $"show {revision}:\"{file}\"", tmpFile)) {
|
||||
if (ExecCmd(repo, $"show {revision}:\"{file}\"", tmpFile))
|
||||
{
|
||||
ExecCmd(repo, $"lfs smudge", saveTo, tmpFile);
|
||||
}
|
||||
}
|
||||
File.Delete(tmpFile);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecCmd(repo, $"show {revision}:\"{file}\"", saveTo);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ExecCmd(string repo, string args, string outputFile, string inputFile = null) {
|
||||
|
||||
private static bool ExecCmd(string repo, string args, string outputFile, string inputFile = null)
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
starter.WorkingDirectory = repo;
|
||||
starter.FileName = Native.OS.GitInstallPath;
|
||||
|
@ -30,14 +39,19 @@ namespace SourceGit.Commands {
|
|||
starter.RedirectStandardOutput = true;
|
||||
starter.RedirectStandardError = true;
|
||||
|
||||
using (var sw = File.OpenWrite(outputFile)) {
|
||||
try {
|
||||
using (var sw = File.OpenWrite(outputFile))
|
||||
{
|
||||
try
|
||||
{
|
||||
var proc = new Process() { StartInfo = starter };
|
||||
proc.Start();
|
||||
|
||||
if (inputFile != null) {
|
||||
using (StreamReader sr = new StreamReader(inputFile)) {
|
||||
while (true) {
|
||||
if (inputFile != null)
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(inputFile))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var line = sr.ReadLine();
|
||||
if (line == null) break;
|
||||
proc.StandardInput.WriteLine(line);
|
||||
|
@ -51,13 +65,16 @@ namespace SourceGit.Commands {
|
|||
proc.Close();
|
||||
|
||||
return rs;
|
||||
} catch (Exception e) {
|
||||
Dispatcher.UIThread.Invoke(() => {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Save file failed: " + e.Message);
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +1,45 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Stash : Command {
|
||||
public Stash(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Stash : Command
|
||||
{
|
||||
public Stash(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Push(string message) {
|
||||
public bool Push(string message)
|
||||
{
|
||||
Args = $"stash push -m \"{message}\"";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Push(List<Models.Change> changes, string message) {
|
||||
public bool Push(List<Models.Change> changes, string message)
|
||||
{
|
||||
var temp = Path.GetTempFileName();
|
||||
var stream = new FileStream(temp, FileMode.Create);
|
||||
var writer = new StreamWriter(stream);
|
||||
|
||||
var needAdd = new List<Models.Change>();
|
||||
foreach (var c in changes) {
|
||||
foreach (var c in changes)
|
||||
{
|
||||
writer.WriteLine(c.Path);
|
||||
|
||||
if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked) {
|
||||
if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked)
|
||||
{
|
||||
needAdd.Add(c);
|
||||
if (needAdd.Count > 10) {
|
||||
if (needAdd.Count > 10)
|
||||
{
|
||||
new Add(WorkingDirectory, needAdd).Exec();
|
||||
needAdd.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needAdd.Count > 0) {
|
||||
if (needAdd.Count > 0)
|
||||
{
|
||||
new Add(WorkingDirectory, needAdd).Exec();
|
||||
needAdd.Clear();
|
||||
}
|
||||
|
@ -46,24 +55,28 @@ namespace SourceGit.Commands {
|
|||
return succ;
|
||||
}
|
||||
|
||||
public bool Apply(string name) {
|
||||
public bool Apply(string name)
|
||||
{
|
||||
Args = $"stash apply -q {name}";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Pop(string name) {
|
||||
public bool Pop(string name)
|
||||
{
|
||||
Args = $"stash pop -q {name}";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Drop(string name) {
|
||||
public bool Drop(string name)
|
||||
{
|
||||
Args = $"stash drop -q {name}";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Clear() {
|
||||
public bool Clear()
|
||||
{
|
||||
Args = "stash clear";
|
||||
return Exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Statistics : Command {
|
||||
public Statistics(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Statistics : Command
|
||||
{
|
||||
public Statistics(string repo)
|
||||
{
|
||||
_statistics = new Models.Statistics();
|
||||
|
||||
WorkingDirectory = repo;
|
||||
|
@ -10,13 +13,15 @@ namespace SourceGit.Commands {
|
|||
Args = $"log --date-order --branches --remotes --since=\"{_statistics.Since()}\" --pretty=format:\"%ct$%cn\"";
|
||||
}
|
||||
|
||||
public Models.Statistics Result() {
|
||||
public Models.Statistics Result()
|
||||
{
|
||||
Exec();
|
||||
_statistics.Complete();
|
||||
return _statistics;
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
var dateEndIdx = line.IndexOf('$', StringComparison.Ordinal);
|
||||
if (dateEndIdx == -1) return;
|
||||
|
||||
|
@ -27,6 +32,6 @@ namespace SourceGit.Commands {
|
|||
_statistics.AddCommit(line.Substring(dateEndIdx + 1), date);
|
||||
}
|
||||
|
||||
private Models.Statistics _statistics = null;
|
||||
private readonly Models.Statistics _statistics = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +1,41 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public class Submodule : Command {
|
||||
public Submodule(string repo) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Submodule : Command
|
||||
{
|
||||
public Submodule(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Add(string url, string relativePath, bool recursive, Action<string> outputHandler) {
|
||||
public bool Add(string url, string relativePath, bool recursive, Action<string> outputHandler)
|
||||
{
|
||||
_outputHandler = outputHandler;
|
||||
Args = $"submodule add {url} {relativePath}";
|
||||
if (!Exec()) return false;
|
||||
|
||||
if (recursive) {
|
||||
if (recursive)
|
||||
{
|
||||
Args = $"submodule update --init --recursive -- {relativePath}";
|
||||
return Exec();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = $"submodule update --init -- {relativePath}";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Update() {
|
||||
public bool Update()
|
||||
{
|
||||
Args = $"submodule update --rebase --remote";
|
||||
return Exec();
|
||||
}
|
||||
|
||||
public bool Delete(string relativePath) {
|
||||
public bool Delete(string relativePath)
|
||||
{
|
||||
Args = $"submodule deinit -f {relativePath}";
|
||||
if (!Exec()) return false;
|
||||
|
||||
|
@ -34,10 +43,11 @@ namespace SourceGit.Commands {
|
|||
return Exec();
|
||||
}
|
||||
|
||||
protected override void OnReadline(string line) {
|
||||
protected override void OnReadline(string line)
|
||||
{
|
||||
_outputHandler?.Invoke(line);
|
||||
}
|
||||
|
||||
private Action<string> _outputHandler;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +1,43 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands {
|
||||
public static class Tag {
|
||||
public static bool Add(string repo, string name, string basedOn, string message) {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class Tag
|
||||
{
|
||||
public static bool Add(string repo, string name, string basedOn, string message)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"tag -a {name} {basedOn} ";
|
||||
|
||||
if (!string.IsNullOrEmpty(message)) {
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
string tmp = Path.GetTempFileName();
|
||||
File.WriteAllText(tmp, message);
|
||||
cmd.Args += $"-F \"{tmp}\"";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Args += $"-m {name}";
|
||||
}
|
||||
|
||||
return cmd.Exec();
|
||||
}
|
||||
|
||||
public static bool Delete(string repo, string name, List<Models.Remote> remotes) {
|
||||
public static bool Delete(string repo, string name, List<Models.Remote> remotes)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"tag --delete {name}";
|
||||
if (!cmd.Exec()) return false;
|
||||
|
||||
if (remotes != null) {
|
||||
foreach (var r in remotes) {
|
||||
if (remotes != null)
|
||||
{
|
||||
foreach (var r in remotes)
|
||||
{
|
||||
new Push(repo, r.Name, name, true).Exec();
|
||||
}
|
||||
}
|
||||
|
@ -36,4 +45,4 @@ namespace SourceGit.Commands {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,18 @@
|
|||
namespace SourceGit.Commands {
|
||||
public class Version : Command {
|
||||
public Version() {
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Version : Command
|
||||
{
|
||||
public Version()
|
||||
{
|
||||
Args = "--version";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public string Query() {
|
||||
public string Query()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess || string.IsNullOrWhiteSpace(rs.StdOut)) return string.Empty;
|
||||
return rs.StdOut.Trim().Substring("git version ".Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue