Skip to content

Commit 84101cd

Browse files
committed
Async command methods
1 parent 25afcba commit 84101cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2338
-6
lines changed

src/Commands/Blame.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Text;
33
using System.Text.RegularExpressions;
4+
using System.Threading.Tasks;
45

56
namespace SourceGit.Commands
67
{
@@ -49,6 +50,36 @@ public Models.BlameData Result()
4950
return _result;
5051
}
5152

53+
public async Task<Models.BlameData> ResultAsync()
54+
{
55+
var rs = await ReadToEndAsync();
56+
if (!rs.IsSuccess)
57+
return _result;
58+
59+
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
60+
foreach (var line in lines)
61+
{
62+
ParseLine(line);
63+
64+
if (_result.IsBinary)
65+
break;
66+
}
67+
68+
if (_needUnifyCommitSHA)
69+
{
70+
foreach (var line in _result.LineInfos)
71+
{
72+
if (line.CommitSHA.Length > _minSHALen)
73+
{
74+
line.CommitSHA = line.CommitSHA.Substring(0, _minSHALen);
75+
}
76+
}
77+
}
78+
79+
_result.Content = _content.ToString();
80+
return _result;
81+
}
82+
5283
private void ParseLine(string line)
5384
{
5485
if (line.Contains('\0', StringComparison.Ordinal))

src/Commands/Branch.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text;
2+
using System.Threading.Tasks;
23

34
namespace SourceGit.Commands
45
{
@@ -79,5 +80,81 @@ public static bool DeleteRemote(string repo, string remote, string name, Models.
7980
cmd.Log = log;
8081
return cmd.Exec();
8182
}
83+
84+
public static async Task<string> ShowCurrentAsync(string repo)
85+
{
86+
var cmd = new Command();
87+
cmd.WorkingDirectory = repo;
88+
cmd.Context = repo;
89+
cmd.Args = "branch --show-current";
90+
return (await cmd.ReadToEndAsync()).StdOut.Trim();
91+
}
92+
93+
public static async Task<bool> CreateAsync(string repo, string name, string basedOn, bool force, Models.ICommandLog log)
94+
{
95+
var builder = new StringBuilder();
96+
builder.Append("branch ");
97+
if (force)
98+
builder.Append("-f ");
99+
builder.Append(name);
100+
builder.Append(" ");
101+
builder.Append(basedOn);
102+
103+
var cmd = new Command();
104+
cmd.WorkingDirectory = repo;
105+
cmd.Context = repo;
106+
cmd.Args = builder.ToString();
107+
cmd.Log = log;
108+
return await cmd.ExecAsync();
109+
}
110+
111+
public static async Task<bool> RenameAsync(string repo, string name, string to, Models.ICommandLog log)
112+
{
113+
var cmd = new Command();
114+
cmd.WorkingDirectory = repo;
115+
cmd.Context = repo;
116+
cmd.Args = $"branch -M {name} {to}";
117+
cmd.Log = log;
118+
return await cmd.ExecAsync();
119+
}
120+
121+
public static async Task<bool> SetUpstreamAsync(string repo, string name, string upstream, Models.ICommandLog log)
122+
{
123+
var cmd = new Command();
124+
cmd.WorkingDirectory = repo;
125+
cmd.Context = repo;
126+
cmd.Log = log;
127+
128+
if (string.IsNullOrEmpty(upstream))
129+
cmd.Args = $"branch {name} --unset-upstream";
130+
else
131+
cmd.Args = $"branch {name} -u {upstream}";
132+
133+
return await cmd.ExecAsync();
134+
}
135+
136+
public static async Task<bool> DeleteLocalAsync(string repo, string name, Models.ICommandLog log)
137+
{
138+
var cmd = new Command();
139+
cmd.WorkingDirectory = repo;
140+
cmd.Context = repo;
141+
cmd.Args = $"branch -D {name}";
142+
cmd.Log = log;
143+
return await cmd.ExecAsync();
144+
}
145+
146+
public static async Task<bool> DeleteRemoteAsync(string repo, string remote, string name, Models.ICommandLog log)
147+
{
148+
bool exists = await new Remote(repo).HasBranchAsync(remote, name);
149+
if (exists)
150+
return await new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.ExecAsync();
151+
152+
var cmd = new Command();
153+
cmd.WorkingDirectory = repo;
154+
cmd.Context = repo;
155+
cmd.Args = $"branch -D -r {remote}/{name}";
156+
cmd.Log = log;
157+
return await cmd.ExecAsync();
158+
}
82159
}
83160
}

