git repo: Simplify log parsing logic
This commit is contained in:
parent
8eb4fdf28f
commit
dd97d564be
|
@ -491,7 +491,7 @@ namespace Sparkles.Git {
|
||||||
|
|
||||||
foreach (string line in lines) {
|
foreach (string line in lines) {
|
||||||
string conflicting_file_path = line.Substring (3);
|
string conflicting_file_path = line.Substring (3);
|
||||||
conflicting_file_path = EnsureSpecialCharacters (conflicting_file_path);
|
conflicting_file_path = EnsureSpecialChars (conflicting_file_path);
|
||||||
conflicting_file_path = conflicting_file_path.Trim ("\"".ToCharArray ());
|
conflicting_file_path = conflicting_file_path.Trim ("\"".ToCharArray ());
|
||||||
|
|
||||||
// Remove possible rename indicators
|
// Remove possible rename indicators
|
||||||
|
@ -689,90 +689,31 @@ namespace Sparkles.Git {
|
||||||
|
|
||||||
if (path == null && string.IsNullOrWhiteSpace (output)) {
|
if (path == null && string.IsNullOrWhiteSpace (output)) {
|
||||||
git = new GitCommand (LocalPath, "--no-pager log -n 75 " + log_args);
|
git = new GitCommand (LocalPath, "--no-pager log -n 75 " + log_args);
|
||||||
|
|
||||||
output = git.StartAndReadStandardOutput ();
|
output = git.StartAndReadStandardOutput ();
|
||||||
}
|
}
|
||||||
|
|
||||||
string [] lines = output.Split ("\n".ToCharArray ());
|
|
||||||
List<string> entries = new List <string> ();
|
|
||||||
|
|
||||||
// Split up commit entries
|
// Offset the output so our log_regex can be simpler
|
||||||
int line_number = 0;
|
string commit_sep = "commit ";
|
||||||
bool first_pass = true;
|
|
||||||
string entry = "", last_entry = "";
|
|
||||||
foreach (string line in lines) {
|
|
||||||
if (line.StartsWith ("commit") && !first_pass) {
|
|
||||||
entries.Add (entry);
|
|
||||||
entry = "";
|
|
||||||
line_number = 0;
|
|
||||||
|
|
||||||
} else {
|
if (output.StartsWith (commit_sep))
|
||||||
first_pass = false;
|
output = output.Substring (commit_sep.Length) + "\n\n" + commit_sep;
|
||||||
}
|
|
||||||
|
|
||||||
// Only parse first 250 files to prevent memory issues
|
|
||||||
if (line_number < 250) {
|
|
||||||
entry += line + "\n";
|
|
||||||
line_number++;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_entry = entry;
|
MatchCollection matches = this.log_regex.Matches (output);
|
||||||
}
|
|
||||||
|
|
||||||
entries.Add (last_entry);
|
foreach (Match match in matches) {
|
||||||
|
ChangeSet change_set = ParseChangeSet (match);
|
||||||
|
|
||||||
// Parse commit entries
|
if (change_set == null)
|
||||||
foreach (string log_entry in entries) {
|
|
||||||
Match match = this.log_regex.Match (log_entry);
|
|
||||||
|
|
||||||
if (!match.Success) {
|
|
||||||
match = this.merge_regex.Match (log_entry);
|
|
||||||
|
|
||||||
if (!match.Success)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChangeSet change_set = new ChangeSet ();
|
|
||||||
|
|
||||||
change_set.Folder = new SparkleFolder (Name);
|
|
||||||
change_set.Revision = match.Groups [1].Value;
|
|
||||||
change_set.User = new User (match.Groups [2].Value, match.Groups [3].Value);
|
|
||||||
|
|
||||||
if (change_set.User.Name == "SparkleShare")
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
change_set.RemoteUrl = RemoteUrl;
|
int count = 0;
|
||||||
|
foreach (string line in match.Groups ["files"].Value.Split ("\n".ToCharArray ())) {
|
||||||
|
if (count++ == 256)
|
||||||
|
break;
|
||||||
|
|
||||||
if (StorageType == StorageType.Encrypted) {
|
Change change = ParseChange (line);
|
||||||
string password_file_path = Path.Combine (LocalPath, ".git", "info", "encryption_password");
|
|
||||||
string password = File.ReadAllText (password_file_path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
change_set.User = new User (
|
|
||||||
change_set.User.Name.AESDecrypt (password),
|
|
||||||
change_set.User.Email.AESDecrypt (password));
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
Console.WriteLine (e.StackTrace);
|
|
||||||
change_set.User = new User (match.Groups [2].Value, match.Groups [3].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
change_set.Timestamp = new DateTime (int.Parse (match.Groups [4].Value),
|
|
||||||
int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value),
|
|
||||||
int.Parse (match.Groups [7].Value), int.Parse (match.Groups [8].Value),
|
|
||||||
int.Parse (match.Groups [9].Value));
|
|
||||||
|
|
||||||
string time_zone = match.Groups [10].Value;
|
|
||||||
int our_offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Hours;
|
|
||||||
int their_offset = int.Parse (time_zone.Substring (0, 3));
|
|
||||||
change_set.Timestamp = change_set.Timestamp.AddHours (their_offset * -1);
|
|
||||||
change_set.Timestamp = change_set.Timestamp.AddHours (our_offset);
|
|
||||||
|
|
||||||
string [] entry_lines = log_entry.Split ("\n".ToCharArray ());
|
|
||||||
|
|
||||||
foreach (string entry_line in entry_lines) {
|
|
||||||
Change change = ParseFileChange (entry_line);
|
|
||||||
|
|
||||||
if (change == null)
|
if (change == null)
|
||||||
continue;
|
continue;
|
||||||
|
@ -781,21 +722,22 @@ namespace Sparkles.Git {
|
||||||
change_set.Changes.Add (change);
|
change_set.Changes.Add (change);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group commits per user, per day
|
|
||||||
if (change_sets.Count > 0 && path == null) {
|
if (path == null && change_sets.Count > 0) {
|
||||||
ChangeSet last_change_set = change_sets [change_sets.Count - 1];
|
ChangeSet last_change_set = change_sets [change_sets.Count - 1];
|
||||||
|
|
||||||
if (change_set.Timestamp.Year == last_change_set.Timestamp.Year &&
|
// If a change set set already exists for this user and day, group into that one
|
||||||
|
if (change_set.Timestamp.Year == last_change_set.Timestamp.Year &&
|
||||||
change_set.Timestamp.Month == last_change_set.Timestamp.Month &&
|
change_set.Timestamp.Month == last_change_set.Timestamp.Month &&
|
||||||
change_set.Timestamp.Day == last_change_set.Timestamp.Day &&
|
change_set.Timestamp.Day == last_change_set.Timestamp.Day &&
|
||||||
change_set.User.Name.Equals (last_change_set.User.Name)) {
|
change_set.User.Name.Equals (last_change_set.User.Name)) {
|
||||||
|
|
||||||
last_change_set.Changes.AddRange (change_set.Changes);
|
last_change_set.Changes.AddRange (change_set.Changes);
|
||||||
|
|
||||||
if (DateTime.Compare (last_change_set.Timestamp, change_set.Timestamp) < 1) {
|
if (DateTime.Compare (last_change_set.Timestamp, change_set.Timestamp) < 1) {
|
||||||
last_change_set.FirstTimestamp = last_change_set.Timestamp;
|
last_change_set.FirstTimestamp = last_change_set.Timestamp;
|
||||||
last_change_set.Timestamp = change_set.Timestamp;
|
last_change_set.Timestamp = change_set.Timestamp;
|
||||||
last_change_set.Revision = change_set.Revision;
|
last_change_set.Revision = change_set.Revision;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
last_change_set.FirstTimestamp = change_set.Timestamp;
|
last_change_set.FirstTimestamp = change_set.Timestamp;
|
||||||
|
@ -805,23 +747,22 @@ namespace Sparkles.Git {
|
||||||
change_sets.Add (change_set);
|
change_sets.Add (change_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else if (path != null) {
|
||||||
// Don't show removals or moves in the revision list of a file
|
// Don't show removals or moves in the history list of a file
|
||||||
if (path != null) {
|
var changes = new Change [change_set.Changes.Count];
|
||||||
List<Change> changes_to_skip = new List<Change> ();
|
change_set.Changes.CopyTo (changes);
|
||||||
|
|
||||||
foreach (Change change in change_set.Changes) {
|
foreach (Change change in changes) {
|
||||||
if ((change.Type == ChangeType.Deleted || change.Type == ChangeType.Moved)
|
if (!change.Path.Equals (path))
|
||||||
&& change.Path.Equals (path)) {
|
continue;
|
||||||
|
|
||||||
changes_to_skip.Add (change);
|
if (change.Type == ChangeType.Deleted || change.Type == ChangeType.Moved)
|
||||||
}
|
change_set.Changes.Remove (change);
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Change change_to_skip in changes_to_skip)
|
|
||||||
change_set.Changes.Remove (change_to_skip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
change_sets.Add (change_set);
|
||||||
|
|
||||||
|
} else {
|
||||||
change_sets.Add (change_set);
|
change_sets.Add (change_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -830,7 +771,51 @@ namespace Sparkles.Git {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Change ParseFileChange (string line)
|
ChangeSet ParseChangeSet (Match match)
|
||||||
|
{
|
||||||
|
ChangeSet change_set = new ChangeSet ();
|
||||||
|
|
||||||
|
// Set the name and email
|
||||||
|
if (match.Groups ["name"].Value == "SparkleShare")
|
||||||
|
return null;
|
||||||
|
|
||||||
|
change_set.Folder = new SparkleFolder (Name);
|
||||||
|
change_set.Revision = match.Groups ["commit"].Value;
|
||||||
|
change_set.User = new User (match.Groups ["name"].Value, match.Groups ["email"].Value);
|
||||||
|
change_set.RemoteUrl = RemoteUrl;
|
||||||
|
|
||||||
|
if (StorageType == StorageType.Encrypted) {
|
||||||
|
string password_file_path = Path.Combine (LocalPath, ".git", "info", "encryption_password");
|
||||||
|
string password = File.ReadAllText (password_file_path);
|
||||||
|
|
||||||
|
try {
|
||||||
|
change_set.User = new User (
|
||||||
|
change_set.User.Name.AESDecrypt (password),
|
||||||
|
change_set.User.Email.AESDecrypt (password));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Console.WriteLine (e.StackTrace);
|
||||||
|
change_set.User = new User (match.Groups ["name"].Value, match.Groups ["email"].Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the right date and time by offsetting the timezones
|
||||||
|
change_set.Timestamp = new DateTime (
|
||||||
|
int.Parse (match.Groups ["year"].Value), int.Parse (match.Groups ["month"].Value), int.Parse (match.Groups ["day"].Value),
|
||||||
|
int.Parse (match.Groups ["hour"].Value), int.Parse (match.Groups ["minute"].Value), int.Parse (match.Groups ["second"].Value));
|
||||||
|
|
||||||
|
string time_zone = match.Groups ["timezone"].Value;
|
||||||
|
int our_offset = TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.Now).Hours;
|
||||||
|
int their_offset = int.Parse (time_zone.Substring (0, 3));
|
||||||
|
|
||||||
|
change_set.Timestamp = change_set.Timestamp.AddHours (their_offset * -1);
|
||||||
|
change_set.Timestamp = change_set.Timestamp.AddHours (our_offset);
|
||||||
|
|
||||||
|
return change_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Change ParseChange (string line)
|
||||||
{
|
{
|
||||||
// Skip lines containing backspace characters or the .sparkleshare file
|
// Skip lines containing backspace characters or the .sparkleshare file
|
||||||
if (line.Contains ("\\177") || line.Contains (".sparkleshare"))
|
if (line.Contains ("\\177") || line.Contains (".sparkleshare"))
|
||||||
|
@ -846,8 +831,8 @@ namespace Sparkles.Git {
|
||||||
}
|
}
|
||||||
|
|
||||||
Change change = new Change () { Type = ChangeType.Added };
|
Change change = new Change () { Type = ChangeType.Added };
|
||||||
|
|
||||||
string file_path;
|
string file_path;
|
||||||
|
|
||||||
int first_tab_pos = line.IndexOf ('\t');
|
int first_tab_pos = line.IndexOf ('\t');
|
||||||
int last_tab_pos = line.LastIndexOf ('\t');
|
int last_tab_pos = line.LastIndexOf ('\t');
|
||||||
|
|
||||||
|
@ -878,21 +863,23 @@ namespace Sparkles.Git {
|
||||||
file_path = file_path.Replace ("\\\"", "\"");
|
file_path = file_path.Replace ("\\\"", "\"");
|
||||||
change.Path = file_path;
|
change.Path = file_path;
|
||||||
|
|
||||||
|
string empty_name = ".empty";
|
||||||
|
|
||||||
// Handle .empty files as if they were folders
|
// Handle .empty files as if they were folders
|
||||||
if (change.Path.EndsWith (".empty")) {
|
if (change.Path.EndsWith (empty_name)) {
|
||||||
change.Path = change.Path.Substring (0, change.Path.Length - ".empty".Length);
|
change.Path = change.Path.Substring (0, change.Path.Length - empty_name.Length);
|
||||||
|
|
||||||
if (change.Type == ChangeType.Moved)
|
if (change.Type == ChangeType.Moved)
|
||||||
change.MovedToPath = change.MovedToPath.Substring (0, change.MovedToPath.Length - ".empty".Length);
|
change.MovedToPath = change.MovedToPath.Substring (0, change.MovedToPath.Length - empty_name.Length);
|
||||||
|
|
||||||
change.IsFolder = true;
|
change.IsFolder = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
change.Path = EnsureSpecialCharacters (change.Path);
|
change.Path = EnsureSpecialChars (change.Path);
|
||||||
|
|
||||||
if (change.Type == ChangeType.Moved)
|
if (change.Type == ChangeType.Moved)
|
||||||
change.MovedToPath = EnsureSpecialCharacters (change.MovedToPath);
|
change.MovedToPath = EnsureSpecialChars (change.MovedToPath);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger.LogInfo ("Local", string.Format ("Error parsing line due to special character: '{0}'", line), e);
|
Logger.LogInfo ("Local", string.Format ("Error parsing line due to special character: '{0}'", line), e);
|
||||||
|
@ -903,7 +890,7 @@ namespace Sparkles.Git {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string EnsureSpecialCharacters (string path)
|
string EnsureSpecialChars (string path)
|
||||||
{
|
{
|
||||||
// The path is quoted if it contains special characters
|
// The path is quoted if it contains special characters
|
||||||
if (path.StartsWith ("\""))
|
if (path.StartsWith ("\""))
|
||||||
|
@ -1014,13 +1001,13 @@ namespace Sparkles.Git {
|
||||||
|
|
||||||
change = new Change () {
|
change = new Change () {
|
||||||
Type = ChangeType.Moved,
|
Type = ChangeType.Moved,
|
||||||
Path = EnsureSpecialCharacters (path),
|
Path = EnsureSpecialChars (path),
|
||||||
MovedToPath = EnsureSpecialCharacters (moved_to_path)
|
MovedToPath = EnsureSpecialChars (moved_to_path)
|
||||||
};
|
};
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
string path = line.Substring (2).Trim ("\" ".ToCharArray ());
|
string path = line.Substring (2).Trim ("\" ".ToCharArray ());
|
||||||
change = new Change () { Path = EnsureSpecialCharacters (path) };
|
change = new Change () { Path = EnsureSpecialChars (path) };
|
||||||
change.Type = ChangeType.Added;
|
change.Type = ChangeType.Added;
|
||||||
|
|
||||||
if (line.StartsWith ("M")) {
|
if (line.StartsWith ("M")) {
|
||||||
|
@ -1048,8 +1035,8 @@ namespace Sparkles.Git {
|
||||||
|
|
||||||
foreach (Change change in ParseStatus ()) {
|
foreach (Change change in ParseStatus ()) {
|
||||||
if (change.Type == ChangeType.Moved) {
|
if (change.Type == ChangeType.Moved) {
|
||||||
message += "< ‘" + EnsureSpecialCharacters (change.Path) + "’\n";
|
message += "< ‘" + EnsureSpecialChars (change.Path) + "’\n";
|
||||||
message += "> ‘" + EnsureSpecialCharacters (change.MovedToPath) + "’\n";
|
message += "> ‘" + EnsureSpecialChars (change.MovedToPath) + "’\n";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (change.Type) {
|
switch (change.Type) {
|
||||||
|
@ -1122,17 +1109,13 @@ namespace Sparkles.Git {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Regex log_regex = new Regex (@"commit ([a-f0-9]{40})*\n" +
|
Regex log_regex = new Regex (
|
||||||
"Author: (.+) <(.+)>\n" +
|
"(?'commit'[a-f0-9]{40})\n" +
|
||||||
"Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " +
|
"Author: (?'name'.+?) <(?'email'.+?)>\n" +
|
||||||
"([0-9]{2}):([0-9]{2}):([0-9]{2}) (.[0-9]{4})\n" +
|
"Date: (?'year'[0-9]{4})-(?'month'[0-9]{2})-(?'day'[0-9]{2}) (?'hour'[0-9]{2}):(?'minute'[0-9]{2}):(?'second'[0-9]{2}) (?'timezone'.[0-9]{4})\n" +
|
||||||
"*", RegexOptions.Compiled);
|
"\n" +
|
||||||
|
" (?'message'.+?)\n" +
|
||||||
Regex merge_regex = new Regex (@"commit ([a-f0-9]{40})\n" +
|
"\n" +
|
||||||
"Merge: [a-f0-9]{7} [a-f0-9]{7}\n" +
|
"(?'files'.+?)\n\ncommit ", RegexOptions.Singleline | RegexOptions.Compiled);
|
||||||
"Author: (.+) <(.+)>\n" +
|
|
||||||
"Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " +
|
|
||||||
"([0-9]{2}):([0-9]{2}):([0-9]{2}) (.[0-9]{4})\n" +
|
|
||||||
"*", RegexOptions.Compiled);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue