using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace SourceGit.Git {
///
/// Git commit information.
///
public class Commit {
private static readonly string GPGSIG_START = "gpgsig -----BEGIN PGP SIGNATURE-----";
private static readonly string GPGSIG_END = " -----END PGP SIGNATURE-----";
///
/// Object in commit.
///
public class Object {
public enum Type {
Tag,
Blob,
Tree,
Commit,
}
public string Path { get; set; }
public Type Kind { get; set; }
public string SHA { get; set; }
}
///
/// SHA
///
public string SHA { get; set; }
///
/// Short SHA.
///
public string ShortSHA => SHA.Substring(0, 8);
///
/// Parent commit SHAs.
///
public List Parents { get; set; } = new List();
///
/// Author
///
public User Author { get; set; } = new User();
///
/// Committer.
///
public User Committer { get; set; } = new User();
///
/// Subject
///
public string Subject { get; set; } = "";
///
/// Extra message.
///
public string Message { get; set; } = "";
///
/// HEAD commit?
///
public bool IsHEAD { get; set; } = false;
///
/// Merged in current branch?
///
public bool IsMerged { get; set; } = false;
///
/// X offset in graph
///
public double GraphOffset { get; set; } = 0;
///
/// Has decorators.
///
public bool HasDecorators => Decorators.Count > 0;
///
/// Decorators.
///
public List Decorators { get; set; } = new List();
///
/// Read commits.
///
/// Repository
/// Limitations
/// Parsed commits.
public static List Load(Repository repo, string limit) {
List commits = new List();
Commit current = null;
bool bSkippingGpgsig = false;
bool findHead = false;
repo.RunCommand("log --date-order --decorate=full --pretty=raw " + limit, line => {
if (bSkippingGpgsig) {
if (line.StartsWith(GPGSIG_END, StringComparison.Ordinal)) bSkippingGpgsig = false;
return;
} else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal)) {
bSkippingGpgsig = true;
return;
}
if (line.StartsWith("commit ", StringComparison.Ordinal)) {
if (current != null) {
current.Message = current.Message.TrimEnd();
commits.Add(current);
}
current = new Commit();
ParseSHA(current, line.Substring("commit ".Length));
if (!findHead) findHead = current.IsHEAD;
return;
}
if (current == null) return;
if (line.StartsWith("tree ", StringComparison.Ordinal)) {
return;
} else if (line.StartsWith("parent ", StringComparison.Ordinal)) {
current.Parents.Add(line.Substring("parent ".Length));
} else if (line.StartsWith("author ", StringComparison.Ordinal)) {
current.Author.Parse(line);
} else if (line.StartsWith("committer ", StringComparison.Ordinal)) {
current.Committer.Parse(line);
} else if (string.IsNullOrEmpty(current.Subject)) {
current.Subject = line.Trim();
} else {
current.Message += (line.Trim() + "\n");
}
});
if (current != null) {
current.Message = current.Message.TrimEnd();
commits.Add(current);
}
if (!findHead && commits.Count > 0) {
var startInfo = new ProcessStartInfo();
startInfo.FileName = Preference.Instance.GitExecutable;
startInfo.Arguments = $"merge-base --is-ancestor {commits[0].SHA} HEAD";
startInfo.WorkingDirectory = repo.Path;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = false;
startInfo.RedirectStandardError = false;
var proc = new Process() { StartInfo = startInfo };
proc.Start();
proc.WaitForExit();
commits[0].IsMerged = proc.ExitCode == 0;
proc.Close();
}
return commits;
}
///
/// Get changed file list.
///
///
///
public List GetChanges(Repository repo) {
var changes = new List();
var regex = new Regex(@"^[MADRC]\d*\s*.*$");
var errs = repo.RunCommand($"show --name-status {SHA}", line => {
if (!regex.IsMatch(line)) return;
var change = Change.Parse(line, true);
if (change != null) changes.Add(change);
});
if (errs != null) App.RaiseError(errs);
return changes;
}
///
/// Get revision files.
///
///
///
public List