2024-02-05 23:08:37 -08:00
|
|
|
|
using System;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
using System.Collections.Generic;
|
2024-06-06 05:25:16 -07:00
|
|
|
|
using System.Text;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
namespace SourceGit.Commands
|
|
|
|
|
{
|
|
|
|
|
public class QueryCommits : Command
|
|
|
|
|
{
|
|
|
|
|
public QueryCommits(string repo, string limits, bool needFindHead = true)
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_endOfBodyToken = $"----- END OF BODY {Guid.NewGuid()} -----";
|
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
|
WorkingDirectory = repo;
|
2024-05-27 02:21:28 -07:00
|
|
|
|
Context = repo;
|
2024-06-04 20:46:31 -07:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public List<Models.Commit> Result()
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Exec();
|
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
if (_findFirstMerged && !_isHeadFounded && _commits.Count > 0)
|
2021-04-29 05:05:55 -07:00
|
|
|
|
MarkFirstMerged();
|
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
return _commits;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
protected override void OnReadline(string line)
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
switch (_nextPartIdx)
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
case 0:
|
|
|
|
|
_current = new Models.Commit() { SHA = line };
|
2024-06-06 05:25:16 -07:00
|
|
|
|
_isSubjectSet = false;
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_commits.Add(_current);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
2024-06-06 05:25:16 -07:00
|
|
|
|
ParseParent(line);
|
2024-06-04 20:46:31 -07:00
|
|
|
|
break;
|
|
|
|
|
case 2:
|
2024-06-06 05:25:16 -07:00
|
|
|
|
ParseDecorators(line);
|
2024-06-04 20:46:31 -07:00
|
|
|
|
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;
|
2024-06-06 05:59:09 -07:00
|
|
|
|
_current.Body = _bodyReader.ToString().TrimEnd();
|
|
|
|
|
_bodyReader.Clear();
|
2024-06-04 20:46:31 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-06-06 05:59:09 -07:00
|
|
|
|
if (!_isSubjectSet)
|
|
|
|
|
{
|
|
|
|
|
_isSubjectSet = true;
|
|
|
|
|
_current.SubjectLen = line.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_bodyReader.AppendLine(line);
|
2024-06-04 20:46:31 -07:00
|
|
|
|
}
|
|
|
|
|
return;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_nextPartIdx++;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 05:25:16 -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));
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
private void ParseDecorators(string data)
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2024-06-06 05:25:16 -07:00
|
|
|
|
if (data.Length < 3)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
var subs = data.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
2024-03-17 18:37:06 -07:00
|
|
|
|
foreach (var sub in subs)
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
var d = sub.Trim();
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_current.Decorators.Add(new Models.Decorator()
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Type = Models.DecoratorType.Tag,
|
|
|
|
|
Name = d.Substring(15).Trim(),
|
|
|
|
|
});
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (d.EndsWith("/HEAD", StringComparison.Ordinal))
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
continue;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_current.IsMerged = true;
|
|
|
|
|
_current.Decorators.Add(new Models.Decorator()
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Type = Models.DecoratorType.CurrentBranchHead,
|
|
|
|
|
Name = d.Substring(19).Trim(),
|
|
|
|
|
});
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
2024-05-25 11:05:32 -07:00
|
|
|
|
else if (d.Equals("HEAD"))
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_current.IsMerged = true;
|
|
|
|
|
_current.Decorators.Add(new Models.Decorator()
|
2024-05-25 11:05:32 -07:00
|
|
|
|
{
|
|
|
|
|
Type = Models.DecoratorType.CurrentCommitHead,
|
|
|
|
|
Name = d.Trim(),
|
|
|
|
|
});
|
|
|
|
|
}
|
2024-03-17 18:37:06 -07:00
|
|
|
|
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_current.Decorators.Add(new Models.Decorator()
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Type = Models.DecoratorType.LocalBranchHead,
|
|
|
|
|
Name = d.Substring(11).Trim(),
|
|
|
|
|
});
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal))
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_current.Decorators.Add(new Models.Decorator()
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Type = Models.DecoratorType.RemoteBranchHead,
|
|
|
|
|
Name = d.Substring(13).Trim(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
_current.Decorators.Sort((l, r) =>
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
|
|
|
|
if (l.Type != r.Type)
|
|
|
|
|
{
|
2021-04-30 02:03:22 -07:00
|
|
|
|
return (int)l.Type - (int)r.Type;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-04-30 02:03:22 -07:00
|
|
|
|
return l.Name.CompareTo(r.Name);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
if (_current.IsMerged && !_isHeadFounded)
|
|
|
|
|
_isHeadFounded = true;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private void MarkFirstMerged()
|
|
|
|
|
{
|
2024-06-04 20:46:31 -07:00
|
|
|
|
Args = $"log --since=\"{_commits[_commits.Count - 1].CommitterTimeStr}\" --format=\"%H\"";
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
|
|
|
|
var rs = ReadToEnd();
|
2024-02-05 23:08:37 -08:00
|
|
|
|
var shas = rs.StdOut.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (shas.Length == 0)
|
|
|
|
|
return;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2021-04-29 18:03:35 -07:00
|
|
|
|
var set = new HashSet<string>();
|
2024-03-31 01:54:29 -07:00
|
|
|
|
foreach (var sha in shas)
|
|
|
|
|
set.Add(sha);
|
2021-04-29 18:03:35 -07:00
|
|
|
|
|
2024-06-04 20:46:31 -07:00
|
|
|
|
foreach (var c in _commits)
|
2024-03-17 18:37:06 -07:00
|
|
|
|
{
|
|
|
|
|
if (set.Contains(c.SHA))
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
c.IsMerged = true;
|
2021-04-29 18:03:35 -07:00
|
|
|
|
break;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-04 20:46:31 -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;
|
2024-06-06 05:59:09 -07:00
|
|
|
|
private bool _findFirstMerged = true;
|
2024-06-04 20:46:31 -07:00
|
|
|
|
private int _nextPartIdx = 0;
|
2024-06-06 05:25:16 -07:00
|
|
|
|
private bool _isSubjectSet = false;
|
2024-06-06 05:59:09 -07:00
|
|
|
|
private StringBuilder _bodyReader = new StringBuilder();
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
2024-03-31 01:54:29 -07:00
|
|
|
|
}
|