sourcegit/src/Commands/QueryCommits.cs

200 lines
6.6 KiB
C#
Raw Normal View History

using System;
2021-04-29 05:05:55 -07:00
using System.Collections.Generic;
using System.Text;
2021-04-29 05:05:55 -07:00
namespace SourceGit.Commands
{
public class QueryCommits : Command
{
public QueryCommits(string repo, string limits, bool needFindHead = true)
{
_endOfBodyToken = $"----- END OF BODY {Guid.NewGuid()} -----";
WorkingDirectory = repo;
Context = repo;
Args = $"log --date-order --no-show-signature --decorate=full --pretty=format:\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_endOfBodyToken}\" " + limits;
_findFirstMerged = needFindHead;
2021-04-29 05:05:55 -07:00
}
public List<Models.Commit> Result()
{
2021-04-29 05:05:55 -07:00
Exec();
if (_findFirstMerged && !_isHeadFounded && _commits.Count > 0)
2021-04-29 05:05:55 -07:00
MarkFirstMerged();
return _commits;
2021-04-29 05:05:55 -07:00
}
protected override void OnReadline(string line)
{
switch (_nextPartIdx)
{
case 0:
_current = new Models.Commit() { SHA = line };
_isSubjectSet = false;
_commits.Add(_current);
break;
case 1:
ParseParent(line);
break;
case 2:
ParseDecorators(line);
break;
case 3:
_current.Author = Models.User.FindOrAdd(line);
break;
case 4:
_current.AuthorTime = ulong.Parse(line);
break;
case 5:
_current.Committer = Models.User.FindOrAdd(line);
break;
case 6:
_current.CommitterTime = ulong.Parse(line);
break;
default:
if (line.Equals(_endOfBodyToken, StringComparison.Ordinal))
{
_nextPartIdx = 0;
_current.Message = _messageReader.ToString().Trim();
_messageReader.Clear();
}
else if (!_isSubjectSet)
{
_isSubjectSet = true;
_current.Subject = line;
}
else
{
_messageReader.AppendLine(line);
}
return;
2021-04-29 05:05:55 -07:00
}
_nextPartIdx++;
2021-04-29 05:05:55 -07:00
}
private void ParseParent(string data)
{
if (data.Length < 8)
return;
var idx = data.IndexOf(' ', StringComparison.Ordinal);
if (idx == -1)
{
_current.Parents.Add(data);
return;
}
_current.Parents.Add(data.Substring(0, idx));
_current.Parents.Add(data.Substring(idx + 1));
}
private void ParseDecorators(string data)
{
if (data.Length < 3)
return;
var subs = data.Split(',', StringSplitOptions.RemoveEmptyEntries);
foreach (var sub in subs)
{
2021-04-29 05:05:55 -07:00
var d = sub.Trim();
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
{
_current.Decorators.Add(new Models.Decorator()
{
2021-04-29 05:05:55 -07:00
Type = Models.DecoratorType.Tag,
Name = d.Substring(15).Trim(),
});
}
else if (d.EndsWith("/HEAD", StringComparison.Ordinal))
{
2021-04-29 05:05:55 -07:00
continue;
}
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
{
_current.IsMerged = true;
_current.Decorators.Add(new Models.Decorator()
{
2021-04-29 05:05:55 -07:00
Type = Models.DecoratorType.CurrentBranchHead,
Name = d.Substring(19).Trim(),
});
}
else if (d.Equals("HEAD"))
{
_current.IsMerged = true;
_current.Decorators.Add(new Models.Decorator()
{
Type = Models.DecoratorType.CurrentCommitHead,
Name = d.Trim(),
});
}
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
{
_current.Decorators.Add(new Models.Decorator()
{
2021-04-29 05:05:55 -07:00
Type = Models.DecoratorType.LocalBranchHead,
Name = d.Substring(11).Trim(),
});
}
else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal))
{
_current.Decorators.Add(new Models.Decorator()
{
2021-04-29 05:05:55 -07:00
Type = Models.DecoratorType.RemoteBranchHead,
Name = d.Substring(13).Trim(),
});
}
}
_current.Decorators.Sort((l, r) =>
{
if (l.Type != r.Type)
{
return (int)l.Type - (int)r.Type;
}
else
{
return l.Name.CompareTo(r.Name);
}
});
if (_current.IsMerged && !_isHeadFounded)
_isHeadFounded = true;
2021-04-29 05:05:55 -07:00
}
private void MarkFirstMerged()
{
Args = $"log --since=\"{_commits[_commits.Count - 1].CommitterTimeStr}\" --format=\"%H\"";
2021-04-29 05:05:55 -07:00
var rs = ReadToEnd();
var shas = rs.StdOut.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
if (shas.Length == 0)
return;
2021-04-29 05:05:55 -07:00
var set = new HashSet<string>();
foreach (var sha in shas)
set.Add(sha);
foreach (var c in _commits)
{
if (set.Contains(c.SHA))
{
2021-04-29 05:05:55 -07:00
c.IsMerged = true;
break;
2021-04-29 05:05:55 -07:00
}
}
}
private string _endOfBodyToken = string.Empty;
private List<Models.Commit> _commits = new List<Models.Commit>();
private Models.Commit _current = null;
private bool _isHeadFounded = false;
private readonly bool _findFirstMerged = true;
private int _nextPartIdx = 0;
private bool _isSubjectSet = false;
private StringBuilder _messageReader = new StringBuilder();
2021-04-29 05:05:55 -07:00
}
}