2024-02-05 23:08:37 -08:00
|
|
|
|
using System;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
namespace SourceGit.Commands
|
|
|
|
|
{
|
|
|
|
|
public class QueryCommits : Command
|
|
|
|
|
{
|
2024-03-31 01:54:29 -07:00
|
|
|
|
private const string GPGSIG_START = "gpgsig -----BEGIN PGP SIGNATURE-----";
|
|
|
|
|
private const string GPGSIG_END = " -----END PGP SIGNATURE-----";
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private readonly List<Models.Commit> commits = new List<Models.Commit>();
|
2021-04-29 05:05:55 -07:00
|
|
|
|
private Models.Commit current = null;
|
|
|
|
|
private bool isSkipingGpgsig = false;
|
|
|
|
|
private bool isHeadFounded = false;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private readonly bool findFirstMerged = true;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public QueryCommits(string repo, string limits, bool needFindHead = true)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
WorkingDirectory = repo;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Args = "log --date-order --decorate=full --pretty=raw " + limits;
|
|
|
|
|
findFirstMerged = needFindHead;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public List<Models.Commit> Result()
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Exec();
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (current != null)
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
current.Message = current.Message.Trim();
|
|
|
|
|
commits.Add(current);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (findFirstMerged && !isHeadFounded && commits.Count > 0)
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
MarkFirstMerged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commits;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
protected override void OnReadline(string line)
|
|
|
|
|
{
|
|
|
|
|
if (isSkipingGpgsig)
|
|
|
|
|
{
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (line.StartsWith(GPGSIG_END, StringComparison.Ordinal))
|
|
|
|
|
isSkipingGpgsig = false;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
return;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal))
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
isSkipingGpgsig = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (line.StartsWith("commit ", StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
if (current != null)
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
current.Message = current.Message.Trim();
|
|
|
|
|
commits.Add(current);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = new Models.Commit();
|
|
|
|
|
line = line.Substring(7);
|
|
|
|
|
|
2024-03-13 20:09:05 -07:00
|
|
|
|
var decoratorStart = line.IndexOf('(', StringComparison.Ordinal);
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (decoratorStart < 0)
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
current.SHA = line.Trim();
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
current.SHA = line.Substring(0, decoratorStart).Trim();
|
|
|
|
|
current.IsMerged = ParseDecorators(current.Decorators, line.Substring(decoratorStart + 1));
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (!isHeadFounded)
|
|
|
|
|
isHeadFounded = current.IsMerged;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-31 01:54:29 -07:00
|
|
|
|
if (current == null)
|
|
|
|
|
return;
|
2021-04-29 05:05:55 -07:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (line.StartsWith("tree ", StringComparison.Ordinal))
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
return;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (line.StartsWith("parent ", StringComparison.Ordinal))
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
current.Parents.Add(line.Substring("parent ".Length));
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (line.StartsWith("author ", StringComparison.Ordinal))
|
|
|
|
|
{
|
2023-10-09 20:25:57 -07:00
|
|
|
|
Models.User user = Models.User.Invalid;
|
|
|
|
|
ulong time = 0;
|
2023-10-11 21:02:41 -07:00
|
|
|
|
Models.Commit.ParseUserAndTime(line.Substring(7), ref user, ref time);
|
2023-10-09 20:25:57 -07:00
|
|
|
|
current.Author = user;
|
|
|
|
|
current.AuthorTime = time;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (line.StartsWith("committer ", StringComparison.Ordinal))
|
|
|
|
|
{
|
2023-10-09 20:25:57 -07:00
|
|
|
|
Models.User user = Models.User.Invalid;
|
|
|
|
|
ulong time = 0;
|
2023-10-11 21:02:41 -07:00
|
|
|
|
Models.Commit.ParseUserAndTime(line.Substring(10), ref user, ref time);
|
2023-10-09 20:25:57 -07:00
|
|
|
|
current.Committer = user;
|
|
|
|
|
current.CommitterTime = time;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else if (string.IsNullOrEmpty(current.Subject))
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
current.Subject = line.Trim();
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
current.Message += (line.Trim() + "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private bool ParseDecorators(List<Models.Decorator> decorators, string data)
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
bool isHeadOfCurrent = false;
|
|
|
|
|
|
|
|
|
|
var subs = data.Split(new char[] { ',', ')', '(' }, 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))
|
|
|
|
|
{
|
|
|
|
|
decorators.Add(new Models.Decorator()
|
|
|
|
|
{
|
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))
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
isHeadOfCurrent = true;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
decorators.Add(new Models.Decorator()
|
|
|
|
|
{
|
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
|
|
|
|
}
|
|
|
|
|
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
decorators.Add(new Models.Decorator()
|
|
|
|
|
{
|
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))
|
|
|
|
|
{
|
|
|
|
|
decorators.Add(new Models.Decorator()
|
|
|
|
|
{
|
2021-04-29 05:05:55 -07:00
|
|
|
|
Type = Models.DecoratorType.RemoteBranchHead,
|
|
|
|
|
Name = d.Substring(13).Trim(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
decorators.Sort((l, r) =>
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2021-04-29 05:05:55 -07:00
|
|
|
|
return isHeadOfCurrent;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private void MarkFirstMerged()
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08: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-03-17 18:37:06 -07:00
|
|
|
|
foreach (var c in commits)
|
|
|
|
|
{
|
|
|
|
|
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-03-31 01:54:29 -07:00
|
|
|
|
}
|