Skip to content

Commit 9be50eb

Browse files
committed
enhance: do not create temp string for large output of some git command
Signed-off-by: leo <[email protected]>
1 parent 632e394 commit 9be50eb

File tree

8 files changed

+319
-300
lines changed

8 files changed

+319
-300
lines changed

src/Commands/CompareRevisions.cs

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using System;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using System.Diagnostics;
33
using System.Text.RegularExpressions;
44
using System.Threading.Tasks;
55

@@ -33,56 +33,62 @@ public CompareRevisions(string repo, string start, string end, string path)
3333
public async Task<List<Models.Change>> ReadAsync()
3434
{
3535
var changes = new List<Models.Change>();
36-
var rs = await ReadToEndAsync().ConfigureAwait(false);
37-
if (!rs.IsSuccess)
38-
return changes;
36+
try
37+
{
38+
using var proc = new Process();
39+
proc.StartInfo = CreateGitStartInfo(true);
40+
proc.Start();
3941

40-
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
41-
foreach (var line in lines)
42-
ParseLine(changes, line);
42+
while (await proc.StandardOutput.ReadLineAsync() is { } line)
43+
{
44+
var match = REG_FORMAT().Match(line);
45+
if (!match.Success)
46+
{
47+
match = REG_RENAME_FORMAT().Match(line);
48+
if (match.Success)
49+
{
50+
var renamed = new Models.Change() { Path = match.Groups[1].Value };
51+
renamed.Set(Models.ChangeState.Renamed);
52+
changes.Add(renamed);
53+
}
4354

44-
changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
45-
return changes;
46-
}
55+
continue;
56+
}
4757

48-
private void ParseLine(List<Models.Change> outs, string line)
49-
{
50-
var match = REG_FORMAT().Match(line);
51-
if (!match.Success)
52-
{
53-
match = REG_RENAME_FORMAT().Match(line);
54-
if (match.Success)
55-
{
56-
var renamed = new Models.Change() { Path = match.Groups[1].Value };
57-
renamed.Set(Models.ChangeState.Renamed);
58-
outs.Add(renamed);
59-
}
58+
var change = new Models.Change() { Path = match.Groups[2].Value };
59+
var status = match.Groups[1].Value;
6060

61-
return;
62-
}
61+
switch (status[0])
62+
{
63+
case 'M':
64+
change.Set(Models.ChangeState.Modified);
65+
changes.Add(change);
66+
break;
67+
case 'A':
68+
change.Set(Models.ChangeState.Added);
69+
changes.Add(change);
70+
break;
71+
case 'D':
72+
change.Set(Models.ChangeState.Deleted);
73+
changes.Add(change);
74+
break;
75+
case 'C':
76+
change.Set(Models.ChangeState.Copied);
77+
changes.Add(change);
78+
break;
79+
}
80+
}
6381

64-
var change = new Models.Change() { Path = match.Groups[2].Value };
65-
var status = match.Groups[1].Value;
82+
await proc.WaitForExitAsync().ConfigureAwait(false);
6683

67-
switch (status[0])
84+
changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
85+
}
86+
catch
6887
{
69-
case 'M':
70-
change.Set(Models.ChangeState.Modified);
71-
outs.Add(change);
72-
break;
73-
case 'A':
74-
change.Set(Models.ChangeState.Added);
75-
outs.Add(change);
76-
break;
77-
case 'D':
78-
change.Set(Models.ChangeState.Deleted);
79-
outs.Add(change);
80-
break;
81-
case 'C':
82-
change.Set(Models.ChangeState.Copied);
83-
outs.Add(change);
84-
break;
88+
//ignore changes;
8589
}
90+
91+
return changes;
8692
}
8793
}
8894
}

src/Commands/Diff.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.IO;
3+
using System.Diagnostics;
44
using System.Text.RegularExpressions;
55
using System.Threading.Tasks;
66