src/Commands/Checkout.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using System.Text;
3+
using System.Threading.Tasks;
34

45
namespace SourceGit.Commands
56
{
@@ -78,5 +79,74 @@ public bool FileWithRevision(string file, string revision)
7879
Args = $"checkout --no-overlay {revision} -- \"{file}\"";
7980
return Exec();
8081
}
82+
83+
public async Task<bool> BranchAsync(string branch, bool force)
84+
{
85+
var builder = new StringBuilder();
86+
builder.Append("checkout --progress ");
87+
if (force)
88+
builder.Append("--force ");
89+
builder.Append(branch);
90+
91+
Args = builder.ToString();
92+
return await ExecAsync();
93+
}
94+
95+
public async Task<bool> BranchAsync(string branch, string basedOn, bool force, bool allowOverwrite)
96+
{
97+
var builder = new StringBuilder();
98+
builder.Append("checkout --progress ");
99+
if (force)
100+
builder.Append("--force ");
101+
builder.Append(allowOverwrite ? "-B " : "-b ");
102+
builder.Append(branch);
103+
builder.Append(" ");
104+
builder.Append(basedOn);
105+
106+
Args = builder.ToString();
107+
return await ExecAsync();
108+
}
109+
110+
public async Task<bool> CommitAsync(string commitId, bool force)
111+
{
112+
var option = force ? "--force" : string.Empty;
113+
Args = $"checkout {option} --detach --progress {commitId}";
114+
return await ExecAsync();
115+
}
116+
117+
public async Task<bool> UseTheirsAsync(List<string> files)
118+
{
119+
var builder = new StringBuilder();
120+
builder.Append("checkout --theirs --");
121+
foreach (var f in files)
122+
{
123+
builder.Append(" \"");
124+
builder.Append(f);
125+
builder.Append("\"");
126+
}
127+
Args = builder.ToString();
128+
return await ExecAsync();
129+
}
130+
131+
public async Task<bool> UseMineAsync(List<string> files)
132+
{
133+
var builder = new StringBuilder();
134+
builder.Append("checkout --ours --");
135+
foreach (var f in files)
136+
{
137+
builder.Append(" \"");
138+
builder.Append(f);
139+
builder.Append("\"");
140+
}
141+
142+
Args = builder.ToString();
143+
return await ExecAsync();
144+
}
145+
146+
public async Task<bool> FileWithRevisionAsync(string file, string revision)
147+
{
148+
Args = $"checkout --no-overlay {revision} -- \"{file}\"";
149+
return await ExecAsync();
150+
}
81151
}
82152
}

src/Commands/Command.cs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text;
55
using System.Text.RegularExpressions;
66
using System.Threading;
7+
using System.Threading.Tasks;
78

89
namespace SourceGit.Commands
910
{
@@ -135,6 +136,109 @@ public ReadToEndResult ReadToEnd()
135136
return rs;
136137
}
137138

