在团队开发环境中,资源文件(.resx)的合并是一个常见的问题。Visual StudioTeam Foundation Server (TFS) 提供了版本控制功能,但并不直接支持.resx文件的合并。本文将介绍如何通过配置Visual Studio和编写辅助程序来解决这一问题。
首先,需要在Visual Studio中配置源代码管理工具,以便能够比较和合并.resx文件。以下是详细步骤:
这样,就可以在Visual Studio中使用“比较”和“合并”功能来处理.resx文件了。
为了实现.resx文件的比较和合并,需要编写一个辅助程序。以下是一个使用C#编写的示例程序:
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 options = args.Length >= 6 ? "\"" + args[5] + "\"" : "";
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"))
)
);
}
}