mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-24 20:57:19 -08:00
optimize<User>: reduce memory used by commit's author/committer data
This commit is contained in:
parent
d9afb798db
commit
766f24f4b0
14 changed files with 91 additions and 41 deletions
|
@ -8,6 +8,8 @@ namespace SourceGit.Commands {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Blame : Command {
|
public class Blame : Command {
|
||||||
private static readonly Regex REG_FORMAT = new Regex(@"^\^?([0-9a-f]+)\s+.*\((.*)\s+(\d+)\s+[\-\+]?\d+\s+\d+\) (.*)");
|
private static readonly Regex REG_FORMAT = new Regex(@"^\^?([0-9a-f]+)\s+.*\((.*)\s+(\d+)\s+[\-\+]?\d+\s+\d+\) (.*)");
|
||||||
|
private static readonly DateTime UTC_START = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
|
||||||
|
|
||||||
private Data data = new Data();
|
private Data data = new Data();
|
||||||
private bool needUnifyCommitSHA = false;
|
private bool needUnifyCommitSHA = false;
|
||||||
private int minSHALen = 0;
|
private int minSHALen = 0;
|
||||||
|
@ -53,7 +55,7 @@ namespace SourceGit.Commands {
|
||||||
var author = match.Groups[2].Value;
|
var author = match.Groups[2].Value;
|
||||||
var timestamp = int.Parse(match.Groups[3].Value);
|
var timestamp = int.Parse(match.Groups[3].Value);
|
||||||
var content = match.Groups[4].Value;
|
var content = match.Groups[4].Value;
|
||||||
var when = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp).ToLocalTime().ToString("yyyy/MM/dd");
|
var when = UTC_START.AddSeconds(timestamp).ToString("yyyy/MM/dd");
|
||||||
|
|
||||||
var blameLine = new Models.BlameLine() {
|
var blameLine = new Models.BlameLine() {
|
||||||
LineNumber = $"{data.Lines.Count + 1}",
|
LineNumber = $"{data.Lines.Count + 1}",
|
||||||
|
|
|
@ -61,9 +61,9 @@ namespace SourceGit.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ParseTrackStatus(string data) {
|
private string ParseTrackStatus(string data) {
|
||||||
if (string.IsNullOrEmpty(data)) return "";
|
if (string.IsNullOrEmpty(data)) return string.Empty;
|
||||||
|
|
||||||
string track = "";
|
string track = string.Empty;
|
||||||
|
|
||||||
var ahead = REG_AHEAD.Match(data);
|
var ahead = REG_AHEAD.Match(data);
|
||||||
if (ahead.Success) {
|
if (ahead.Success) {
|
||||||
|
|
|
@ -145,7 +145,7 @@ namespace SourceGit.Commands {
|
||||||
proc.Start();
|
proc.Start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return new ReadToEndResult() {
|
return new ReadToEndResult() {
|
||||||
Output = "",
|
Output = string.Empty,
|
||||||
Error = e.Message,
|
Error = e.Message,
|
||||||
IsSuccess = false,
|
IsSuccess = false,
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,9 +75,17 @@ namespace SourceGit.Commands {
|
||||||
} else if (line.StartsWith("parent ", StringComparison.Ordinal)) {
|
} else if (line.StartsWith("parent ", StringComparison.Ordinal)) {
|
||||||
current.Parents.Add(line.Substring("parent ".Length));
|
current.Parents.Add(line.Substring("parent ".Length));
|
||||||
} else if (line.StartsWith("author ", StringComparison.Ordinal)) {
|
} else if (line.StartsWith("author ", StringComparison.Ordinal)) {
|
||||||
current.Author.Parse(line);
|
Models.User user = Models.User.Invalid;
|
||||||
|
ulong time = 0;
|
||||||
|
Models.Commit.ParseUserAndTime(line, ref user, ref time);
|
||||||
|
current.Author = user;
|
||||||
|
current.AuthorTime = time;
|
||||||
} else if (line.StartsWith("committer ", StringComparison.Ordinal)) {
|
} else if (line.StartsWith("committer ", StringComparison.Ordinal)) {
|
||||||
current.Committer.Parse(line);
|
Models.User user = Models.User.Invalid;
|
||||||
|
ulong time = 0;
|
||||||
|
Models.Commit.ParseUserAndTime(line, ref user, ref time);
|
||||||
|
current.Committer = user;
|
||||||
|
current.CommitterTime = time;
|
||||||
} else if (string.IsNullOrEmpty(current.Subject)) {
|
} else if (string.IsNullOrEmpty(current.Subject)) {
|
||||||
current.Subject = line.Trim();
|
current.Subject = line.Trim();
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,7 +137,7 @@ namespace SourceGit.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MarkFirstMerged() {
|
private void MarkFirstMerged() {
|
||||||
Args = $"log --since=\"{commits.Last().Committer.Time}\" --format=\"%H\"";
|
Args = $"log --since=\"{commits.Last().CommitterTimeStr}\" --format=\"%H\"";
|
||||||
|
|
||||||
var rs = ReadToEnd();
|
var rs = ReadToEnd();
|
||||||
var shas = rs.Output.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
var shas = rs.Output.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
|
@ -37,7 +37,11 @@ namespace SourceGit.Commands {
|
||||||
} else if (line.StartsWith("Reflog message: ", StringComparison.Ordinal)) {
|
} else if (line.StartsWith("Reflog message: ", StringComparison.Ordinal)) {
|
||||||
current.Message = line.Substring(16);
|
current.Message = line.Substring(16);
|
||||||
} else if (line.StartsWith("author ", StringComparison.Ordinal)) {
|
} else if (line.StartsWith("author ", StringComparison.Ordinal)) {
|
||||||
current.Author.Parse(line);
|
Models.User user = Models.User.Invalid;
|
||||||
|
ulong time = 0;
|
||||||
|
Models.Commit.ParseUserAndTime(line, ref user, ref time);
|
||||||
|
current.Author = user;
|
||||||
|
current.Time = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace SourceGit.Models {
|
namespace SourceGit.Models {
|
||||||
|
@ -6,16 +8,32 @@ namespace SourceGit.Models {
|
||||||
/// 提交记录
|
/// 提交记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Commit {
|
public class Commit {
|
||||||
public string SHA { get; set; } = "";
|
private static readonly Regex REG_USER_FORMAT = new Regex(@"\w+ (.*) <(.*)> (\d{10}) [\+\-]\d+");
|
||||||
|
private static readonly DateTime UTC_START = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
|
||||||
|
|
||||||
|
public string SHA { get; set; } = string.Empty;
|
||||||
public string ShortSHA => SHA.Substring(0, 8);
|
public string ShortSHA => SHA.Substring(0, 8);
|
||||||
public User Author { get; set; } = new User();
|
public User Author { get; set; } = User.Invalid;
|
||||||
public User Committer { get; set; } = new User();
|
public ulong AuthorTime { get; set; } = 0;
|
||||||
public string Subject { get; set; } = "";
|
public User Committer { get; set; } = User.Invalid;
|
||||||
public string Message { get; set; } = "";
|
public ulong CommitterTime { get; set; } = 0;
|
||||||
|
public string Subject { get; set; } = string.Empty;
|
||||||
|
public string Message { get; set; } = string.Empty;
|
||||||
public List<string> Parents { get; set; } = new List<string>();
|
public List<string> Parents { get; set; } = new List<string>();
|
||||||
public List<Decorator> Decorators { get; set; } = new List<Decorator>();
|
public List<Decorator> Decorators { get; set; } = new List<Decorator>();
|
||||||
public bool HasDecorators => Decorators.Count > 0;
|
public bool HasDecorators => Decorators.Count > 0;
|
||||||
public bool IsMerged { get; set; } = false;
|
public bool IsMerged { get; set; } = false;
|
||||||
public Thickness Margin { get; set; } = new Thickness(0);
|
public Thickness Margin { get; set; } = new Thickness(0);
|
||||||
|
|
||||||
|
public string AuthorTimeStr => UTC_START.AddSeconds(AuthorTime).ToString("yyyy-MM-dd HH:mm:ss");
|
||||||
|
public string CommitterTimeStr => UTC_START.AddSeconds(CommitterTime).ToString("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public static void ParseUserAndTime(string data, ref User user, ref ulong time) {
|
||||||
|
var match = REG_USER_FORMAT.Match(data);
|
||||||
|
if (!match.Success) return;
|
||||||
|
|
||||||
|
user = User.FindOrAdd(match.Groups[1].Value, match.Groups[2].Value);
|
||||||
|
time = ulong.Parse(match.Groups[3].Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace SourceGit.Models {
|
namespace SourceGit.Models {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 贮藏
|
/// 贮藏
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Stash {
|
public class Stash {
|
||||||
|
private static readonly DateTime UTC_START = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
|
||||||
|
|
||||||
public string Name { get; set; } = "";
|
public string Name { get; set; } = "";
|
||||||
public string SHA { get; set; } = "";
|
public string SHA { get; set; } = "";
|
||||||
public User Author { get; set; } = new User();
|
public User Author { get; set; } = User.Invalid;
|
||||||
|
public ulong Time { get; set; } = 0;
|
||||||
public string Message { get; set; } = "";
|
public string Message { get; set; } = "";
|
||||||
|
|
||||||
|
public string TimeStr => UTC_START.AddSeconds(Time).ToString("yyyy-MM-dd HH:mm:ss");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,36 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace SourceGit.Models {
|
namespace SourceGit.Models {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Git用户
|
/// Git用户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class User {
|
public class User {
|
||||||
private static readonly Regex REG_FORMAT = new Regex(@"\w+ (.*) <(.*)> (\d{10}) [\+\-]\d+");
|
public static User Invalid = new User();
|
||||||
|
public static Dictionary<string, User> Caches = new Dictionary<string, User>();
|
||||||
|
|
||||||
public string Name { get; set; } = "";
|
public string Name { get; set; } = string.Empty;
|
||||||
public string Email { get; set; } = "";
|
public string Email { get; set; } = string.Empty;
|
||||||
public string Time { get; set; } = "";
|
|
||||||
|
|
||||||
public void Parse(string data) {
|
public override bool Equals(object obj) {
|
||||||
var match = REG_FORMAT.Match(data);
|
if (obj == null || !(obj is User)) return false;
|
||||||
if (!match.Success) return;
|
|
||||||
|
|
||||||
var time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(int.Parse(match.Groups[3].Value));
|
var other = obj as User;
|
||||||
|
return Name == other.Name && Email == other.Email;
|
||||||
|
}
|
||||||
|
|
||||||
Name = match.Groups[1].Value;
|
public override int GetHashCode() {
|
||||||
Email = match.Groups[2].Value;
|
return base.GetHashCode();
|
||||||
Time = time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
|
}
|
||||||
|
|
||||||
|
public static User FindOrAdd(string name, string email) {
|
||||||
|
string key = $"{name}#&#{email}";
|
||||||
|
if (Caches.ContainsKey(key)) {
|
||||||
|
return Caches[key];
|
||||||
|
} else {
|
||||||
|
User user = new User() { Name = name, Email = email };
|
||||||
|
Caches.Add(key, user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Text="{Binding Author.Time}"
|
Text="{Binding AuthorTimeStr}"
|
||||||
Foreground="{DynamicResource Brush.FG2}"
|
Foreground="{DynamicResource Brush.FG2}"
|
||||||
Margin="4,0,0,0"
|
Margin="4,0,0,0"
|
||||||
HorizontalAlignment="Right"/>
|
HorizontalAlignment="Right"/>
|
||||||
|
|
|
@ -58,6 +58,7 @@ namespace SourceGit.Views {
|
||||||
var weekStart = today.AddSeconds(-(int)today.DayOfWeek * 3600 * 24 - today.Hour * 3600 - today.Minute * 60 - today.Second);
|
var weekStart = today.AddSeconds(-(int)today.DayOfWeek * 3600 * 24 - today.Hour * 3600 - today.Minute * 60 - today.Second);
|
||||||
var weekEnd = weekStart.AddDays(7);
|
var weekEnd = weekStart.AddDays(7);
|
||||||
var month = today.Month;
|
var month = today.Month;
|
||||||
|
var utcStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
|
||||||
|
|
||||||
var limits = $"--branches --remotes --since=\"{today.ToString("yyyy-01-01 00:00:00")}\"";
|
var limits = $"--branches --remotes --since=\"{today.ToString("yyyy-01-01 00:00:00")}\"";
|
||||||
var commits = new Commands.Commits(repo, limits).Result();
|
var commits = new Commands.Commits(repo, limits).Result();
|
||||||
|
@ -65,7 +66,7 @@ namespace SourceGit.Views {
|
||||||
var totalCommitsMonth = 0;
|
var totalCommitsMonth = 0;
|
||||||
var totalCommitsYear = commits.Count;
|
var totalCommitsYear = commits.Count;
|
||||||
foreach (var c in commits) {
|
foreach (var c in commits) {
|
||||||
var commitTime = DateTime.Parse(c.Committer.Time);
|
var commitTime = utcStart.AddSeconds(c.CommitterTime);
|
||||||
if (commitTime.CompareTo(weekStart) >= 0 && commitTime.CompareTo(weekEnd) < 0) {
|
if (commitTime.CompareTo(weekStart) >= 0 && commitTime.CompareTo(weekEnd) < 0) {
|
||||||
mapsWeek[(int)commitTime.DayOfWeek].Count++;
|
mapsWeek[(int)commitTime.DayOfWeek].Count++;
|
||||||
totalCommitsWeek++;
|
totalCommitsWeek++;
|
||||||
|
|
|
@ -49,20 +49,20 @@ namespace SourceGit.Views.Widgets {
|
||||||
avatarAuthor.FallbackLabel = commit.Author.Name;
|
avatarAuthor.FallbackLabel = commit.Author.Name;
|
||||||
txtAuthorName.Text = commit.Author.Name;
|
txtAuthorName.Text = commit.Author.Name;
|
||||||
txtAuthorEmail.Text = commit.Author.Email;
|
txtAuthorEmail.Text = commit.Author.Email;
|
||||||
txtAuthorTime.Text = commit.Author.Time;
|
txtAuthorTime.Text = commit.AuthorTimeStr;
|
||||||
|
|
||||||
avatarCommitter.Email = commit.Committer.Email;
|
if (commit.Committer.Equals(commit.Author) && commit.CommitterTime == commit.AuthorTime) {
|
||||||
avatarCommitter.FallbackLabel = commit.Committer.Name;
|
|
||||||
txtCommitterName.Text = commit.Committer.Name;
|
|
||||||
txtCommitterEmail.Text = commit.Committer.Email;
|
|
||||||
txtCommitterTime.Text = commit.Committer.Time;
|
|
||||||
|
|
||||||
if (commit.Committer.Email == commit.Author.Email && commit.Committer.Time == commit.Author.Time) {
|
|
||||||
avatarCommitter.Visibility = Visibility.Hidden;
|
avatarCommitter.Visibility = Visibility.Hidden;
|
||||||
committerInfoPanel.Visibility = Visibility.Hidden;
|
committerInfoPanel.Visibility = Visibility.Hidden;
|
||||||
} else {
|
} else {
|
||||||
avatarCommitter.Visibility = Visibility.Visible;
|
avatarCommitter.Visibility = Visibility.Visible;
|
||||||
committerInfoPanel.Visibility = Visibility.Visible;
|
committerInfoPanel.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
avatarCommitter.Email = commit.Committer.Email;
|
||||||
|
avatarCommitter.FallbackLabel = commit.Committer.Name;
|
||||||
|
txtCommitterName.Text = commit.Committer.Name;
|
||||||
|
txtCommitterEmail.Text = commit.Committer.Email;
|
||||||
|
txtCommitterTime.Text = commit.CommitterTimeStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commit.Parents.Count == 0) {
|
if (commit.Parents.Count == 0) {
|
||||||
|
|
|
@ -147,7 +147,7 @@
|
||||||
<DataGridTemplateColumn Width="140" IsReadOnly="True">
|
<DataGridTemplateColumn Width="140" IsReadOnly="True">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding Committer.Time}" HorizontalAlignment="Right" Margin="0,0,4,0"/>
|
<TextBlock Text="{Binding CommitterTimeStr}" HorizontalAlignment="Right" Margin="0,0,4,0"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</DataGridTemplateColumn>
|
</DataGridTemplateColumn>
|
||||||
|
|
|
@ -404,7 +404,7 @@ namespace SourceGit.Views.Widgets {
|
||||||
copyInfo.Click += (o, e) => {
|
copyInfo.Click += (o, e) => {
|
||||||
Clipboard.SetDataObject(string.Format(
|
Clipboard.SetDataObject(string.Format(
|
||||||
"SHA: {0}\nTITLE: {1}\nAUTHOR: {2} <{3}>\nTIME: {4}",
|
"SHA: {0}\nTITLE: {1}\nAUTHOR: {2} <{3}>\nTIME: {4}",
|
||||||
commit.SHA, commit.Subject, commit.Committer.Name, commit.Committer.Email, commit.Committer.Time), true);
|
commit.SHA, commit.Subject, commit.Committer.Name, commit.Committer.Email, commit.CommitterTime), true);
|
||||||
};
|
};
|
||||||
menu.Items.Add(copyInfo);
|
menu.Items.Add(copyInfo);
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,14 @@ namespace SourceGit.Views.Widgets {
|
||||||
avatarStart.FallbackLabel = start.Committer.Name;
|
avatarStart.FallbackLabel = start.Committer.Name;
|
||||||
avatarStart.ToolTip = start.Committer.Name;
|
avatarStart.ToolTip = start.Committer.Name;
|
||||||
txtStartSHA.Text = start.ShortSHA;
|
txtStartSHA.Text = start.ShortSHA;
|
||||||
txtStartTime.Text = start.Committer.Time;
|
txtStartTime.Text = start.CommitterTimeStr;
|
||||||
txtStartSubject.Text = start.Subject;
|
txtStartSubject.Text = start.Subject;
|
||||||
|
|
||||||
avatarEnd.Email = end.Committer.Email;
|
avatarEnd.Email = end.Committer.Email;
|
||||||
avatarEnd.FallbackLabel = end.Committer.Name;
|
avatarEnd.FallbackLabel = end.Committer.Name;
|
||||||
avatarEnd.ToolTip = end.Committer.Name;
|
avatarEnd.ToolTip = end.Committer.Name;
|
||||||
txtEndSHA.Text = end.ShortSHA;
|
txtEndSHA.Text = end.ShortSHA;
|
||||||
txtEndTime.Text = end.Committer.Time;
|
txtEndTime.Text = end.CommitterTimeStr;
|
||||||
txtEndSubject.Text = end.Subject;
|
txtEndSubject.Text = end.Subject;
|
||||||
|
|
||||||
Task.Run(() => {
|
Task.Run(() => {
|
||||||
|
|
Loading…
Reference in a new issue