在DotNetNuke,我们发布了许多不同的软件包,每个版本包括社区和我们的专业和企业客户的源软件包。在内部,我们有一个覆盖的解决方案文件,它包含了我们每天处理的所有项目,这个解决方案文件还包含了所有的单元测试。当我们发布源包时,我们发布了包含或不包含单元测试的解决方案文件,以及一个VS2008格式的sln文件和一堆针对专业和企业客户的变体,这实际上是15个不同的解决方案文件。一旦包被创建,就会有一个自动的构建,它会编译每个包,以确保我们设置了所有正确的项目和引用。
此外,由于我们将这些解决方案分发给无法访问TFS设置的用户,因此TFS绑定也被删除了。
所有这些不同的sln文件都是从一个解决方案文件创建的,因此所有内部开发人员只需处理一个sln文件。
好了,就这样。问题是如何从解决方案文件中删除各种项目,使其在Visual Studio中打开,也可以从CCNet中构建。简单地删除定义项目的文本是不够的,因为这会使嵌套项目部分混乱不堪。即使Visual Studio可以打开文件,MSBuild也会死得很惨,因此无法进行自动编译。
我在下面写的自定义任务以这样一种方式处理sln文件,即VS和MSBuild都可以解析文件并做他们需要做的事情。
要使用该任务,请将以下内容添加到MSBuild文件中
<GenerateSolutionFiles
OriginalFile="$ (PackagingFolder) \ DotNetNuke_Enterprise_UnitTests.sln"
CreatedFile="$ (PackagingFolder) \ DotNetNuke_Community_UnitTests_Source.sln"
projectname="@ (AllSolutionsProjects);@ (EEProjects);@ (PEProjects);
@ (EETestProjects);DotNetNuke.Professional.HtmlPro"
更换="@ (CEReplacements)"
RemoveTfsBindings="真正的"/>
你在ProjectNames中指定要删除的项目列表,你也可以在指定要替换的测试和替换文本的地方做简单的文本替换:
<ItemGroup><CEReplacements包括="DotNetNuke_Enterprise"/><CEReplacements包括="DotNetNuke_Community"/>ItemGroup>
我们用它来管理网站名称。
Task的代码如下所示。享受。
使用系统;使用来;使用Microsoft.Build.Utilities;名称空间DotNetNuke.MSBuild.Tasks {使用先;公共类GenerateSolutionFiles:任务{公共字符串OriginalFile {得到;集;}公共字符串CreatedFile {得到;集;}公共字符串[] ProjectNames {得到;集;}公共字符串[]替换{得到;集;}公共保龄球RemoveTfsBindings {得到;集;}公共覆盖保龄球Execute () {如果(projectname = =零) {返回真正的;}试一试{vartr =新StreamReader (OriginalFile真正的);tr.Peek ();varfileEncoding = tr.CurrentEncoding;varcontent = tr.ReadToEnd();tr.Close ();varglobalIndex = content。IndexOf (“全球”);varglobalSection =内容。Substring (globalIndex内容。长度- globalIndex);varglobalSections = globalSection。分(新字符串[] {”GlobalSection(“},
StringSplitOptions.RemoveEmptyEntries);varprojectsSection =内容。Substring (0, globalIndex);projectsSection = projectsSection。删除(0,projectsSection。IndexOf (”项目(“));varprojects = projectsSection。分(新字符串[] {”项目(“}, StringSplitOptions.RemoveEmptyEntries);varnestedProjectsSection =字符串空虚;如果(RemoveTfsBindings) {//删除TFS部分。content = globalSections。其中(glb =>)包含(“TeamFoundationVersionControl”)).
Aggregate(content, (current, glb) => current。替换(字符串.Concat (”GlobalSection(“, glb),字符串空虚));Content =内容。替换(“傻科”,字符串空虚);}foreach(varglb在globalSections。其中(glb =>)包含(“NestedProjects”{nestedProjectsSection =字符串.Concat (”GlobalSection(“、glb);}varnestedProjects = nestedProjectsSection。分(新字符[] {' \ r ',' \ n ',' \ t ',' \ t '},
StringSplitOptions.RemoveEmptyEntries) .ToList ();foreach(varprojectName在projectname) {foreach(var项目在项目){如果(项目。包含(“ProjectSection”))继续;varprojectEntry =项目。替换(“EndProject”,字符串空虚).Replace (“\”“,字符串空虚)。
替换(”“,字符串空虚).Replace (“\ r”,字符串空虚).Replace (“\ n”,字符串空虚);varindexfirstquals = projectEntry。IndexOf (“=”) + 1;projectEntry = projectEntry。删除(0,indexFirstEquals);varprojectNameGuid = projectEntry。分(”、“);如果(projectNameGuid[0] == projectName) {content = content。替换(字符串.Concat (”项目(“、项目)字符串空虚);varnestedProject = nestedProjects。FirstOrDefault(l => l.s startswith (projectNameGuid[2]));如果(nestedProject ! =默认的(字符串{nestedProjects。RemoveAll(l => . startswith (projectNameGuid[2]));} } } }varfilteredNestedProjects =字符串.Concat (字符串. join (“t \ r \ n \ t \”, nestedProjects。
ToArray ()),“t \ r \ n \”).替换(“\ tEndGlobalSection”,“EndGlobalSection”);content = content. replace (nestedProjectsSection,filteredNestedProjects);如果(替换! =零) {为(var索引= 0;index <=替换项。长度- 1;Index = Index + 2) {content = content。替换(更换[index], Replacements[index + 1]); } }如果(CreatedFile。包含(“_VS2008”)) {//将副本转换为VS2008Content =内容。替换(# Visual Studio 2010,# Visual Studio 2008);Content =内容。替换(Microsoft Visual Studio解决方案文件,格式版本11.00,
Microsoft Visual Studio解决方案文件,格式版本10.00);Content =内容。替换(“vbproj”,“VS2008.vbproj”).替换(“csproj”,“VS2008.csproj”);}varnewSolutionFile =新StreamWriter (CreatedFile假, fileEncoding);newSolutionFile.WriteLine(内容);newSolutionFile.Close ();}抓(ex例外){var文件=新StreamWriter (“F: \ \ \ \ log.txt构建”);file.WriteLine (ex.StackTrace);file.Close ();返回假;}返回真正的;}}