@@ -35,10 +35,21 @@ public Diff(string repo, Models.DiffOption opt, int unified, bool ignoreWhitespa
3535

3636
public async Task<Models.DiffResult> ReadAsync()
3737
{
38-
var rs = await ReadToEndAsync().ConfigureAwait(false);
39-
var sr = new StringReader(rs.StdOut);
40-
while (sr.ReadLine() is { } line)
41-
ParseLine(line);
38+
try
39+
{
40+
using var proc = new Process();
41+
proc.StartInfo = CreateGitStartInfo(true);
42+
proc.Start();
43+
44+
while (await proc.StandardOutput.ReadLineAsync() is { } line)
45+
ParseLine(line);
46+
47+
await proc.WaitForExitAsync().ConfigureAwait(false);
48+
}
49+
catch
50+
{
51+
// Ignore exceptions.
52+
}
4253

4354
if (_result.IsBinary || _result.IsLFS || _result.TextDiff.Lines.Count == 0)
4455
{

src/Commands/QueryCommits.cs

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

@@ -11,7 +12,7 @@ public QueryCommits(string repo, string limits, bool needFindHead = true)
1112
{
1213
WorkingDirectory = repo;
1314
Context = repo;
14-
Args = $"log --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {limits}";
15+
Args = $"log --no-show-signature --decorate=full --format=%H%x00%P%x00%D%x00%aN±%aE%x00%at%x00%cN±%cE%x00%ct%x00%s {limits}";
1516
_findFirstMerged = needFindHead;
1617
}
1718

@@ -50,80 +51,55 @@ public QueryCommits(string repo, string filter, Models.CommitSearchMethod method
5051

5152
WorkingDirectory = repo;
5253
Context = repo;
53-
Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {search}";
54+
Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%x00%P%x00%D%x00%aN±%aE%x00%at%x00%cN±%cE%x00%ct%x00%s {search}";
5455
_findFirstMerged = false;
5556
}
5657

5758
public async Task<List<Models.Commit>> GetResultAsync()
5859
{
59-
var rs = await ReadToEndAsync().ConfigureAwait(false);
60-
if (!rs.IsSuccess)
61-
return _commits;
62-
63-
var nextPartIdx = 0;
64-
var start = 0;
65-
var end = rs.StdOut.IndexOf('\n', start);
66-
while (end > 0)
60+
var commits = new List<Models.Commit>();
61+
try
6762
{
68-
var line = rs.StdOut.Substring(start, end - start);
69-
switch (nextPartIdx)
63+
using var proc = new Process();
64+
proc.StartInfo = CreateGitStartInfo(true);
65+
proc.Start();
66+
67+
while (await proc.StandardOutput.ReadLineAsync() is { } line)
7068
{
71-
case 0:
72-
_current = new Models.Commit() { SHA = line };
73-
_commits.Add(_current);
74-
break;
75-
case 1:
76-
ParseParent(line);
77-
break;
78-
case 2:
79-
_current.ParseDecorators(line);
80-
if (_current.IsMerged && !_isHeadFound)
81-
_isHeadFound = true;
82-
break;
83-
case 3:
84-
_current.Author = Models.User.FindOrAdd(line);
85-
break;
86-
case 4:
87-
_current.AuthorTime = ulong.Parse(line);
88-
break;
89-
case 5:
90-
_current.Committer = Models.User.FindOrAdd(line);
91-
break;
92-
case 6:
93-
_current.CommitterTime = ulong.Parse(line);
94-
break;
95-
case 7:
96-
_current.Subject = line;
97-
nextPartIdx = -1;
98-
break;
69+
var parts = line.Split('\0');
70+
if (parts.Length != 8)
71+
continue;
72+
73+
var commit = new Models.Commit() { SHA = parts[0] };
74+
commit.ParseParents(parts[1]);
75+
commit.ParseDecorators(parts[2]);
76+
commit.Author = Models.User.FindOrAdd(parts[3]);
77+
commit.AuthorTime = ulong.Parse(parts[4]);
78+
commit.Committer = Models.User.FindOrAdd(parts[5]);
79+
commit.CommitterTime = ulong.Parse(parts[6]);
80+
commit.Subject = parts[7];
81+
commits.Add(commit);
82+
83+
if (commit.IsMerged && !_isHeadFound)
84+
_isHeadFound = true;
9985
}
10086

101-
nextPartIdx++;
87+
await proc.WaitForExitAsync().ConfigureAwait(false);
10288

103-
start = end + 1;
104-
end = rs.StdOut.IndexOf('\n', start);
89+
if (_findFirstMerged && !_isHeadFound && commits.Count > 0)
90+
await MarkFirstMergedAsync(commits).ConfigureAwait(false);
91+
}
92+
catch (Exception e)
93+
{
94+
App.RaiseException(Context, $"Failed to query commits. Reason: {e.Message}");
10595
}
10696

107-
if (start < rs.StdOut.Length)
108-
_current.Subject = rs.StdOut.Substring(start);
109-
110-
if (_findFirstMerged && !_isHeadFound && _commits.Count > 0)
111-
await MarkFirstMergedAsync().ConfigureAwait(false);
112-
113-
return _commits;
114-
}
115-
116-
private void ParseParent(string data)
117-
{
118-
if (data.Length < 8)
119-
return;
120-
121-
_current.Parents.AddRange(data.Split(' ', StringSplitOptions.RemoveEmptyEntries));
97+
return commits;
12298
}
12399

124-
private async Task MarkFirstMergedAsync()
100+
private async Task MarkFirstMergedAsync(List<Models.Commit> commits)
125101
{
126-
Args = $"log --since={_commits[^1].CommitterTimeStr.Quoted()} --format=\"%H\"";
102+
Args = $"log --since={commits[^1].CommitterTimeStr.Quoted()} --format=\"%H\"";
127103

128104
var rs = await ReadToEndAsync().ConfigureAwait(false);
129105
var shas = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
@@ -132,7 +108,7 @@ private async Task MarkFirstMergedAsync()
132108

133109
var set = new HashSet<string>(shas);
134110

135-
foreach (var c in _commits)
111+
foreach (var c in commits)
136112
{
137113
if (set.Contains(c.SHA))
138114
{
@@ -142,8 +118,6 @@ private async Task MarkFirstMergedAsync()
142118
}
143119
}
144120

145-
private List<Models.Commit> _commits = new List<Models.Commit>();
146-
private Models.Commit _current = null;
147121
private bool _findFirstMerged = false;
148122
private bool _isHeadFound = false;
149123
}

src/Commands/QueryCommitsForInteractiveRebase.cs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@ public QueryCommitsForInteractiveRebase(string repo, string on)
1717

1818
public async Task<List<Models.InteractiveCommit>> GetResultAsync()
1919
{
20+
var commits = new List<Models.InteractiveCommit>();
2021
var rs = await ReadToEndAsync().ConfigureAwait(false);
2122
if (!rs.IsSuccess)
22-
return _commits;
23+
{
24+
App.RaiseException(Context, $"Failed to query commits for interactive-rebase. Reason: {rs.StdErr}");
25+
return commits;
26+
}
27+
28+
Models.InteractiveCommit current = null;
2329

2430
var nextPartIdx = 0;
2531
var start = 0;
@@ -30,38 +36,38 @@ public QueryCommitsForInteractiveRebase(string repo, string on)
3036
switch (nextPartIdx)
3137
{
3238
case 0:
33-
_current = new Models.InteractiveCommit();
34-
_current.Commit.SHA = line;
35-
_commits.Add(_current);
39+
current = new Models.InteractiveCommit();
40+
current.Commit.SHA = line;
41+
commits.Add(current);
3642
break;
3743
case 1:
38-
ParseParent(line);
44+
current.Commit.ParseParents(line);
3945
break;
4046
case 2:
41-
_current.Commit.ParseDecorators(line);
47+
current.Commit.ParseDecorators(line);
4248
break;
4349
case 3:
44-
_current.Commit.Author = Models.User.FindOrAdd(line);
50+
current.Commit.Author = Models.User.FindOrAdd(line);
4551
break;
4652
case 4:
47-
_current.Commit.AuthorTime = ulong.Parse(line);
53+
current.Commit.AuthorTime = ulong.Parse(line);
4854
break;
4955
case 5:
50-
_current.Commit.Committer = Models.User.FindOrAdd(line);
56+
current.Commit.Committer = Models.User.FindOrAdd(line);
5157
break;
5258
case 6:
53-
_current.Commit.CommitterTime = ulong.Parse(line);
59+
current.Commit.CommitterTime = ulong.Parse(line);
5460
break;
5561
default:
5662
var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal);
5763
if (boundary > end)
5864
{
59-
_current.Message = rs.StdOut.Substring(start, boundary - start - 1);
65+
current.Message = rs.StdOut.Substring(start, boundary - start - 1);
6066
end = boundary + _boundary.Length;
6167
}
6268
else
6369
{
64-
_current.Message = rs.StdOut.Substring(start);
70+
current.Message = rs.StdOut.Substring(start);
6571
end = rs.StdOut.Length - 2;
6672
}
6773

@@ -78,19 +84,9 @@ public QueryCommitsForInteractiveRebase(string repo, string on)
7884
end = rs.StdOut.IndexOf('\n', start);
7985
}
8086

81-
return _commits;
82-
}
83-
84-
private void ParseParent(string data)
85-
{
86-
if (data.Length < 8)
87-
return;
88-
89-
_current.Commit.Parents.AddRange(data.Split(' ', StringSplitOptions.RemoveEmptyEntries));
87+
return commits;
9088
}
9189

92-
private List<Models.InteractiveCommit> _commits = [];
93-
private Models.InteractiveCommit _current = null;
9490
private readonly string _boundary;
9591
}
9692
}

0 commit comments

Comments
 (0)