我想我会更新我之前的答案,因为我花了很多时间和精力来创建自己的解决方法来解决这个问题。解决方法比简单地解决问题要全面一些,但我试图既消除问题又使自己免受未来此类冲击的影响。
MSBuild 已从使用解决方案、配置或其他方式降级。MSBuild 只是被要求单独编译项目。发生这种情况的顺序由 Powershell 脚本计算,该脚本解析我们的解决方案和项目,以制定出最佳的即时构建执行计划。
关键(我认为您可能会发现有帮助)是以下片段:
确定我的解决方案
我在我的平台上有一个所有解决方案的列表,并且我基本上迭代了其中的每一个。
$buildPlan = (
@{
solutions = (
@{
name = "DataStorage"
namespace = "Platform.Databases"
},
@{
name = "CoreFramework"
},
@{
namespace = "Platform.Server"
name = "Application1"
},
@{
namespace = "Platform.Server"
name = "Application2"
},
@{
namespace = "Platform.Client"
name = "Application1"
}
)
})
我有一些逻辑可以帮助将其转化为实际的物理路径,但它非常符合我们的需求,所以我不会在这里列出。可以说,从这个列表中,我可以找到我需要解析的 .sln 文件。
解析项目的解决方案文件
对于每个解决方案,我都会阅读 .sln 文件并尝试提取其中包含的所有项目,我将在以后需要构建这些项目。
所以首先,确定我的所有项目
$solutionContent = Get-Content $solutionFile
$buildConfigurations += Get-Content $solutionFile | Select-String "{([a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})}\.(Release.*)\|Any CPU\.Build" | % {
New-Object PSObject -Property @{
Name = $_.matches[0].groups[3].value.replace("Release ","");
Guid = $_.matches[0].groups[1].value
}
} | Sort-Object Name,Guid -unique
然后将其翻译成一个很好的项目列表,我可以稍后对其进行迭代。
$projectDefinitions = $solutionContent |
Select-String 'Project\(' |
ForEach-Object {
$projectParts = $_ -Split '[,=]' | ForEach-Object { $_.Trim('[ "{}]') };
$configs = ($buildConfigurations | where {$_.Guid -eq $projectParts[3]} | Select-Object Name)
foreach ($config in $configs)
{
$santisiedConfig = if ([string]::IsNullOrEmpty($config.Name)){"Release"}else{$config.Name}
if ($projectParts[1] -match "OurCompanyPrefix.")
{
New-Object PSObject -Property @{
Name = $projectParts[1];
File = $projectParts[2];
Guid = $projectParts[3];
Config = $santisiedConfig
}
}
}
}
加载 Visual Studio 项目
从我对解决方案文件的解析中,我现在有一个每个解决方案的项目列表,其中关键包含从解决方案根目录找到项目的相对文件路径。
$projectDefinition = [xml](Get-Content $csProjectFileName)
$ns = @{ e = "http://schemas.microsoft.com/developer/msbuild/2003" }
$references = @();
1) 识别外部项目参考
$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:ItemGroup/e:Reference" -Namespace $ns | % {$_.Node} | where {$_.Include -match "OurCompanyPrefix" -and $_.HintPath -notmatch "packages"} | % {$_.Include}
2) 识别内部项目参考
$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:ItemGroup/e:ProjectReference" -Namespace $ns | % { $_.Node.Name }
3) 遵循“构建后”事件作为外部参考
$references += Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup/e:PostBuildEvent" -Namespace $ns | where {(!([String]::IsNullOrEmpty($_.Node.InnerText)))} | % {
$postBuildEvents = $_.Node.InnerText.Split("`n")
$projectsReferencedInPostBuildEvents = $postBuildEvents | Select-String "\(SolutionDir\)((\w|\.)*)" | % {$_.Matches[0].Groups[1].Value}
if ($projectsReferencedInPostBuildEvents -ne $null)
{
Write-Output $projectsReferencedInPostBuildEvents | % { $matchedProject = $_; ($releaseConfiguation | ? {$_.File -match $matchedProject}).Name }
}
}
而且,既然我们在这里,也可以获得一些基本的输出信息
在迭代我要构建的项目列表时,这很方便,因为知道在哪里推送输出,或者在哪里找到依赖项的输出。
$assemblyName = (Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup/e:AssemblyName" -Namespace $ns).Node.InnerText
$outputPath = (Select-Xml -Xml $projectDefinition -XPath "//e:Project/e:PropertyGroup[contains(@Condition,'Release|')]/e:OutputPath" -Namespace $ns).Node.InnerText
最后
我们只需要确保我们没有任何重复项,所以我只记录这个特定代码项目的不同依赖项:
$dependendents = @();
if ($references -ne $null)
{
$buildAction.project.dependencies += $references | where {(!([string]::IsNullOrEmpty($_))) -and ($_ -match "OurCompanyPrefix\.(.*)")} | % { $_.ToLower()} | Select -unique
}
我希望这可以为您提供足够的信息来解析您的 SLN 和 PROJ 文件。我认为您将如何选择捕获和存储这些信息完全取决于您。
我正在写一篇关于此的相当深入的博客文章,其中将包含我上面没有提到的所有修饰和框架。这篇文章还没有准备好,但我会从之前的一篇文章中链接到它:http: //automagik.piximo.me/2013/02/just-in-time-compilation.html - 因为微软的这个改变几乎使这项工作出轨!
干杯。