Files
git-tfs/GitTfs/Core/GitChangeInfo.cs
T
2014-02-06 15:33:11 +04:00

147 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using StructureMap;
using FileMode = LibGit2Sharp.Mode;
namespace Sep.Git.Tfs.Core
{
public class GitChangeInfo
{
public struct ChangeType
{
public const string ADD = "A";
public const string COPY = "C";
public const string MODIFY = "M";
public const string DELETE = "D";
public const string RENAMEEDIT = "R";
//public const string TYPECHANGE="T";
//public const string UNMERGED="U";
//public const string UNKNOWN="X";
}
public static readonly Regex DiffTreePattern = new Regex(
// See http://www.kernel.org/pub/software/scm/git/docs/git-diff-tree.html#_raw_output_format
"^:" +
"(?<srcmode>[0-7]{6})" +
" " +
"(?<dstmode>[0-7]{6})" +
" " +
"(?<srcsha1>[0-9a-f]{40})" +
" " +
"(?<dstsha1>[0-9a-f]{40})" +
" " +
"(?<status>.)" + "(?<score>[0-9]*)" +
"\\000" +
"(?<srcpath>[^\\000]+)" +
"(\\000" +
"(?<dstpath>[^\\000]+)" +
")?" +
"\\000$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static IEnumerable<GitChangeInfo> GetChangedFiles(TextReader reader)
{
string line;
while (null != (line = GetDiffTreeLine(reader)))
{
var change = GitChangeInfo.Parse(line);
if (FileMode.GitLink == change.NewMode)
continue;
yield return change;
}
}
private static string GetDiffTreeLine(TextReader reader)
{
var sb = new StringBuilder();
char[] block = new char[98];
var bytesRead = reader.ReadBlock(block, 0, 98);
if (bytesRead == 0)
{
return null;
}
else if (bytesRead != 98)
{
throw new Exception("Invalid input.");
}
var nullBytesLeft = 2;
if (block[97] == 'C' || block[97] == 'R')
{
nullBytesLeft = 3;
}
sb.Append(block);
while (nullBytesLeft > 0)
{
var currentByte = reader.Read();
if (currentByte == -1)
{
throw new Exception("Invalid input.");
}
else if (currentByte == 0)
{
nullBytesLeft--;
}
sb.Append((char)currentByte);
}
return sb.ToString();
}
public static GitChangeInfo Parse(string diffTreeLine)
{
var match = DiffTreePattern.Match(diffTreeLine);
if (!match.Success)
{
throw new Exception("Invalid input.");
}
Debug(diffTreeLine, match, DiffTreePattern);
return new GitChangeInfo(match);
}
private static void Debug(string input, Match match, Regex regex)
{
Trace.WriteLine("Regex: " + regex);
Trace.WriteLine("Input: " + input);
foreach(var groupName in regex.GetGroupNames())
{
Trace.WriteLine(" -> " + groupName + ": >>" + match.Groups[groupName].Value + "<<");
}
}
private readonly Match _match;
private GitChangeInfo(Match match)
{
_match = match;
}
public LibGit2Sharp.Mode NewMode { get { return _match.Groups["dstmode"].Value.ToFileMode(); } }
public string Status { get { return _match.Groups["status"].Value; } }
public string oldMode { get { return _match.Groups["srcmode"].Value; } }
public string newMode { get { return _match.Groups["dstmode"].Value; } }
public string oldSha { get { return _match.Groups["srcsha1"].Value; } }
public string newSha { get { return _match.Groups["dstsha1"].Value; } }
public string path { get { return _match.Groups["srcpath"].Value; } }
public string pathTo { get { return _match.Groups["dstpath"].Value; } }
public string score { get { return _match.Groups["score"].Value; } }
public IGitChangedFile ToGitChangedFile(ExplicitArgsExpression builder)
{
return builder.With(this).GetInstance<IGitChangedFile>(Status);
}
}
}