139+
public async Task<bool> ExecAsync()
140+
{
141+
Log?.AppendLine($"$ git {Args}\n");
142+
143+
var start = CreateGitStartInfo();
144+
var errs = new List<string>();
145+
var proc = new Process() { StartInfo = start };
146+
147+
proc.OutputDataReceived += (_, e) => HandleOutput(e.Data, errs);
148+
proc.ErrorDataReceived += (_, e) => HandleOutput(e.Data, errs);
149+
150+
var dummy = null as Process;
151+
var dummyProcLock = new object();
152+
try
153+
{
154+
proc.Start();
155+
156+
// It not safe, please only use `CancellationToken` in readonly commands.
157+
if (CancellationToken.CanBeCanceled)
158+
{
159+
dummy = proc;
160+
CancellationToken.Register(() =>
161+
{
162+
lock (dummyProcLock)
163+
{
164+
if (dummy is { HasExited: false })
165+
dummy.Kill();
166+
}
167+
});
168+
}
169+
}
170+
catch (Exception e)
171+
{
172+
if (RaiseError)
173+
App.RaiseException(Context, e.Message);
174+
175+
Log?.AppendLine(string.Empty);
176+
return false;
177+
}
178+
179+
proc.BeginOutputReadLine();
180+
proc.BeginErrorReadLine();
181+
await proc.WaitForExitAsync(CancellationToken);
182+
183+
if (dummy != null)
184+
{
185+
lock (dummyProcLock)
186+
{
187+
dummy = null;
188+
}
189+
}
190+
191+
int exitCode = proc.ExitCode;
192+
proc.Close();
193+
Log?.AppendLine(string.Empty);
194+
195+
if (!CancellationToken.IsCancellationRequested && exitCode != 0)
196+
{
197+
if (RaiseError)
198+
{
199+
var errMsg = string.Join("\n", errs).Trim();
200+
if (!string.IsNullOrEmpty(errMsg))
201+
App.RaiseException(Context, errMsg);
202+
}
203+
204+
return false;
205+
}
206+
207+
return true;
208+
}
209+
210+
public async Task<ReadToEndResult> ReadToEndAsync()
211+
{
212+
var start = CreateGitStartInfo();
213+
var proc = new Process() { StartInfo = start };
214+
215+
try
216+
{
217+
proc.Start();
218+
}
219+
catch (Exception e)
220+
{
221+
return new ReadToEndResult()
222+
{
223+
IsSuccess = false,
224+
StdOut = string.Empty,
225+
StdErr = e.Message,
226+
};
227+
}
228+
229+
var rs = new ReadToEndResult()
230+
{
231+
StdOut = await proc.StandardOutput.ReadToEndAsync(CancellationToken),
232+
StdErr = await proc.StandardError.ReadToEndAsync(CancellationToken),
233+
};
234+
235+
await proc.WaitForExitAsync(CancellationToken);
236+
rs.IsSuccess = proc.ExitCode == 0;
237+
proc.Close();
238+
239+
return rs;
240+
}
241+
138242
private ProcessStartInfo CreateGitStartInfo()
139243
{
140244
var start = new ProcessStartInfo();

src/Commands/Commit.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.IO;
2+
using System.Threading.Tasks;
23

34
namespace SourceGit.Commands
45
{
@@ -34,6 +35,22 @@ public bool Run()
3435
return succ;
3536
}
3637

38+
public async Task<bool> RunAsync()
39+
{
40+
var succ = await ExecAsync();
41+
42+
try
43+
{
44+
File.Delete(_tmpFile);
45+
}
46+
catch
47+
{
48+
// Ignore
49+
}
50+
51+
return succ;
52+
}
53+
3754
private readonly string _tmpFile;
3855
}
3956
}

src/Commands/CompareRevisions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Text.RegularExpressions;
4+
using System.Threading.Tasks;
45

56
namespace SourceGit.Commands
67
{
@@ -43,6 +44,20 @@ public CompareRevisions(string repo, string start, string end, string path)
4344
return _changes;
4445
}
4546

47+
public async Task<List<Models.Change>> ResultAsync()
48+
{
49+
var rs = await ReadToEndAsync();
50+
if (!rs.IsSuccess)
51+
return _changes;
52+
53+
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
54+
foreach (var line in lines)
55+
ParseLine(line);
56+
57+
_changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
58+
return _changes;
59+
}
60+
4661
private void ParseLine(string line)
4762
{
4863
var match = REG_FORMAT().Match(line);

0 commit comments

Comments
 (0)