Introduction
This expands on the original article on how to solve the merging problem of .resx files with an TFS implementation. But could be easily tweaked to work with ant diff merge application.
Using the code
In Visual Studio do the following: Tools -> Options ->Source Control -> Visual Studio Team foundation server -> Configure
user tools
Click Add and write:
Extension:
.resx
Operation:
Compare
Command :
C:\SortRESX.exe
Arguments:
compare %1 %2 %6 %7 %5
Click Ok and then Add and write:
Extension:
.resx
Operation:
Merge
Command :
C:\SortRESX.exe
Arguments:
merge %1 %2 %3 %4 %6 %7 %8
Code
The program uses the sort from the original article before launching the TFS merge utility.
class Program
{
private const string DiffMergeLocation =
@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\diffmerge.exe";
static void Main(string[] args)
{
if (String.Equals(args[0], "merge", StringComparison.CurrentCultureIgnoreCase))
{
HandleMerge(args);
}
else if (String.Equals(args[0], "compare", StringComparison.CurrentCultureIgnoreCase))
{
HandleCompare(args);
}
else
{
throw new NotSupportedException("Unknown mode, use either merge or compare");
}
}
private static void HandleCompare(string[] args)
{
var theirsSource = args[1];
var theirs = Path.GetTempFileName();
var yoursSource = args[2];
var yours = Path.GetTempFileName();
try
{
var doc = XDocument.Load(theirsSource);
var sortedDoc = SortDataByName(doc);
sortedDoc.Save(theirs);
doc = XDocument.Load(yoursSource);
sortedDoc = SortDataByName(doc);
sortedDoc.Save(yours);
var theirLabel = args[3];
var yoursLabel = args[4];
var start = new ProcessStartInfo
{
Arguments = string.Format("\"{0}\" \"{1}\" \"{2}\"
\"{3}\" /ignorespace", theirs, yours, theirLabel, yoursLabel),
FileName = DiffMergeLocation,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
using (var proc = Process.Start(start))
{
proc.WaitForExit();
}
}
finally
{
File.Delete(theirs);
File.Delete(yours);
}
}
private static void HandleMerge(string[] args)
{
var theirsSource = args[1];
var theirs = Path.GetTempFileName();
var yoursSource = args[2];
var yours = Path.GetTempFileName();
var baseFileSource = args[3];
var baseFile = Path.GetTempFileName();
var merged = args[4];
var theirLabel = args[5];
var yoursLabel = args[6];
try
{
var doc = XDocument.Load(theirsSource);
var sortedDoc = SortDataByName(doc);
sortedDoc.Save(theirs);
doc = XDocument.Load(yoursSource);
sortedDoc = SortDataByName(doc);
sortedDoc.Save(yours);
doc = XDocument.Load(baseFileSource);
sortedDoc = SortDataByName(doc);
sortedDoc.Save(baseFile);
var start = new ProcessStartInfo
{
Arguments = string.Format("/merge \"{0}\" \"{1}\" \"{2}\"
\"{3}\" \"{4}\" \"{5}\"", theirs, yours, baseFile, merged, theirLabel, yoursLabel),
FileName = DiffMergeLocation,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
using (var proc = Process.Start(start))
{
proc.WaitForExit();
}
}
finally
{
File.Delete(theirs);
File.Delete(yours);
File.Delete(baseFile);
}
}
private static XDocument SortDataByName(XDocument resx)
{
return new XDocument(
new XElement(resx.Root.Name,
resx.Root.Nodes().Where(comment => comment.NodeType == XmlNodeType.Comment),
resx.Root.Elements().Where(schema => schema.Name.LocalName == "schema"),
resx.Root.Elements("resheader").OrderBy(resheader => (string) resheader.Attribute("name")),
resx.Root.Elements("assembly").OrderBy(assembly => (string) assembly.Attribute("name")),
resx.Root.Elements("metadata").OrderBy(metadata => (string) metadata.Attribute("name")),
resx.Root.Elements("data").OrderBy(data => (string) data.Attribute("name"))
)
);
}
}