Родитель
02003383f0
Коммит
217a6332cb
|
@ -0,0 +1,26 @@
|
|||
# EditorConfig is awesome:
|
||||
http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Don't use tabs for indentation.
|
||||
[*]
|
||||
indent_style = space
|
||||
# (Please don't specify an indent_size here; that has too many unintended consequences.)
|
||||
|
||||
# Code files
|
||||
[*.cs,*.csx,*.vb,*.vbx]
|
||||
indent_size = 4
|
||||
|
||||
# Xml project files
|
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
|
||||
indent_size = 2
|
||||
|
||||
# Xml config files
|
||||
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
|
||||
indent_size = 2
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
indent_size = 2
|
|
@ -1,74 +1,49 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
# Set default behavior to:
|
||||
# automatically normalize line endings on check-in, and
|
||||
# convert to Windows-style line endings on check-out
|
||||
###############################################################################
|
||||
* text=auto encoding=UTF-8
|
||||
|
||||
# csc/vbc are shell scripts and should always have unix line endings
|
||||
# These shell scripts are included in the toolset packages. Normally, the shell
|
||||
# scripts in our repo are only run by cloning onto a Linux/Mac machine, and git
|
||||
# automatically chooses LF as the line ending.
|
||||
#
|
||||
# However, right now the toolset packages must be built on Windows, and so the
|
||||
# files must be hard-coded to be cloned with LF
|
||||
src/Compilers/CSharp/CscCore/csc text eol=lf
|
||||
src/Compilers/VisualBasic/VbcCore/vbc text eol=lf
|
||||
*.sh text eol=lf
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
# Set file behavior to:
|
||||
# treat as text, and
|
||||
# diff as C# source code
|
||||
###############################################################################
|
||||
*.cs diff=csharp text
|
||||
*.vb text
|
||||
*.cs text diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
# Set file behavior to:
|
||||
# treat as text
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
*.cmd text
|
||||
*.config text
|
||||
*.csproj text
|
||||
*.groovy text
|
||||
*.json text
|
||||
*.md text
|
||||
*.nuspec text
|
||||
*.pkgdef text
|
||||
*.proj text
|
||||
*.projitems text
|
||||
*.props text
|
||||
*.ps1 text
|
||||
*.resx text
|
||||
*.ruleset text
|
||||
*.shproj text
|
||||
*.sln text
|
||||
*.targets text
|
||||
*.vb text
|
||||
*.vbproj text
|
||||
*.vcxproj text
|
||||
*.vcxproj.filters text
|
||||
*.vsct text
|
||||
*.vsixmanifest text
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
# Set file behavior to:
|
||||
# treat as binary
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
*.png binary
|
||||
*.snk binary
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
resources:
|
||||
- repo: self
|
||||
clean: true
|
||||
queue:
|
||||
name: VSEng-MicroBuildVS2017
|
||||
demands: Cmd
|
||||
variables:
|
||||
BuildConfiguration: Release
|
||||
TeamName: Roslyn
|
||||
|
||||
steps:
|
||||
- task: ms-vseng.MicroBuildTasks.30666190-6959-11e5-9f96-f56098202fef.MicroBuildSigningPlugin@1
|
||||
displayName: Install Signing Plugin
|
||||
inputs:
|
||||
signType: real
|
||||
condition: and(succeeded(), eq(variables['PB_SignType'], 'real'))
|
||||
|
||||
- script: eng\common\CIBuild.cmd
|
||||
-configuration $(BuildConfiguration)
|
||||
/p:PB_PublishBlobFeedKey=$(PB_PublishBlobFeedKey)
|
||||
displayName: Build
|
||||
|
||||
- task: PublishTestResults@1
|
||||
displayName: Publish Test Results
|
||||
inputs:
|
||||
testRunner: XUnit
|
||||
testResultsFiles: 'artifacts/$(BuildConfiguration)/TestResults/*.xml'
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'Unit Tests'
|
||||
condition: and(succeeded(), ne(variables['PB_SkipTests'], 'true'))
|
||||
|
||||
- task: NuGetPublisher@0
|
||||
displayName: Publish NuGet Packages to MyGet
|
||||
inputs:
|
||||
searchPattern: 'artifacts\$(BuildConfiguration)\packages\*.nupkg'
|
||||
connectedServiceName: 'SymReaderConverter NuGet feed'
|
||||
nuGetVersion: 4.0.0.2283
|
||||
condition: and(succeeded(), not(contains(variables['PB_PublishType'], 'blob')))
|
||||
|
||||
- task: PublishSymbols@1
|
||||
displayName: Prepare Symbols
|
||||
inputs:
|
||||
SymbolsPath: '$(DropRoot)\$(TeamName)\$(Build.DefinitionName)\$(Build.BuildNumber)\Symbols'
|
||||
SearchPattern: '**/*.+(dll|exe|pdb)'
|
||||
SymbolsFolder: '$(Build.SourcesDirectory)\artifacts\$(BuildConfiguration)\SymStore'
|
||||
SkipIndexing: true
|
||||
enabled: false
|
||||
condition: and(succeeded(), not(contains(variables['PB_PublishType'], 'blob')))
|
||||
|
||||
- task: ms-vscs-artifact.build-tasks.artifactSymbolTask-1.artifactSymbolTask@0
|
||||
displayName: Publish Symbols
|
||||
inputs:
|
||||
symbolServiceURI: 'https://microsoft.artifacts.visualstudio.com/DefaultCollection'
|
||||
requestName: '$(system.teamProject)/$(Build.DefinitionName)/$(Build.BuildNumber)/$(Build.BuildId)'
|
||||
sourcePath: '$(DropRoot)\$(TeamName)\$(Build.DefinitionName)\$(Build.BuildNumber)\Symbols'
|
||||
usePat: false
|
||||
enabled: false
|
||||
condition: and(succeeded(), not(contains(variables['PB_PublishType'], 'blob')))
|
||||
|
||||
- task: CopyPublishBuildArtifacts@1
|
||||
displayName: Publish Artifacts
|
||||
inputs:
|
||||
CopyRoot: '$(Build.SourcesDirectory)'
|
||||
Contents: |
|
||||
artifacts\$(BuildConfiguration)\bin
|
||||
artifacts\$(BuildConfiguration)\log
|
||||
artifacts\$(BuildConfiguration)\TestResults
|
||||
artifacts\$(BuildConfiguration)\packages
|
||||
ArtifactName: '$(Build.BuildNumber)'
|
||||
ArtifactType: FilePath
|
||||
TargetPath: '$(DropRoot)\$(TeamName)\$(Build.DefinitionName)'
|
||||
condition: and(succeeded(), not(contains(variables['PB_PublishType'], 'blob')))
|
||||
|
||||
- task: ms-vseng.MicroBuildTasks.521a94ea-9e68-468a-8167-6dcf361ea776.MicroBuildCleanup@1
|
||||
displayName: Cleanup
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish MicroBuild Artifacts
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.ArtifactStagingDirectory)\MicroBuild\Output'
|
||||
ArtifactName: '$(Build.BuildNumber)'
|
||||
publishLocation: FilePath
|
||||
TargetPath: '$(DropRoot)\$(TeamName)\$(Build.DefinitionName)'
|
||||
condition: not(contains(variables['PB_PublishType'], 'blob'))
|
|
@ -1,3 +1,3 @@
|
|||
@echo off
|
||||
powershell -ExecutionPolicy ByPass %~dp0build\Build.ps1 -restore -build %*
|
||||
powershell -ExecutionPolicy ByPass -command "& {&'%~dp0eng\common\Build.ps1' -restore -build %*}
|
||||
exit /b %ErrorLevel%
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
@echo off
|
||||
powershell -ExecutionPolicy ByPass %~dp0build\Build.ps1 -restore -build -test -sign -pack -ci %*
|
||||
exit /b %ErrorLevel%
|
|
@ -1,3 +1,3 @@
|
|||
@echo off
|
||||
powershell -ExecutionPolicy ByPass %~dp0build\Build.ps1 -restore %*
|
||||
powershell -ExecutionPolicy ByPass -command "& {&'%~dp0eng\common\Build.ps1' -restore %*}
|
||||
exit /b %ErrorLevel%
|
||||
|
|
2
Test.cmd
2
Test.cmd
|
@ -1,3 +1,3 @@
|
|||
@echo off
|
||||
powershell -ExecutionPolicy ByPass %~dp0build\Build.ps1 -test %*
|
||||
powershell -ExecutionPolicy ByPass -command "& {&'%~dp0eng\common\Build.ps1' -test %*}
|
||||
exit /b %ErrorLevel%
|
147
build/build.ps1
147
build/build.ps1
|
@ -1,147 +0,0 @@
|
|||
[CmdletBinding(PositionalBinding=$false)]
|
||||
Param(
|
||||
[string] $configuration = "Debug",
|
||||
[string] $solution = "",
|
||||
[string] $verbosity = "minimal",
|
||||
[switch] $restore,
|
||||
[switch] $build,
|
||||
[switch] $rebuild,
|
||||
[switch] $test,
|
||||
[switch] $sign,
|
||||
[switch] $pack,
|
||||
[switch] $ci,
|
||||
[switch] $prepareMachine,
|
||||
[switch] $log,
|
||||
[switch] $help,
|
||||
[Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
|
||||
)
|
||||
|
||||
set-strictmode -version 2.0
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Print-Usage() {
|
||||
Write-Host "Common settings:"
|
||||
Write-Host " -configuration <value> Build configuration Debug, Release"
|
||||
Write-Host " -verbosity <value> Msbuild verbosity (q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic])"
|
||||
Write-Host " -help Print help and exit"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Actions:"
|
||||
Write-Host " -restore Restore dependencies"
|
||||
Write-Host " -build Build solution"
|
||||
Write-Host " -rebuild Rebuild solution"
|
||||
Write-Host " -test Run all unit tests in the solution"
|
||||
Write-Host " -sign Sign build outputs"
|
||||
Write-Host " -pack Package build outputs into NuGet packages and Willow components"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Advanced settings:"
|
||||
Write-Host " -solution <value> Path to solution to build"
|
||||
Write-Host " -ci Set when running on CI server"
|
||||
Write-Host " -log Enable logging (by default on CI)"
|
||||
Write-Host " -prepareMachine Prepare machine for CI run"
|
||||
Write-Host ""
|
||||
Write-Host "Command line arguments not listed above are passed thru to msbuild."
|
||||
Write-Host "The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.)."
|
||||
}
|
||||
|
||||
if ($help -or (($properties -ne $null) -and ($properties.Contains("/help") -or $properties.Contains("/?")))) {
|
||||
Print-Usage
|
||||
exit 0
|
||||
}
|
||||
|
||||
function Create-Directory([string[]] $path) {
|
||||
if (!(Test-Path $path)) {
|
||||
New-Item -path $path -force -itemType "Directory" | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function InstallDotNetCli {
|
||||
$installScript = "$DotNetRoot\dotnet-install.ps1"
|
||||
if (!(Test-Path $installScript)) {
|
||||
Create-Directory $DotNetRoot
|
||||
Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile $installScript
|
||||
}
|
||||
|
||||
& $installScript -Version $globalJson.sdk.version -InstallDir $DotNetRoot
|
||||
if ($lastExitCode -ne 0) {
|
||||
throw "Failed to install dotnet cli (exit code '$lastExitCode')."
|
||||
}
|
||||
}
|
||||
|
||||
function InstallToolset {
|
||||
if (!(Test-Path $ToolsetBuildProj)) {
|
||||
$proj = Join-Path $TempDir "_restore.proj"
|
||||
'<Project Sdk="RoslynTools.RepoToolset"><Target Name="NoOp"/></Project>' | Set-Content $proj
|
||||
& $DotNetExe msbuild $proj /t:NoOp /m /nologo /clp:None /warnaserror /v:$verbosity /p:NuGetPackageRoot=$NuGetPackageRoot /p:__ExcludeSdkImports=true
|
||||
}
|
||||
}
|
||||
|
||||
function Build {
|
||||
if ($ci -or $log) {
|
||||
Create-Directory($logDir)
|
||||
$logCmd = "/bl:" + (Join-Path $LogDir "Build.binlog")
|
||||
} else {
|
||||
$logCmd = ""
|
||||
}
|
||||
|
||||
& $DotNetExe msbuild $ToolsetBuildProj /m /nologo /clp:Summary /warnaserror /v:$verbosity $logCmd /p:Configuration=$configuration /p:SolutionPath=$solution /p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Test=$test /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci /p:NuGetPackageRoot=$NuGetPackageRoot $properties
|
||||
}
|
||||
|
||||
function Stop-Processes() {
|
||||
Write-Host "Killing running build processes..."
|
||||
Get-Process -Name "dotnet" -ErrorAction SilentlyContinue | Stop-Process
|
||||
Get-Process -Name "vbcscompiler" -ErrorAction SilentlyContinue | Stop-Process
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$RepoRoot = Join-Path $PSScriptRoot "..\"
|
||||
$DotNetRoot = Join-Path $RepoRoot ".dotnet"
|
||||
$DotNetExe = Join-Path $DotNetRoot "dotnet.exe"
|
||||
$ArtifactsDir = Join-Path $RepoRoot "artifacts"
|
||||
$LogDir = Join-Path (Join-Path $ArtifactsDir $configuration) "log"
|
||||
$TempDir = Join-Path (Join-Path $ArtifactsDir $configuration) "tmp"
|
||||
$globalJson = Get-Content(Join-Path $RepoRoot "global.json") | ConvertFrom-Json
|
||||
|
||||
if ($solution -eq "") {
|
||||
$solution = @(gci(Join-Path $RepoRoot "*.sln"))[0]
|
||||
}
|
||||
|
||||
if ($env:NUGET_PACKAGES -ne $null) {
|
||||
$NuGetPackageRoot = $env:NUGET_PACKAGES.TrimEnd("\") + "\"
|
||||
} else {
|
||||
$NuGetPackageRoot = Join-Path $env:UserProfile ".nuget\packages\"
|
||||
}
|
||||
|
||||
$ToolsetVersion = $globalJson.'msbuild-sdks'.'RoslynTools.RepoToolset'
|
||||
$ToolsetBuildProj = Join-Path $NuGetPackageRoot "roslyntools.repotoolset\$ToolsetVersion\tools\Build.proj"
|
||||
|
||||
Create-Directory $TempDir
|
||||
|
||||
if ($ci) {
|
||||
$env:TEMP = $TempDir
|
||||
$env:TMP = $TempDir
|
||||
}
|
||||
|
||||
if ($restore) {
|
||||
InstallDotNetCli
|
||||
InstallToolset
|
||||
}
|
||||
|
||||
Build
|
||||
exit $lastExitCode
|
||||
}
|
||||
catch {
|
||||
Write-Host $_
|
||||
Write-Host $_.Exception
|
||||
Write-Host $_.ScriptStackTrace
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
if ($ci -and $prepareMachine) {
|
||||
Stop-Processes
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
|
||||
<!-- This repo version -->
|
||||
<VersionBase>1.1.0</VersionBase>
|
||||
<VersionPrefix>1.1.0</VersionPrefix>
|
||||
<PreReleaseVersionLabel>beta1</PreReleaseVersionLabel>
|
||||
|
||||
<!-- libs -->
|
|
@ -0,0 +1,3 @@
|
|||
@echo off
|
||||
powershell -ExecutionPolicy ByPass -command "& {&'%~dp0Build.ps1' -restore -build -test -sign -pack -ci %*}
|
||||
exit /b %ErrorLevel%
|
|
@ -0,0 +1,211 @@
|
|||
[CmdletBinding(PositionalBinding=$false)]
|
||||
Param(
|
||||
[string] $configuration = "Debug",
|
||||
[string] $solution = "",
|
||||
[string] $verbosity = "minimal",
|
||||
[switch] $restore,
|
||||
[switch] $deployDeps,
|
||||
[switch] $build,
|
||||
[switch] $rebuild,
|
||||
[switch] $deploy,
|
||||
[switch] $test,
|
||||
[switch] $integrationTest,
|
||||
[switch] $sign,
|
||||
[switch] $pack,
|
||||
[switch] $ci,
|
||||
[switch] $prepareMachine,
|
||||
[switch] $help,
|
||||
[Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
|
||||
)
|
||||
|
||||
set-strictmode -version 2.0
|
||||
$ErrorActionPreference = "Stop"
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
function Print-Usage() {
|
||||
Write-Host "Common settings:"
|
||||
Write-Host " -configuration <value> Build configuration Debug, Release"
|
||||
Write-Host " -verbosity <value> Msbuild verbosity (q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic])"
|
||||
Write-Host " -help Print help and exit"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Actions:"
|
||||
Write-Host " -restore Restore dependencies"
|
||||
Write-Host " -build Build solution"
|
||||
Write-Host " -rebuild Rebuild solution"
|
||||
Write-Host " -deploy Deploy built VSIXes"
|
||||
Write-Host " -deployDeps Deploy dependencies (e.g. VSIXes for integration tests)"
|
||||
Write-Host " -test Run all unit tests in the solution"
|
||||
Write-Host " -integrationTest Run all integration tests in the solution"
|
||||
Write-Host " -sign Sign build outputs"
|
||||
Write-Host " -pack Package build outputs into NuGet packages and Willow components"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Advanced settings:"
|
||||
Write-Host " -solution <value> Path to solution to build"
|
||||
Write-Host " -ci Set when running on CI server"
|
||||
Write-Host " -prepareMachine Prepare machine for CI run"
|
||||
Write-Host ""
|
||||
Write-Host "Command line arguments not listed above are passed thru to msbuild."
|
||||
Write-Host "The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.)."
|
||||
}
|
||||
|
||||
if ($help -or (($properties -ne $null) -and ($properties.Contains("/help") -or $properties.Contains("/?")))) {
|
||||
Print-Usage
|
||||
exit 0
|
||||
}
|
||||
|
||||
function Create-Directory([string[]] $path) {
|
||||
if (!(Test-Path $path)) {
|
||||
New-Item -path $path -force -itemType "Directory" | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function InstallDotNetCli {
|
||||
$installScript = "$DotNetRoot\dotnet-install.ps1"
|
||||
if (!(Test-Path $installScript)) {
|
||||
Create-Directory $DotNetRoot
|
||||
Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile $installScript
|
||||
}
|
||||
|
||||
& $installScript -Version $GlobalJson.sdk.version -InstallDir $DotNetRoot
|
||||
if ($lastExitCode -ne 0) {
|
||||
throw "Failed to install dotnet cli (exit code '$lastExitCode')."
|
||||
}
|
||||
}
|
||||
|
||||
function LocateVisualStudio {
|
||||
if ($InVSEnvironment) {
|
||||
return Join-Path $env:VS150COMNTOOLS "..\.."
|
||||
}
|
||||
|
||||
$vswhereVersion = $GlobalJson.vswhere.version
|
||||
$toolsRoot = Join-Path $RepoRoot ".tools"
|
||||
$vsWhereDir = Join-Path $toolsRoot "vswhere\$vswhereVersion"
|
||||
$vsWhereExe = Join-Path $vsWhereDir "vswhere.exe"
|
||||
|
||||
if (!(Test-Path $vsWhereExe)) {
|
||||
Create-Directory $vsWhereDir
|
||||
Write-Host "Downloading vswhere"
|
||||
Invoke-WebRequest "https://github.com/Microsoft/vswhere/releases/download/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe
|
||||
}
|
||||
|
||||
$vsInstallDir = & $vsWhereExe -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild -requires Microsoft.VisualStudio.Component.VSSDK -requires Microsoft.Net.Component.4.6.TargetingPack -requires Microsoft.VisualStudio.Component.Roslyn.Compiler -requires Microsoft.VisualStudio.Component.VSSDK
|
||||
|
||||
if (!(Test-Path $vsInstallDir)) {
|
||||
throw "Failed to locate Visual Studio (exit code '$lastExitCode')."
|
||||
}
|
||||
|
||||
return $vsInstallDir
|
||||
}
|
||||
|
||||
function InstallToolset {
|
||||
if (!(Test-Path $ToolsetBuildProj)) {
|
||||
$proj = Join-Path $TempDir "_restore.proj"
|
||||
'<Project Sdk="RoslynTools.RepoToolset"><Target Name="NoOp"/></Project>' | Set-Content $proj
|
||||
& $BuildDriver $BuildArgs $proj /t:NoOp /m /nologo /clp:None /warnaserror /v:$verbosity /p:NuGetPackageRoot=$NuGetPackageRoot /p:__ExcludeSdkImports=true
|
||||
}
|
||||
}
|
||||
|
||||
function Build {
|
||||
& $BuildDriver $BuildArgs $ToolsetBuildProj /m /nologo /clp:Summary /warnaserror /v:$verbosity /bl:$Log /p:Configuration=$configuration /p:Projects=$solution /p:RepoRoot=$RepoRoot /p:Restore=$restore /p:DeployDeps=$deployDeps /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:IntegrationTest=$integrationTest /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci /p:NuGetPackageRoot=$NuGetPackageRoot $properties
|
||||
}
|
||||
|
||||
function Stop-Processes() {
|
||||
Write-Host "Killing running build processes..."
|
||||
Get-Process -Name "msbuild" -ErrorAction SilentlyContinue | Stop-Process
|
||||
Get-Process -Name "dotnet" -ErrorAction SilentlyContinue | Stop-Process
|
||||
Get-Process -Name "vbcscompiler" -ErrorAction SilentlyContinue | Stop-Process
|
||||
}
|
||||
|
||||
function Clear-NuGetCache() {
|
||||
# clean nuget packages -- necessary to avoid mismatching versions of swix microbuild build plugin and VSSDK on Jenkins
|
||||
$nugetRoot = (Join-Path $env:USERPROFILE ".nuget\packages")
|
||||
if (Test-Path $nugetRoot) {
|
||||
Remove-Item $nugetRoot -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$RepoRoot = Join-Path $PSScriptRoot "..\.."
|
||||
$ArtifactsDir = Join-Path $RepoRoot "artifacts"
|
||||
$LogDir = Join-Path (Join-Path $ArtifactsDir $configuration) "log"
|
||||
$Log = Join-Path $LogDir "Build.binlog"
|
||||
$TempDir = Join-Path (Join-Path $ArtifactsDir $configuration) "tmp"
|
||||
$GlobalJson = Get-Content(Join-Path $RepoRoot "global.json") | ConvertFrom-Json
|
||||
|
||||
if ($solution -eq "") {
|
||||
$solution = Join-Path $RepoRoot "*.sln"
|
||||
}
|
||||
|
||||
if ($env:NUGET_PACKAGES -ne $null) {
|
||||
$NuGetPackageRoot = $env:NUGET_PACKAGES.TrimEnd("\") + "\"
|
||||
} else {
|
||||
$NuGetPackageRoot = Join-Path $env:UserProfile ".nuget\packages\"
|
||||
}
|
||||
|
||||
$ToolsetVersion = $GlobalJson.'msbuild-sdks'.'RoslynTools.RepoToolset'
|
||||
$ToolsetBuildProj = Join-Path $NuGetPackageRoot "roslyntools.repotoolset\$ToolsetVersion\tools\Build.proj"
|
||||
|
||||
# Presence of vswhere.version indicated the repo needs to build using VS msbuild
|
||||
if ((Get-Member -InputObject $GlobalJson -Name "vswhere") -ne $null) {
|
||||
$DotNetRoot = $null
|
||||
$InVSEnvironment = !($env:VS150COMNTOOLS -eq $null) -and (Test-Path $env:VS150COMNTOOLS)
|
||||
$vsInstallDir = LocateVisualStudio
|
||||
|
||||
$BuildDriver = Join-Path $vsInstallDir "MSBuild\15.0\Bin\msbuild.exe"
|
||||
$BuildArgs = "/nodeReuse:$(!$ci)"
|
||||
|
||||
if (!$InVSEnvironment) {
|
||||
$env:VS150COMNTOOLS = Join-Path $vsInstallDir "Common7\Tools\"
|
||||
$env:VSSDK150Install = Join-Path $vsInstallDir "VSSDK\"
|
||||
$env:VSSDKInstall = Join-Path $vsInstallDir "VSSDK\"
|
||||
}
|
||||
} elseif ((Get-Member -InputObject $GlobalJson -Name "sdk") -ne $null) {
|
||||
$DotNetRoot = Join-Path $RepoRoot ".dotnet"
|
||||
$BuildDriver = Join-Path $DotNetRoot "dotnet.exe"
|
||||
$BuildArgs = "msbuild"
|
||||
} else {
|
||||
throw "/global.json must either specify 'sdk.version' or 'vswhere.version'."
|
||||
}
|
||||
|
||||
Create-Directory $TempDir
|
||||
Create-Directory $LogDir
|
||||
|
||||
if ($ci) {
|
||||
$env:TEMP = $TempDir
|
||||
$env:TMP = $TempDir
|
||||
|
||||
Write-Host "Using $BuildDriver"
|
||||
}
|
||||
|
||||
|
||||
# Preparation of a CI machine
|
||||
if ($prepareMachine) {
|
||||
Clear-NuGetCache
|
||||
}
|
||||
|
||||
if ($restore) {
|
||||
if ($DotNetRoot -ne $null) {
|
||||
InstallDotNetCli
|
||||
}
|
||||
|
||||
InstallToolset
|
||||
}
|
||||
|
||||
Build
|
||||
exit $lastExitCode
|
||||
}
|
||||
catch {
|
||||
Write-Host $_
|
||||
Write-Host $_.Exception
|
||||
Write-Host $_.ScriptStackTrace
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
if ($ci -and $prepareMachine) {
|
||||
Stop-Processes
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source="${BASH_SOURCE[0]}"
|
||||
|
||||
# resolve $source until the file is no longer a symlink
|
||||
while [[ -h "$source" ]]; do
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
source="$(readlink "$source")"
|
||||
# if $source was a relative symlink, we need to resolve it relative to the path where the
|
||||
# symlink file was located
|
||||
[[ $source != /* ]] && source="$scriptroot/$source"
|
||||
done
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
|
||||
build=false
|
||||
ci=false
|
||||
configuration='Debug'
|
||||
help=false
|
||||
log=false
|
||||
pack=false
|
||||
prepareMachine=false
|
||||
rebuild=false
|
||||
restore=false
|
||||
sign=false
|
||||
solution=''
|
||||
test=false
|
||||
verbosity='minimal'
|
||||
properties=''
|
||||
reporoot="$scriptroot/../.."
|
||||
artifactsdir="$reporoot/artifacts"
|
||||
artifactsconfigurationdir="$artifactsdir/$configuration"
|
||||
logdir="$artifactsconfigurationdir/log"
|
||||
globaljsonfile="$reporoot/global.json"
|
||||
tempdir="$artifactsconfigurationdir/tmp"
|
||||
officialbuild=false
|
||||
|
||||
if [[ ! -z $OfficialBuildId ]]; then
|
||||
officialbuild=true
|
||||
fi
|
||||
|
||||
while (($# > 0)); do
|
||||
lowerI="$(echo $1 | awk '{print tolower($0)}')"
|
||||
case $lowerI in
|
||||
--build)
|
||||
build=true
|
||||
shift 1
|
||||
;;
|
||||
--ci)
|
||||
ci=true
|
||||
shift 1
|
||||
;;
|
||||
--configuration)
|
||||
configuration=$2
|
||||
shift 2
|
||||
;;
|
||||
--help)
|
||||
echo "Common settings:"
|
||||
echo " --configuration <value> Build configuration Debug, Release"
|
||||
echo " --verbosity <value> Msbuild verbosity (q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic])"
|
||||
echo " --help Print help and exit"
|
||||
echo ""
|
||||
echo "Actions:"
|
||||
echo " --restore Restore dependencies"
|
||||
echo " --build Build solution"
|
||||
echo " --rebuild Rebuild solution"
|
||||
echo " --test Run all unit tests in the solution"
|
||||
echo " --sign Sign build outputs"
|
||||
echo " --pack Package build outputs into NuGet packages and Willow components"
|
||||
echo ""
|
||||
echo "Advanced settings:"
|
||||
echo " --solution <value> Path to solution to build"
|
||||
echo " --ci Set when running on CI server"
|
||||
echo " --log Enable logging (by default on CI)"
|
||||
echo " --prepareMachine Prepare machine for CI run"
|
||||
echo ""
|
||||
echo "Command line arguments not listed above are passed through to MSBuild."
|
||||
exit 0
|
||||
;;
|
||||
--log)
|
||||
log=true
|
||||
shift 1
|
||||
;;
|
||||
--pack)
|
||||
pack=true
|
||||
shift 1
|
||||
;;
|
||||
--preparemachine)
|
||||
preparemachine=true
|
||||
shift 1
|
||||
;;
|
||||
--rebuild)
|
||||
rebuild=true
|
||||
shift 1
|
||||
;;
|
||||
--restore)
|
||||
restore=true
|
||||
shift 1
|
||||
;;
|
||||
--sign)
|
||||
sign=true
|
||||
shift 1
|
||||
;;
|
||||
--solution)
|
||||
solution=$2
|
||||
shift 2
|
||||
;;
|
||||
--test)
|
||||
test=true
|
||||
shift 1
|
||||
;;
|
||||
--verbosity)
|
||||
verbosity=$2
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
properties="$properties $1"
|
||||
shift 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ReadJson [filename] [json key]
|
||||
# Result: Sets 'readjsonvalue' to the value of the provided json key
|
||||
# Note: this method may return unexpected results if there are duplicate
|
||||
# keys in the json
|
||||
function ReadJson {
|
||||
local unamestr="$(uname)"
|
||||
local sedextended='-r'
|
||||
if [[ "$unamestr" == 'Darwin' ]]; then
|
||||
sedextended='-E'
|
||||
fi;
|
||||
|
||||
readjsonvalue="$(grep -m 1 "\"${2}\"" ${1} | sed ${sedextended} 's/^ *//;s/.*: *"//;s/",?//')"
|
||||
if [[ ! "$readjsonvalue" ]]; then
|
||||
echo "Error: Cannot find \"${2}\" in ${1}" >&2;
|
||||
ExitWithExitCode 1
|
||||
fi;
|
||||
}
|
||||
|
||||
function InstallDotNetCli {
|
||||
local dotnetinstallverbosity=''
|
||||
|
||||
ReadJson "$globaljsonfile" "version"
|
||||
local dotnetcliversion="$readjsonvalue"
|
||||
|
||||
if [[ -z "$DOTNET_INSTALL_DIR" ]]; then
|
||||
export DOTNET_INSTALL_DIR="$reporoot/artifacts/.dotnet/$dotnetcliversion"
|
||||
fi
|
||||
|
||||
local dotnetroot="$DOTNET_INSTALL_DIR"
|
||||
local dotnetinstallscript="$dotnetroot/dotnet-install.sh"
|
||||
|
||||
if [[ ! -a "$dotnetinstallscript" ]]; then
|
||||
mkdir -p "$dotnetroot"
|
||||
|
||||
# Use curl if available, otherwise use wget
|
||||
if command -v curl > /dev/null; then
|
||||
curl "https://dot.net/v1/dotnet-install.sh" -sSL --retry 10 --create-dirs -o "$dotnetinstallscript"
|
||||
else
|
||||
wget -q -O "$dotnetinstallscript" "https://dot.net/v1/dotnet-install.sh"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$(echo $verbosity | awk '{print tolower($0)}')" == 'diagnostic' ]]; then
|
||||
dotnetinstallverbosity="--verbose"
|
||||
fi
|
||||
|
||||
# Install a stage 0
|
||||
local sdkinstalldir="$dotnetroot/sdk/$dotnetcliversion"
|
||||
|
||||
if [[ ! -d "$sdkinstalldir" ]]; then
|
||||
bash "$dotnetinstallscript" --version $dotnetcliversion $dotnetinstallverbosity
|
||||
local lastexitcode=$?
|
||||
|
||||
if [[ $lastexitcode != 0 ]]; then
|
||||
echo "Failed to install stage0"
|
||||
ExitWithExitCode $lastexitcode
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install 1.0 shared framework
|
||||
local netcoreappversion='1.0.5'
|
||||
local netcoreapp10dir="$dotnetroot/shared/Microsoft.NETCore.App/$netcoreappversion"
|
||||
|
||||
if [[ ! -d "$netcoreapp10dir" ]]; then
|
||||
bash "$dotnetinstallscript" --channel "Preview" --version $netcoreappversion --shared-runtime $dotnetinstallverbosity
|
||||
lastexitcode=$?
|
||||
|
||||
if [[ $lastexitcode != 0 ]]; then
|
||||
echo "Failed to install 1.0 shared framework"
|
||||
ExitWithExitCode $lastexitcode
|
||||
fi
|
||||
fi
|
||||
|
||||
# Put the stage 0 on the path
|
||||
export PATH="$dotnetroot:"$PATH""
|
||||
|
||||
# Disable first run since we want to control all package sources
|
||||
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
|
||||
|
||||
# Don't resolve runtime, shared framework, or SDK from other locations
|
||||
export DOTNET_MULTILEVEL_LOOKUP=0
|
||||
}
|
||||
|
||||
# This is a temporary workaround for https://github.com/Microsoft/msbuild/issues/2095 and
|
||||
# https://github.com/dotnet/cli/issues/6589
|
||||
# Currently, SDK's always get resolved to the global location, but we want our packages
|
||||
# to all be installed into a local folder (prevent machine contamination from global state).
|
||||
#
|
||||
# We are restoring all of our packages locally and setting nugetpackageroot to reference the
|
||||
# local location, but this breaks Custom SDK's which are expecting the SDK to be available
|
||||
# from the global user folder.
|
||||
function MakeGlobalSdkAvailableLocal {
|
||||
local repotoolsetsource="$defaultnugetpackageroot/roslyntools.repotoolset/$toolsetversion/"
|
||||
local repotoolsetdestination="$nugetpackageroot/roslyntools.repotoolset/$toolsetversion/"
|
||||
if [[ ! -d "$repotoolsetdestination" ]]; then
|
||||
cp -r $repotoolsetsource $repotoolsetdestination
|
||||
fi
|
||||
}
|
||||
|
||||
function InstallToolset {
|
||||
if [[ ! -d "$toolsetbuildproj" ]]; then
|
||||
local toolsetproj="$tempdir/_restore.csproj"
|
||||
mkdir -p "$tempdir"
|
||||
echo '<Project Sdk="RoslynTools.RepoToolset"><Target Name="NoOp"/></Project>' > $toolsetproj
|
||||
|
||||
dotnet msbuild $toolsetproj /t:NoOp /m /nologo /clp:Summary /warnaserror "/p:NuGetPackageRoot=$nugetpackageroot/" /v:$verbosity
|
||||
local lastexitcode=$?
|
||||
|
||||
if [[ $lastexitcode != 0 ]]; then
|
||||
echo "Failed to build $toolsetproj"
|
||||
ExitWithExitCode $lastexitcode
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function Build {
|
||||
InstallDotNetCli
|
||||
|
||||
if [[ "$prepareMachine" == true ]]; then
|
||||
mkdir -p "$nugetpackageroot"
|
||||
dotnet nuget locals all --clear
|
||||
local lastexitcode=$?
|
||||
|
||||
if [[ $lastexitcode != 0 ]]; then
|
||||
echo 'Failed to clear NuGet cache'
|
||||
ExitWithExitCode $lastexitcode
|
||||
fi
|
||||
fi
|
||||
|
||||
InstallToolset
|
||||
|
||||
if [[ "$officialbuild" == true ]]; then
|
||||
MakeGlobalSdkAvailableLocal
|
||||
fi
|
||||
|
||||
local logcmd=''
|
||||
if [[ "$ci" == true || "$log" == true ]] ; then
|
||||
mkdir -p $logdir
|
||||
logcmd="/bl:$logdir/Build.binlog"
|
||||
fi
|
||||
|
||||
if [[ -z $solution ]]; then
|
||||
solution="$reporoot/*.sln"
|
||||
fi
|
||||
|
||||
dotnet msbuild $toolsetbuildproj /m /nologo /clp:Summary /warnaserror \
|
||||
/v:$verbosity $logcmd /p:Configuration=$configuration /p:Projects=$solution /p:RepoRoot="$reporoot" \
|
||||
/p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci \
|
||||
/p:RestorePackagesPath="$nugetpackageroot/" /p:NuGetPackageRoot="$nugetpackageroot/" \
|
||||
$properties
|
||||
local lastexitcode=$?
|
||||
|
||||
if [[ $lastexitcode != 0 ]]; then
|
||||
echo "Failed to build $toolsetbuildproj"
|
||||
ExitWithExitCode $lastexitcode
|
||||
fi
|
||||
}
|
||||
|
||||
function ExitWithExitCode {
|
||||
if [[ "$ci" == true && "$prepareMachine" == true ]]; then
|
||||
StopProcesses
|
||||
fi
|
||||
exit $1
|
||||
}
|
||||
|
||||
function StopProcesses {
|
||||
echo "Killing running build processes..."
|
||||
pkill -9 "msbuild"
|
||||
pkill -9 "vbcscompiler"
|
||||
}
|
||||
|
||||
function Main {
|
||||
# HOME may not be defined in some scenarios, but it is required by NuGet
|
||||
if [[ -z $HOME ]]; then
|
||||
export HOME="$reporoot/artifacts/.home/"
|
||||
mkdir -p "$HOME"
|
||||
fi
|
||||
|
||||
if [[ $ci ]]; then
|
||||
mkdir -p "$tempdir"
|
||||
export TEMP="$tempdir"
|
||||
export TMP="$tempdir"
|
||||
fi
|
||||
|
||||
if [[ -z $NUGET_PACKAGES ]]; then
|
||||
if [[ "$officialbuild" == true ]]; then
|
||||
export NUGET_PACKAGES="$reporoot/packages"
|
||||
else
|
||||
export NUGET_PACKAGES="$HOME/.nuget/packages"
|
||||
fi
|
||||
fi
|
||||
nugetpackageroot=$NUGET_PACKAGES
|
||||
defaultnugetpackageroot="$HOME/.nuget/packages"
|
||||
|
||||
ReadJson $globaljsonfile "RoslynTools.RepoToolset"
|
||||
toolsetversion=$readjsonvalue
|
||||
|
||||
toolsetbuildproj="$nugetpackageroot/roslyntools.repotoolset/$toolsetversion/tools/Build.proj"
|
||||
|
||||
Build
|
||||
ExitWithExitCode $?
|
||||
}
|
||||
|
||||
Main
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source="${BASH_SOURCE[0]}"
|
||||
|
||||
# resolve $SOURCE until the file is no longer a symlink
|
||||
while [[ -h $source ]]; do
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
source="$(readlink "$source")"
|
||||
|
||||
# if $source was a relative symlink, we need to resolve it relative to the path where
|
||||
# the symlink file was located
|
||||
[[ $source != /* ]] && source="$scriptroot/$source"
|
||||
done
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
|
||||
. "$scriptroot/build.sh" --restore --build --test --ci $@
|
|
@ -3,6 +3,6 @@
|
|||
"version": "2.1.100-preview-007366"
|
||||
},
|
||||
"msbuild-sdks": {
|
||||
"RoslynTools.RepoToolset": "1.0.0-beta2-62626-02"
|
||||
"RoslynTools.RepoToolset": "1.0.0-beta2-62723-01"
|
||||
}
|
||||
}
|
||||
|
|
27
netci.groovy
27
netci.groovy
|
@ -29,28 +29,31 @@ static addXUnitDotNETResults(def job, def configName) {
|
|||
Utilities.addXUnitDotNETResults(job, resultFilePattern, skipIfNoTestFiles)
|
||||
}
|
||||
|
||||
static addBuildSteps(def job, def projectName, def opsysName, def configName, def isPR) {
|
||||
def buildJobName = getJobName(opsysName, configName)
|
||||
static addBuildSteps(def job, def projectName, def os, def configName, def isPR) {
|
||||
def buildJobName = getJobName(os, configName)
|
||||
def buildFullJobName = Utilities.getFullJobName(projectName, buildJobName, isPR)
|
||||
|
||||
job.with {
|
||||
steps {
|
||||
batchFile(""".\\CIBuild.cmd -configuration ${configName} -prepareMachine""")
|
||||
if (os == "Windows_NT") {
|
||||
batchFile(""".\\eng\\common\\CIBuild.cmd -configuration ${configName} -prepareMachine""")
|
||||
} else {
|
||||
shell("./eng/common/cibuild.sh --configuration ${configName} --prepareMachine")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[true, false].each { isPR ->
|
||||
['windows'].each { opsysName ->
|
||||
['debug', 'release'].each { configName ->
|
||||
['Windows_NT'].each { os ->
|
||||
['Debug', 'Release'].each { configName ->
|
||||
def projectName = GithubProject
|
||||
|
||||
def branchName = GithubBranchName
|
||||
|
||||
def filesToArchive = "**/artifacts/${configName}/**"
|
||||
def filesToExclude = "**/artifacts/${configName}/obj/**"
|
||||
|
||||
def jobName = getJobName(opsysName, configName)
|
||||
def jobName = getJobName(os, configName)
|
||||
def fullJobName = Utilities.getFullJobName(projectName, jobName, isPR)
|
||||
def myJob = job(fullJobName)
|
||||
|
||||
|
@ -62,12 +65,16 @@ static addBuildSteps(def job, def projectName, def opsysName, def configName, de
|
|||
Utilities.addGithubPushTrigger(myJob)
|
||||
}
|
||||
|
||||
addArchival(myJob, filesToArchive, filesToExclude)
|
||||
addArchival(myJob, filesToArchive, "")
|
||||
addXUnitDotNETResults(myJob, configName)
|
||||
|
||||
Utilities.setMachineAffinity(myJob, 'Windows_NT', 'latest-dev15-3')
|
||||
if (os == 'Windows_NT') {
|
||||
Utilities.setMachineAffinity(myJob, os, 'latest-dev15-3')
|
||||
} else {
|
||||
Utilities.setMachineAffinity(myJob, os, 'latest-or-auto')
|
||||
}
|
||||
|
||||
addBuildSteps(myJob, projectName, opsysName, configName, isPR)
|
||||
addBuildSteps(myJob, projectName, os, configName, isPR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<Import Project="..\Directory.Build.props"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<LangVersion>Latest</LangVersion>
|
||||
|
||||
<!--
|
||||
TODO: Can't use embedded PDBs with LUT:
|
||||
|
|
Загрузка…
Ссылка в новой задаче