SharpLab/#build/Build-All.ps1

386 строки
16 KiB
PowerShell

Set-StrictMode -Version 2.0
$ErrorActionPreference = 'Stop'
$ProgressPreference = "SilentlyContinue" # https://www.amido.com/powershell-win32-error-handle-invalid-0x6/
# Write-Host, Write-Error and Write-Warning do not function properly in Azure
# So this mostly uses Write-Output for now
$BuildRoslynBranchIfModified = Resolve-Path "$PSScriptRoot\Build-RoslynBranchIfModified.ps1"
."$PSScriptRoot\Setup-Build.ps1"
function Update-RoslynSource($directoryPath, $repositoryUrl) {
Write-Output "Updating $directoryPath"
if (Test-Path "$directoryPath\.git") {
Invoke-Git $directoryPath config user.email "tryroslyn@github.test"
Invoke-Git $directoryPath config user.name "TryRoslyn"
Invoke-Git $directoryPath fetch --prune origin
@(Invoke-Git $directoryPath branch -vv) |
? { $_ -match '\s*(\S+)\s.*: gone\]' } |
% { $matches[1] } |
% { Invoke-Git $directoryPath branch -D $_ }
Invoke-Git $directoryPath gc --auto
}
else {
Invoke-Git . clone $repositoryUrl $directoryPath
}
}
function Format-Xml($xml) {
$stringWriter = New-Object IO.StringWriter
$xmlWriter = New-Object Xml.XmlTextWriter $stringWriter
$xmlWriter.Formatting = [Xml.Formatting]::Indented
$xml.WriteTo($xmlWriter)
$xmlWriter.Flush()
return $stringWriter.ToString()
}
function ConvertTo-Hashtables($inputObject) {
if ($inputObject -isnot [PSObject]) {
return $inputObject
}
$hash = @{}
foreach ($property in $inputObject.PSObject.Properties) {
$hash[$property.Name] = ConvertTo-Hashtables $property.Value
}
return $hash
}
function Get-PackageVersion($projectJsonPath, $name) {
$content = [IO.File]::ReadAllText((Resolve-Path $projectJsonPath))
$json = $content | ConvertFrom-Json
if (!($json.dependencies.PSObject.Properties | ? { $_.Name -eq $name })) {
return $null
}
return $json.dependencies.$name
}
function Map-PackageVersions($name, $projectJsonPaths, $framework, $maps) {
$projectJsonPath = ($projectJsonPaths | ? { Test-Path $_ } | select -first 1)
if (!$projectJsonPath) {
Write-Output " [WARNING] None of project.json paths found for $name"
return
}
$version = Get-PackageVersion $projectJsonPath $name
if (!$version) { return }
$maps.referencePaths[$name] = "..\#packages\$name.$version\lib\$framework\$name.dll"
$maps.packageVersions[$name] = $version
$maps.assemblyVersions[$name] = '<mapped after package restore>'
}
function Rewrite-PackageVersions($packagesPath, $maps) {
$packagesPath = (Resolve-Path $packagesPath)
$content = [IO.File]::ReadAllText($packagesPath)
$contentXml = [xml]$content
$maps.packageVersions.GetEnumerator() | % {
$name = $_.Key
$version = $_.Value
Select-Xml $contentXml -XPath '//package' |
? { $_.Node.id -eq $name } |
% { $_.Node.version = $version }
}
$rewritten = Format-Xml $contentXml
if ($rewritten -eq $content) {
return
}
Set-Content $packagesPath $rewritten
}
function Rewrite-ProjectReferences($projectPath, $maps) {
$xmlNamespaces = @{msbuild='http://schemas.microsoft.com/developer/msbuild/2003'}
$projectPath = (Resolve-Path $projectPath)
$content = [IO.File]::ReadAllText($projectPath)
$contentXml = [xml]$content
$maps.referencePaths.GetEnumerator() | % {
$name = $_.Key
$path = $_.Value
Select-Xml -Xml $contentXml -XPath '//msbuild:Reference' -Namespace $xmlNamespaces |
? { $_.Node.Include -match "^$([regex]::Escape($name))(,|$)" } |
% {
$_.Node.Include = $name
@(Select-Xml -Xml $_.Node -XPath 'descendant::msbuild:HintPath' -Namespace $xmlNamespaces)[0].Node.InnerText = $path
}
}
$rewritten = Format-Xml $contentXml
if ($rewritten -eq $content) {
return
}
Set-Content $projectPath $rewritten
}
function Map-AssemblyVersions($siteBuildRoot, $maps) {
@($maps.assemblyVersions.Keys) | % {
$name = $_
$path = Join-Path (Join-Path $siteBuildRoot '_') ($maps.referencePaths[$name])
$assembly = [Reflection.Assembly]::LoadFrom($path)
$version = $assembly.GetName().Version
$maps.assemblyVersions[$name] = $version
}
}
function Rewrite-BindingRedirects($webConfigPath, $maps) {
$xmlNamespaces = @{a='urn:schemas-microsoft-com:asm.v1'}
$webConfigPath = (Resolve-Path $webConfigPath)
$content = [IO.File]::ReadAllText($webConfigPath)
$contentXml = [xml]$content
$maps.assemblyVersions.GetEnumerator() | % {
$name = $_.Key
$version = $_.Value
Select-Xml -Xml $contentXml -XPath "//a:dependentAssembly[a:assemblyIdentity[@name='$name']]/a:bindingRedirect" -Namespace $xmlNamespaces |
% {
$_.Node.SetAttribute('oldVersion', "0.0.0.0-$version")
$_.Node.SetAttribute('newVersion', $version)
}
}
$rewritten = Format-Xml $contentXml
if ($rewritten -eq $content) {
return
}
Set-Content $webConfigPath $rewritten
}
function Ensure-ResolvedPath($path) {
if (-not (Test-Path $path)) {
New-Item -ItemType directory -Path $path | Out-Null
}
return Resolve-Path $path
}
function ConvertTo-Hashtable([PSCustomObject] $object) {
$result = @{}
$object.PSObject.Properties | % { $result[$_.Name] = $_.Value }
return $result
}
function Find-FirstFilePathDeep($path, $name) {
$file = Get-ChildItem -Path $path -Filter $name -Recurse | select -first 1
if (!$file) {
return "$path\$name"
}
return $file.FullName
}
# Code ------
try {
$Host.UI.RawUI.WindowTitle = "TryRoslyn Build" # prevents title > 1024 char errors
#Write-Output "Killing VBCSCompiler instances"
#taskkill /IM VBCSCompiler.exe /F
Write-Output "Environment:"
Write-Output " Current Path: $(Get-Location)"
Write-Output " Script Root: $PSScriptRoot"
$root = Resolve-Path "$PSScriptRoot\.."
Write-Output " Root: $root"
$sourceRoot = Resolve-Path "$root\source"
Write-Output " Source Root: $sourceRoot"
$roslynBuildRoot = Ensure-ResolvedPath "$root\!roslyn"
Write-Output " Roslyn Build Root: $roslynBuildRoot"
$sitesBuildRoot = Ensure-ResolvedPath "$root\!sites"
Write-Output " Sites Build Root: $sitesBuildRoot"
$buildConfig = ConvertFrom-Json (Get-Content "$root\Build.config.json" -Raw)
${env:$HOME} = $PSScriptRoot
Invoke-Git . --version
Write-Output "Restoring TryRoslyn packages..."
&"$PSScriptRoot\#tools\nuget" restore "$sourceRoot\TryRoslyn.sln"
$failedListPath = "$sitesBuildRoot\!failed.txt"
if (Test-Path $failedListPath) {
Write-Output "Deleting $failedListPath..."
Remove-Item $failedListPath
}
$buildConfig.RoslynRepositories | % {
Write-Output "Building repository '$($_.Name)' ($($_.Url))..."
$roslynSourceRoot = Ensure-ResolvedPath "$roslynBuildRoot\$($_.Name)"
Write-Output " Roslyn Source Root: $roslynSourceRoot"
Write-Output "Updating..."
Update-RoslynSource -DirectoryPath $roslynSourceRoot -RepositoryUrl $($_.Url)
Write-Output "Getting branches..."
$branchesRaw = @(Invoke-Git $roslynSourceRoot branch --remote)
$branches = $branchesRaw |
? { $_ -notmatch '^\s+origin/HEAD' } |
% { ($_ -match 'origin/(.+)$') | Out-Null; $matches[1] }
$repositoryConfig = ConvertTo-Hashtable $_
$repositoryName = $repositoryConfig.Name
$include = $repositoryConfig['Include']
$exclude = $repositoryConfig['Exclude']
Write-Output " $branches"
$branches | % {
Write-Output ''
Write-Output "*** $repositoryName`: $_"
if ($include -and $_ -notmatch $include) {
Write-Output "Does not match inclusion rules, skipped."
return
}
if ($exclude -and $_ -match $exclude) {
Write-Output "Matches exclusion rule, skipped."
return
}
$Host.UI.RawUI.WindowTitle = "TryRoslyn Build: $_"
$branchFsName = $repositoryName + "-" + ($_ -replace '[/\\:_]', '-')
$siteBuildRoot = Ensure-ResolvedPath "$sitesBuildRoot\$branchFsName"
$roslynBinaryRoot = Ensure-ResolvedPath "$siteBuildRoot\!roslyn"
$siteBuildTempRoot = Ensure-ResolvedPath "$siteBuildRoot\!temp"
$siteCopyRoot = Ensure-ResolvedPath "$siteBuildRoot\!site"
$branchMapsPath = "$roslynBinaryRoot\!BranchMaps.json"
try {
Write-Output " Copying $sourceRoot => $siteBuildRoot"
robocopy $sourceRoot $siteBuildRoot /njh /njs /ndl /np /ns /xo /e /purge `
/xd "$roslynBinaryRoot" "$siteCopyRoot" "$siteBuildTempRoot" "$sourceRoot\Web"
Write-Output ""
Push-Location $roslynBuildRoot
try {
&$BuildRoslynBranchIfModified `
-SourceRoot $roslynSourceRoot `
-BranchName $_ `
-OutputRoot $roslynBinaryRoot `
-IfBuilt {
Write-Output "Getting branch info..."
$branchInfo = @{
name = $_
repository = $repositoryConfig.Name
commits = @(@{
hash = (Invoke-Git $roslynSourceRoot log "$_" -n 1 --pretty=format:"%H" )
date = (Invoke-Git $roslynSourceRoot log "$_" -n 1 --pretty=format:"%aI")
author = (Invoke-Git $roslynSourceRoot log "$_" -n 1 --pretty=format:"%aN")
message = @(Invoke-Git $roslynSourceRoot log "$_" -n 1 --pretty=format:"%B" ) -join "`r`n"
})
}
Set-Content "$roslynBinaryRoot\!BranchInfo.json" (ConvertTo-Json $branchInfo -Depth 100)
Write-Output "Mapping references..."
$referenceMaps = @{
packageVersions = @{}
assemblyVersions = @{}
referencePaths = @{
'Microsoft.CodeAnalysis' = Find-FirstFilePathDeep $roslynBinaryRoot "Microsoft.CodeAnalysis.dll"
'Microsoft.CodeAnalysis.CSharp' = Find-FirstFilePathDeep $roslynBinaryRoot "Microsoft.CodeAnalysis.CSharp.dll"
'Microsoft.CodeAnalysis.VisualBasic' = Find-FirstFilePathDeep $roslynBinaryRoot "Microsoft.CodeAnalysis.VisualBasic.dll"
}
}
$portableProjectJsonPath = "$roslynSourceRoot\src\Compilers\Core\Portable\project.json"
Map-PackageVersions 'System.Reflection.Metadata' `
-ProjectJsonPaths @($portableProjectJsonPath, "$roslynSourceRoot\src\Dependencies\Metadata\project.json") `
-Framework 'portable-net45+win8' -Maps $referenceMaps
Map-PackageVersions 'System.Collections.Immutable' `
-ProjectJsonPaths @($portableProjectJsonPath) `
-Framework 'portable-net45+win8+wp8+wpa81' -Maps $referenceMaps
Map-PackageVersions 'System.IO.FileSystem' `
-ProjectJsonPaths @($portableProjectJsonPath) `
-Framework 'net46' -Maps $referenceMaps
Map-PackageVersions 'System.Security.Cryptography.Algorithms' `
-ProjectJsonPaths @($portableProjectJsonPath) `
-Framework 'net46' -Maps $referenceMaps
Map-PackageVersions 'System.ValueTuple' `
-ProjectJsonPaths @($portableProjectJsonPath) `
-Framework 'netstandard1.0' -Maps $referenceMaps
Set-Content $branchMapsPath (ConvertTo-Json $referenceMaps -Depth 100)
}
}
finally {
Pop-Location
}
Push-Location $siteBuildRoot
try {
$buildLogPath = "$siteBuildRoot\!build.log"
Write-Output "Loading reference maps..."
$referenceMaps = ConvertTo-Hashtables (ConvertFrom-Json (Get-Content $branchMapsPath -Raw))
@(
$referenceMaps.packageVersions.GetEnumerator(),
$referenceMaps.referencePaths.GetEnumerator()
) | % { $_ } | % {
Write-Output " $($_.Key) $($_.Value)"
}
Write-Output "Rewriting packages.config files..."
Get-ChildItem packages.config -Recurse -ErrorAction SilentlyContinue | % {
Rewrite-PackageVersions $_ $referenceMaps
Write-Output " $($_.Directory.Name)\$($_.Name)"
}
Write-Output "Rewriting *.csproj files..."
Get-ChildItem *.csproj -Recurse -ErrorAction SilentlyContinue | % {
Rewrite-ProjectReferences $_ $referenceMaps
Write-Output " $($_.Name)"
}
Write-Output "Restoring site packages..."
&"$PSScriptRoot\#tools\nuget" restore "$siteBuildRoot\TryRoslyn.sln"
Write-Output "Mapping assembly versions..."
Map-AssemblyVersions $siteBuildRoot $referenceMaps
$referenceMaps.assemblyVersions.GetEnumerator() | % {
Write-Output " $($_.Key) $($_.Value)"
}
Write-Output "Rewriting Web.config file..."
Get-Item Web.Api\Web.config | % {
Rewrite-BindingRedirects $_ $referenceMaps
Write-Output " $($_.Directory.Name)\$($_.Name)"
}
Write-Output "Building Web.Api.csproj..."
&$MSBuild Web.Api\Web.Api.csproj > $buildLogPath `
/p:OutputPath="""$siteCopyRoot\bin\\""" `
/p:IntermediateOutputPath="""$siteBuildTempRoot\\""" `
/p:AllowedReferenceRelatedFileExtensions=.pdb
if ($LastExitCode -ne 0) {
throw New-Object BranchBuildException("Build failed, see $buildLogPath", $buildLogPath)
}
Copy-Item "Web.Api\Global.asax" "$siteCopyRoot\Global.asax" -Force
Copy-Item "Web.Api\Web.config" "$siteCopyRoot\Web.config" -Force
Write-Output "TryRoslyn build done."
}
finally {
Pop-Location
}
}
catch {
$ex = $_.Exception
if ($ex -isnot [BranchBuildException]) {
throw
}
Write-Output " [WARNING] $($ex.Message)"
Add-Content $failedListPath @("$branchFsName ($repositoryName)", $ex.Message, '')
}
}
}
}
catch {
Write-Output "[ERROR] $_"
Write-Output 'Returning exit code 1'
exit 1
}