diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 6fe393a60..db8b04ad3 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -46,10 +46,10 @@ stages: pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: name: NetCorePublic-Pool - queue: buildpool.windows.10.amd64.vs2017.open + queue: buildpool.windows.10.amd64.vs2019.open ${{ if eq(variables['System.TeamProject'], 'internal') }}: name: NetCoreInternal-Pool - queue: buildpool.windows.10.amd64.vs2017 + queue: buildpool.windows.10.amd64.vs2019 timeoutInMinutes: 180 strategy: matrix: @@ -103,10 +103,10 @@ stages: pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: name: NetCorePublic-Pool - queue: buildpool.windows.10.amd64.vs2017.open + queue: buildpool.windows.10.amd64.vs2019.open ${{ if eq(variables['System.TeamProject'], 'internal') }}: name: NetCoreInternal-Pool - queue: buildpool.windows.10.amd64.vs2017 + queue: buildpool.windows.10.amd64.vs2019 timeoutInMinutes: 180 strategy: matrix: @@ -339,6 +339,12 @@ stages: # Never run tests on arm64 _TestArg: '' + - template: /eng/common/templates/job/source-build.yml + parameters: + platform: + name: 'Managed' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343' + # https://github.com/dotnet/core-sdk/issues/248 # - template: /eng/build.yml # parameters: diff --git a/Native.sln b/Native.sln new file mode 100644 index 000000000..7ce79b609 --- /dev/null +++ b/Native.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28603.18 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED2FE3E2-F7E7-4389-8231-B65123F2076F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "finalizer_shim", "src\finalizer_shim\finalizer_shim.csproj", "{688E2883-C5A9-4D66-A207-772C9160989C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Debug|x64 = Debug|x64 + Debug|arm64 = Debug|arm64 + Release|x86 = Release|x86 + Release|x64 = Release|x64 + Release|arm64 = Release|arm64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x86.ActiveCfg = Debug|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x86.Build.0 = Debug|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x64.ActiveCfg = Debug|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|x64.Build.0 = Debug|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|arm64.ActiveCfg = Debug|arm64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Debug|arm64.Build.0 = Debug|arm64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x86.ActiveCfg = Release|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x86.Build.0 = Release|x86 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x64.ActiveCfg = Release|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|x64.Build.0 = Release|x64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|arm64.ActiveCfg = Release|arm64 + {688E2883-C5A9-4D66-A207-772C9160989C}.Release|arm64.Build.0 = Release|arm64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {688E2883-C5A9-4D66-A207-772C9160989C} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {18FCFCA3-D1A8-4D3A-9763-6A658D0D726F} + EndGlobalSection +EndGlobal diff --git a/eng/Build.props b/eng/Build.props new file mode 100644 index 000000000..917aa8993 --- /dev/null +++ b/eng/Build.props @@ -0,0 +1,8 @@ + + + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2fac17ae1..1ffb8e4bd 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -13,25 +13,25 @@ https://github.com/dotnet/windowsdesktop 9570a321daf2bd6756b91a0866bb8e0d7874190d - + https://github.com/dotnet/runtime - 41f3d48b520d4cf4f9e051dc07f480dcb9c62e08 + 65020c946254c9a99497f4fdfa4136131f51f913 - + https://github.com/dotnet/runtime - 41f3d48b520d4cf4f9e051dc07f480dcb9c62e08 + 65020c946254c9a99497f4fdfa4136131f51f913 - + https://github.com/dotnet/runtime - 41f3d48b520d4cf4f9e051dc07f480dcb9c62e08 + 65020c946254c9a99497f4fdfa4136131f51f913 - + https://github.com/dotnet/runtime - 41f3d48b520d4cf4f9e051dc07f480dcb9c62e08 + 65020c946254c9a99497f4fdfa4136131f51f913 - + https://github.com/dotnet/runtime - 41f3d48b520d4cf4f9e051dc07f480dcb9c62e08 + 65020c946254c9a99497f4fdfa4136131f51f913 @@ -39,33 +39,33 @@ https://github.com/dotnet/core-setup 7d57652f33493fa022125b7f63aad0d70c52d810 - + https://github.com/dotnet/runtime - 41f3d48b520d4cf4f9e051dc07f480dcb9c62e08 + 65020c946254c9a99497f4fdfa4136131f51f913 - + https://github.com/dotnet/aspnetcore - 4681108d2877be20acf73fcfa8fb6cb31c8db6d9 + 665ea2f868d916693ad1e243959349fa8e6d9647 - + https://github.com/dotnet/aspnetcore - 4681108d2877be20acf73fcfa8fb6cb31c8db6d9 + 665ea2f868d916693ad1e243959349fa8e6d9647 - + https://github.com/dotnet/aspnetcore - 4681108d2877be20acf73fcfa8fb6cb31c8db6d9 + 665ea2f868d916693ad1e243959349fa8e6d9647 - + https://github.com/dotnet/aspnetcore - 4681108d2877be20acf73fcfa8fb6cb31c8db6d9 + 665ea2f868d916693ad1e243959349fa8e6d9647 - + https://github.com/dotnet/aspnetcore - 4681108d2877be20acf73fcfa8fb6cb31c8db6d9 + 665ea2f868d916693ad1e243959349fa8e6d9647 - + https://github.com/dotnet/aspnetcore - 4681108d2877be20acf73fcfa8fb6cb31c8db6d9 + 665ea2f868d916693ad1e243959349fa8e6d9647 https://github.com/dotnet/test-templates @@ -79,17 +79,17 @@ https://github.com/dotnet/test-templates 36a1b45f75489255f2d1770acd2d78c5002d4679 - + https://github.com/dotnet/templating - 254a4c63afcd94b221408c6e8d245b90802551eb + 7e14ef44c849e230176477bf271ceab3db74ea7e - + https://github.com/dotnet/sdk - fc6dfaac882ce1229406a1087b22e852378b8319 + 2a3aa0c04c5e047425c25a463a326e1c4a4d43dd - + https://github.com/dotnet/sdk - fc6dfaac882ce1229406a1087b22e852378b8319 + 2a3aa0c04c5e047425c25a463a326e1c4a4d43dd @@ -100,30 +100,30 @@ https://github.com/dotnet/wpf 40775430dc86d110ba7b83ca5a898b8f4e9335e7 - + https://github.com/dotnet/fsharp - 9588f1d472ac8227796dca34ff76dfe136bb4bd7 + a999919d71f838451607deeab656d094b2d13e04 - + https://github.com/microsoft/vstest - 2233e0bdc7ca37eecee62eec848adcafca81024d + 5a4a4c064ec8a0e9ccb02354e0137c3264cc8fb5 - + https://github.com/mono/linker - e48f540b753d2aa5f5d4c22f4bbc41aba130345b + 4afa1051f5e44560368aacb21429e956ce39cc1a linker - + https://github.com/dotnet/roslyn - 84e6ff97a24ba7e74fd89e61da54487a8535ceed + 7b996850bb82a370ca74c3f57e0a4d4df1c90049 - + https://github.com/dotnet/msbuild - 4f72ae4cfb09d03dccd7fc628d619ef4ab5aa479 + fa96a2a81e0fb8c028057fa204bbf386bfb36aec - + https://github.com/nuget/nuget.client - d2bb0de35242b04802c1a7856ebb7718f674565c + dca1d060f38e1e02f6bfca41e25f081f19fd534b https://github.com/Microsoft/ApplicationInsights-dotnet @@ -136,26 +136,26 @@ - + https://github.com/dotnet/arcade - b7279bb45342c948ab46fea2d08ec17ae2f2a1bf + 0cfaf935894a4c98ff7445c903f1b4c32990b127 - + https://github.com/dotnet/arcade - b7279bb45342c948ab46fea2d08ec17ae2f2a1bf + 0cfaf935894a4c98ff7445c903f1b4c32990b127 https://github.com/dotnet/source-build-reference-packages 639aeb4d76c8b1a6226bf7c4edb34fbdae30e6e1 - + https://github.com/dotnet/sourcelink 4b584dbc392bb1aad49c2eb1ab84d8b489b6dccc - + https://github.com/dotnet/xliff-tasks - e92cb4fc57ecfa244930cdd6d98270f185650462 + 59ce967675b3600c2de41443483949d86305de93 diff --git a/eng/Versions.props b/eng/Versions.props index 7ba581631..3ce6a8909 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -20,7 +20,7 @@ - 6.0.0-beta.21222.1 + 6.0.0-beta.21254.3 @@ -32,7 +32,7 @@ - 6.0.100-preview.5.21228.2 + 6.0.100-preview.5.21253.2 @@ -45,35 +45,35 @@ - 6.0.0-preview.5.21226.3 - 6.0.0-preview.5.21226.3 - 6.0.0-preview.5.21226.3 - 6.0.0-preview.5.21226.3 - 6.0.0-preview.5.21226.3 - 6.0.0-preview.5.21226.3 + 6.0.0-preview.5.21254.21 + 6.0.0-preview.5.21254.21 + 6.0.0-preview.5.21254.21 + 6.0.0-preview.5.21254.21 + 6.0.0-preview.5.21254.21 + 6.0.0-preview.5.21254.21 0.2.0 - 6.0.100-preview.5.21228.4 - 6.0.100-preview.5.21228.4 + 6.0.100-preview.5.21255.5 + 6.0.100-preview.5.21255.5 $(MicrosoftNETSdkPackageVersion) $(MicrosoftNETSdkPackageVersion) $(MicrosoftNETSdkPackageVersion) - 6.0.0-preview.5.21227.7 + 6.0.0-preview.5.21254.12 - 6.0.0-preview.5.21227.7 - 6.0.0-preview.5.21227.7 - 6.0.0-preview.5.21227.7 - 6.0.0-preview.5.21227.7 - 6.0.0-preview.5.21227.7 + 6.0.0-preview.5.21254.12 + 6.0.0-preview.5.21254.12 + 6.0.0-preview.5.21254.12 + 6.0.0-preview.5.21254.12 + 6.0.0-preview.5.21254.12 2.1.0 @@ -99,6 +99,9 @@ $(MicrosoftNETCoreAppRuntimePackageVersion) $(MicrosoftNETCoreAppRuntimePackageVersion) + + 3.14.0-dotnet + $(MicrosoftDotnetWinFormsProjectTemplatesPackageVersion) @@ -142,15 +145,15 @@ 2.2.0-beta.19072.10 2.0.0 - 17.0.0-preview-20210427-01 + 17.0.0-preview-20210504-01 - 11.0.200-preview.4.232 - 14.5.100-preview.4.623 - 14.5.100-preview.4.623 - 11.3.100-preview.4.623 - 14.5.100-preview.4.623 + 11.0.200-preview.4.245 + 14.5.100-preview.4.633 + 14.5.100-preview.4.633 + 11.3.100-preview.4.633 + 14.5.100-preview.4.633 $(MicrosoftAspNetCoreAppRuntimePackageVersion) diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index 81e641a57..df0dfa578 100755 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -78,6 +78,10 @@ __IllumosPackages+=" openssl-1.1.1e" __IllumosPackages+=" zlib-1.2.11" __IllumosPackages+=" openldap-client-2.4.49" +# ML.NET dependencies +__UbuntuPackages+=" libomp5" +__UbuntuPackages+=" libomp-dev" + __UseMirror=0 __UnprocessedBuildArgs= diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1 index 1c46f7b63..8c554729b 100644 --- a/eng/common/post-build/sourcelink-validation.ps1 +++ b/eng/common/post-build/sourcelink-validation.ps1 @@ -14,7 +14,7 @@ param( $global:RepoFiles = @{} # Maximum number of jobs to run in parallel -$MaxParallelJobs = 6 +$MaxParallelJobs = 16 # Wait time between check for system load $SecondsBetweenLoadChecks = 10 diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index 99bf28cd5..788321d77 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -1,13 +1,14 @@ param( - [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored - [Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation - [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use - [Parameter(Mandatory=$false)][switch] $ContinueOnError, # If we should keep checking symbols after an error - [Parameter(Mandatory=$false)][switch] $Clean # Clean extracted symbols directory after checking symbols + [Parameter(Mandatory = $true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored + [Parameter(Mandatory = $true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation + [Parameter(Mandatory = $true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use + [Parameter(Mandatory = $false)][switch] $CheckForWindowsPdbs, # If we should check for the existence of windows pdbs in addition to portable PDBs + [Parameter(Mandatory = $false)][switch] $ContinueOnError, # If we should keep checking symbols after an error + [Parameter(Mandatory = $false)][switch] $Clean # Clean extracted symbols directory after checking symbols ) # Maximum number of jobs to run in parallel -$MaxParallelJobs = 6 +$MaxParallelJobs = 16 # Max number of retries $MaxRetry = 5 @@ -19,9 +20,15 @@ $SecondsBetweenLoadChecks = 10 Set-Variable -Name "ERROR_BADEXTRACT" -Option Constant -Value -1 Set-Variable -Name "ERROR_FILEDOESNOTEXIST" -Option Constant -Value -2 +$WindowsPdbVerificationParam = "" +if ($CheckForWindowsPdbs) { + $WindowsPdbVerificationParam = "--windows-pdbs" +} + $CountMissingSymbols = { param( - [string] $PackagePath # Path to a NuGet package + [string] $PackagePath, # Path to a NuGet package + [string] $WindowsPdbVerificationParam # If we should check for the existence of windows pdbs in addition to portable PDBs ) . $using:PSScriptRoot\..\tools.ps1 @@ -34,7 +41,7 @@ $CountMissingSymbols = { if (!(Test-Path $PackagePath)) { Write-PipelineTaskError "Input file does not exist: $PackagePath" return [pscustomobject]@{ - result = $using:ERROR_FILEDOESNOTEXIST + result = $using:ERROR_FILEDOESNOTEXIST packagePath = $PackagePath } } @@ -57,24 +64,25 @@ $CountMissingSymbols = { Write-Host "Something went wrong extracting $PackagePath" Write-Host $_ return [pscustomobject]@{ - result = $using:ERROR_BADEXTRACT + result = $using:ERROR_BADEXTRACT packagePath = $PackagePath } } Get-ChildItem -Recurse $ExtractPath | - Where-Object {$RelevantExtensions -contains $_.Extension} | - ForEach-Object { - $FileName = $_.FullName - if ($FileName -Match '\\ref\\') { - Write-Host "`t Ignoring reference assembly file " $FileName - return - } + Where-Object { $RelevantExtensions -contains $_.Extension } | + ForEach-Object { + $FileName = $_.FullName + if ($FileName -Match '\\ref\\') { + Write-Host "`t Ignoring reference assembly file " $FileName + return + } - $FirstMatchingSymbolDescriptionOrDefault = { + $FirstMatchingSymbolDescriptionOrDefault = { param( - [string] $FullPath, # Full path to the module that has to be checked - [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols + [string] $FullPath, # Full path to the module that has to be checked + [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols + [string] $WindowsPdbVerificationParam, # Parameter to pass to potential check for windows-pdbs. [string] $SymbolsPath ) @@ -99,7 +107,7 @@ $CountMissingSymbols = { # DWARF file for a .dylib $DylibDwarf = $SymbolPath.Replace($Extension, '.dylib.dwarf') - + $dotnetSymbolExe = "$env:USERPROFILE\.dotnet\tools" $dotnetSymbolExe = Resolve-Path "$dotnetSymbolExe\dotnet-symbol.exe" @@ -107,7 +115,7 @@ $CountMissingSymbols = { while ($totalRetries -lt $using:MaxRetry) { # Save the output and get diagnostic output - $output = & $dotnetSymbolExe --symbols --modules --windows-pdbs $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String + $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String if (Test-Path $PdbPath) { return 'PDB' @@ -136,30 +144,30 @@ $CountMissingSymbols = { return $null } - $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--microsoft-symbol-server' $SymbolsPath - $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--internal-server' $SymbolsPath + $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--microsoft-symbol-server' $SymbolsPath $WindowsPdbVerificationParam + $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--internal-server' $SymbolsPath $WindowsPdbVerificationParam - Write-Host -NoNewLine "`t Checking file " $FileName "... " + Write-Host -NoNewLine "`t Checking file " $FileName "... " - if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) { - Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)" + if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) { + Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)" + } + else { + $MissingSymbols++ + + if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) { + Write-Host 'No symbols found on MSDL or SymWeb!' } else { - $MissingSymbols++ - - if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) { - Write-Host 'No symbols found on MSDL or SymWeb!' + if ($SymbolsOnMSDL -eq $null) { + Write-Host 'No symbols found on MSDL!' } else { - if ($SymbolsOnMSDL -eq $null) { - Write-Host 'No symbols found on MSDL!' - } - else { - Write-Host 'No symbols found on SymWeb!' - } + Write-Host 'No symbols found on SymWeb!' } } } + } if ($using:Clean) { Remove-Item $ExtractPath -Recurse -Force @@ -168,16 +176,16 @@ $CountMissingSymbols = { Pop-Location return [pscustomobject]@{ - result = $MissingSymbols - packagePath = $PackagePath - } + result = $MissingSymbols + packagePath = $PackagePath + } } function CheckJobResult( - $result, - $packagePath, - [ref]$DupedSymbols, - [ref]$TotalFailures) { + $result, + $packagePath, + [ref]$DupedSymbols, + [ref]$TotalFailures) { if ($result -eq $ERROR_BADEXTRACT) { Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$packagePath has duplicated symbol files" $DupedSymbols.Value++ @@ -222,7 +230,7 @@ function CheckSymbolsAvailable { return } - Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList $FullName | Out-Null + Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList @($FullName,$WindowsPdbVerificationParam) | Out-Null $NumJobs = @(Get-Job -State 'Running').Count diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index d2b271ec1..958db4064 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -12,11 +12,13 @@ parameters: SourcesDirectory: $(Build.SourcesDirectory) CreatePr: true AutoCompletePr: false + UseLfLineEndings: true UseCheckedInLocProjectJson: false LanguageSet: VS_Main_Languages LclSource: lclFilesInRepo LclPackageId: '' RepoType: gitHub + condition: '' jobs: - job: OneLocBuild @@ -44,6 +46,7 @@ jobs: filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1 arguments: $(_GenerateLocProjectArguments) displayName: Generate LocProject.json + condition: ${{ parameters.condition }} - task: OneLocBuild@2 displayName: OneLocBuild @@ -57,12 +60,13 @@ jobs: isCreatePrSelected: ${{ parameters.CreatePr }} ${{ if eq(parameters.CreatePr, true) }}: isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} + isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} packageSourceAuth: patAuth patVariable: ${{ parameters.CeapexPat }} ${{ if eq(parameters.RepoType, 'gitHub') }}: repoType: ${{ parameters.RepoType }} gitHubPatVariable: "${{ parameters.GithubPat }}" - condition: always() + condition: ${{ parameters.condition }} - task: PublishBuildArtifacts@1 displayName: Publish Localization Files @@ -70,7 +74,7 @@ jobs: PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc' PublishLocation: Container ArtifactName: Loc - condition: always() + condition: ${{ parameters.condition }} - task: PublishBuildArtifacts@1 displayName: Publish LocProject.json @@ -78,4 +82,4 @@ jobs: PathtoPublish: '$(Build.SourcesDirectory)/Localize/' PublishLocation: Container ArtifactName: Loc - condition: always() \ No newline at end of file + condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/eng/configure-toolset.ps1 b/eng/configure-toolset.ps1 index 87375243e..c6cc32f0c 100644 --- a/eng/configure-toolset.ps1 +++ b/eng/configure-toolset.ps1 @@ -2,3 +2,5 @@ $script:useInstalledDotNetCli = $false +# Add CMake to the path. +$env:PATH = "$PSScriptRoot\..\.tools\bin;$env:PATH" diff --git a/eng/configure-toolset.sh b/eng/configure-toolset.sh index d890b1b02..1e0b58a36 100644 --- a/eng/configure-toolset.sh +++ b/eng/configure-toolset.sh @@ -1,3 +1,6 @@ # SdkTests do not currently work with globally installed CLI as they use dotnet-install.ps1 to install more runtimes -useInstalledDotNetCli="false" \ No newline at end of file +useInstalledDotNetCli="false" + +# Working around issue https://github.com/dotnet/arcade/issues/7327 +DisableNativeToolsetInstalls=true \ No newline at end of file diff --git a/eng/native.proj b/eng/native.proj new file mode 100644 index 000000000..736b175c3 --- /dev/null +++ b/eng/native.proj @@ -0,0 +1,16 @@ + + + + $(Architecture) + + + + + + + + + + + + diff --git a/eng/version.csproj b/eng/version.csproj new file mode 100644 index 000000000..c745a3474 --- /dev/null +++ b/eng/version.csproj @@ -0,0 +1,8 @@ + + + $(CoreSdkTargetFramework) + $(ArtifactsObjDir)sdk_version.h + + + + diff --git a/global.json b/global.json index 3a0eae9da..5d25c17d1 100644 --- a/global.json +++ b/global.json @@ -7,7 +7,11 @@ ] } }, + "native-tools": { + "cmake": "3.16.4" + }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21222.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21254.3", + "Microsoft.DotNet.CMake.Sdk": "6.0.0-beta.21253.2" } } diff --git a/src/finalizer/CMakeLists.txt b/src/finalizer/CMakeLists.txt new file mode 100644 index 000000000..fe1b531ea --- /dev/null +++ b/src/finalizer/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.15.5) + +# Create project named finalizer, this will +# will generate Finalizer.vcxproj +project(Finalizer) + +set(CMAKE_MACOSX_RPATH 1) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:wmainCRTStartup") + +# The WiX SDK is extracted from a NuGet package using an SDK .csproj (finalizer_shim) +# that copies the "lib" and "inc" folders to a stable location. + +include_directories(../../artifacts/WixSdk/inc) +include_directories(../../artifacts/obj) +link_directories(../../artifacts/WixSdk/lib/${Platform}) + +add_compile_options(/MT) + +add_executable(Finalizer + finalizer.cpp + native.rc +) + +# These are normally part of a .vcxproj in Visual Studio, but +# appears to be missing when CMAKE generates a .vcxproj +# for arm64. +target_link_libraries(Finalizer shell32.lib) +target_link_libraries(Finalizer advapi32.lib) +target_link_libraries(Finalizer version.lib) +target_link_libraries(Finalizer msi.lib) + +# Add WiX libraries +target_link_libraries(Finalizer wcautil.lib) +target_link_libraries(Finalizer dutil.lib) + +install(TARGETS Finalizer) diff --git a/src/finalizer/finalizer.cpp b/src/finalizer/finalizer.cpp new file mode 100644 index 000000000..5860d3df0 --- /dev/null +++ b/src/finalizer/finalizer.cpp @@ -0,0 +1,211 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "precomp.h" + +extern "C" HRESULT Initialize(int argc, wchar_t* argv[]) +{ + HRESULT hr = S_OK; + + // We're not going to do any clever parsing. This is intended to be called from + // the standalone bundle only and there will only be two parameters: + // 1. The path of the log file, created by the bundle. + // 2. The dependent we're trying to clean up. + if (argc != 3) + { + return HRESULT_FROM_WIN32(ERROR_INVALID_COMMAND_LINE); + } + + LogInitialize(::GetModuleHandleW(NULL)); + +#ifdef _DEBUG + LogSetLevel(REPORT_DEBUG, FALSE); +#else + LogSetLevel(REPORT_VERBOSE, FALSE); // FALSE means don't write an additional text line to the log saying the level changed +#endif + + hr = LogOpen(NULL, argv[1], NULL, NULL, FALSE, TRUE, NULL); + ExitOnFailure(hr, "Failed to create log file."); + + hr = RegInitialize(); + ExitOnFailure(hr, "Failed to initialize the registry."); + + hr = WiuInitialize(); + ExitOnFailure(hr, "Failed to initialize Windows Installer."); + +LExit: + return hr; +} + +extern "C" HRESULT RemoveDependent(LPWSTR sczDependent, BOOL* pbRestartRequired) +{ + HRESULT hr = S_OK; + HKEY hkInstallerDependenciesKey = NULL; + HKEY hkProviderKey = NULL; + HKEY hkDependentsKey = NULL; + LPWSTR sczProviderKey = NULL; + LPWSTR sczDependentsKey = NULL; + LPWSTR sczProductId = NULL; + LPWSTR sczProductName = NULL; + DWORD cSubKeys = 0; + DWORD dwExitCode = 0; + WIU_RESTART restart = WIU_RESTART_NONE; + + // Optional workloads are always per-machine installs, so we don't need to check HKCU. + hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Classes\\Installer\\Dependencies", KEY_READ, &hkInstallerDependenciesKey); + ExitOnFailure(hr, "Failed to read installer dependencies key."); + + // This has to be an exhaustive search as we're not looking for a specific provider key, but for a specific dependent + // that could be registered against any provider key. + for (DWORD dwIndex = 0;; ++dwIndex) + { + // Get the next provider key name + hr = RegKeyEnum(hkInstallerDependenciesKey, dwIndex, &sczProviderKey); + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + break; + } + + ExitOnFailure(hr, "Failed to enumerate installer dependency provider keys."); + LogStringLine(REPORT_STANDARD, "Processing provider key: %ls", sczProviderKey); + + hr = RegOpen(hkInstallerDependenciesKey, sczProviderKey, KEY_READ, &hkProviderKey); + ExitOnFailure(hr, "Unable to open provider key."); + + // Open the dependents key with write permissions so we can modify it if it matches + // the target dependent value. + hr = RegOpen(hkProviderKey, L"Dependents", KEY_READ | KEY_WRITE, &hkDependentsKey); + if (E_FILENOTFOUND == hr) + { + // Providers can sometimes become orphaned duirng uninstalls. If there's no Dependents subkey, we just + // release the handle and continue to the next provider key. + hr = S_OK; + ReleaseRegKey(hkProviderKey); + + continue; + } + + ExitOnFailure(hr, "Unable to open dependents key."); + + // Enumerate over all the dependent keys + for (DWORD dwDepdentsKeyIndex = 0;; ++dwDepdentsKeyIndex) + { + hr = RegKeyEnum(hkDependentsKey, dwDepdentsKeyIndex, &sczDependentsKey); + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + break; + } + + ExitOnFailure(hr, "Failed to read provider's dependent key."); + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczDependentsKey, -1, sczDependent, -1)) + { + LogStringLine(REPORT_STANDARD, " Dependent match found: %ls", sczDependentsKey); + + hr = RegDelete(hkDependentsKey, sczDependent, REG_KEY_DEFAULT, TRUE); + ExitOnFailure(hr, "Failed to delete dependent \"%ls\"", sczDependent); + LogStringLine(REPORT_STANDARD, " Dependent deleted"); + // Reset the index since we're deleting keys while enumerating + dwDepdentsKeyIndex = dwDepdentsKeyIndex > 1 ? dwDepdentsKeyIndex-- : 0; + + // Check if there are any subkeys remaining under the dependents key. If not, we + // can uninstall the MSI. We'll recheck the key again in case the MSI fails to clean up the + // provider key to make sure we don't have orphaned keys. + hr = RegQueryKey(hkDependentsKey, &cSubKeys, NULL); + ExitOnFailure(hr, "Failed to query dependents key."); + + LogStringLine(REPORT_STANDARD, " Remaining dependents: %i", cSubKeys); + + if (0 == cSubKeys) + { + // This was the final dependent, so now we can remove the installation if the provider wasn't corrupted and + // still contains the product ID. + hr = RegReadString(hkProviderKey, NULL, &sczProductId); + + if (E_FILENOTFOUND == hr) + { + LogStringLine(REPORT_STANDARD, " No product ID found, provider key: %ls", sczProviderKey); + hr = S_OK; + break; + } + else + { + ExitOnFailure(hr, "Failed to read product ID."); + } + + // Let's make sure the product is actually installed. The provider key for an MSI typically + // stores the ProductCode, DisplayName, and Version, but by calling into MsiGetProductInfo, + // we're doing an implicit detect and getting a property back. + hr = WiuGetProductInfo(sczProductId, L"ProductName", &sczProductName); + if (SUCCEEDED(hr)) + { + // The provider key *should* have the ProductName and ProductVersion properties, but since + // we know it's installed, we just query the installer service. + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + hr = WiuConfigureProductEx(sczProductId, INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, L"MSIFASTINSTALL=7 IGNOREDEPENDENCIES=ALL REBOOT=ReallySuppress", &restart); + LogStringLine(REPORT_STANDARD, " Uninstall of \"%ls\" (%ls%) exited with 0x%.8x", sczProductName, sczProductId, hr); + + // Flag any reboot since we need to return that to the bundle. + if (WIU_RESTART_INITIATED == restart || WIU_RESTART_REQUIRED == restart) + { + LogStringLine(REPORT_STANDARD, " Reboot requested, deferring."); + *pbRestartRequired = TRUE; + } + + // Reset potential failures so we can continue to remove as many dependents as possible. + hr = S_OK; + } + else if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) == hr) + { + // Possibly a corrupted provider key that wasn't cleaned up. We'll just ignore it. + LogStringLine(REPORT_STANDARD, " Product is not installed, ProductCode:%ls, result: 0x%.8x", sczProductId, hr); + hr = S_OK; + } + } + } + } + + ReleaseRegKey(hkDependentsKey); + ReleaseRegKey(hkProviderKey); + } + +LExit: + ReleaseStr(sczProductName); + ReleaseStr(sczProductId); + ReleaseStr(sczProviderKey); + ReleaseStr(sczDependentsKey); + ReleaseRegKey(hkDependentsKey); + ReleaseRegKey(hkProviderKey); + ReleaseRegKey(hkInstallerDependenciesKey); + return hr; +} + +int wmain(int argc, wchar_t* argv[]) +{ + HRESULT hr = S_OK; + DWORD dwExitCode = 0; + LPWSTR sczDependent = NULL; + BOOL bRestartRequired = FALSE; + + hr = ::Initialize(argc, argv); + ExitOnFailure(hr, "Failed to initialize."); + + sczDependent = argv[2]; + hr = ::RemoveDependent(sczDependent, &bRestartRequired); + ExitOnFailure(hr, "Failed to remove dependent \"%ls\".", sczDependent); + + if (bRestartRequired) + { + dwExitCode = ERROR_SUCCESS_REBOOT_REQUIRED; + } + +LExit: + LogUninitialize(TRUE); + RegUninitialize(); + WiuUninitialize(); + return FAILED(hr) ? (int)hr : (int)dwExitCode; +} diff --git a/src/finalizer/finalizer.proj b/src/finalizer/finalizer.proj new file mode 100644 index 000000000..463a37a14 --- /dev/null +++ b/src/finalizer/finalizer.proj @@ -0,0 +1,14 @@ + + + CMakeLists.txt + + + + + + + + diff --git a/src/finalizer/native.rc b/src/finalizer/native.rc new file mode 100644 index 000000000..bea8f0b52 Binary files /dev/null and b/src/finalizer/native.rc differ diff --git a/src/finalizer/precomp.h b/src/finalizer/precomp.h new file mode 100644 index 000000000..92e713d52 --- /dev/null +++ b/src/finalizer/precomp.h @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +// Configure some logging parameters for WiX +#define ExitTrace LogErrorString +#define ExitTrace1 LogErrorString +#define ExitTrace2 LogErrorString +#define ExitTrace3 LogErrorString + +// Includes from WiX SDK +#include "dutil.h" +#include "regutil.h" +#include "logutil.h" +#include "strutil.h" +#include "wiutil.h" diff --git a/src/finalizer_shim/finalizer_shim.csproj b/src/finalizer_shim/finalizer_shim.csproj new file mode 100644 index 000000000..1f378f56b --- /dev/null +++ b/src/finalizer_shim/finalizer_shim.csproj @@ -0,0 +1,35 @@ + + + + $(Architecture) + $(CoreSdkTargetFramework) + true + false + false + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/redist/targets/GenerateBundledVersions.targets b/src/redist/targets/GenerateBundledVersions.targets index 05b3d13af..d2e538306 100644 --- a/src/redist/targets/GenerateBundledVersions.targets +++ b/src/redist/targets/GenerateBundledVersions.targets @@ -46,11 +46,6 @@ <_AspNet50RuntimePackVersion>5.0.5 <_AspNet50TargetingPackVersion>5.0.0 - <_WindowsDesktop31RuntimePackVersion>3.1.12 - <_WindowsDesktop31TargetingPackVersion>3.1.0 - <_AspNet31RuntimePackVersion>3.1.14 - <_AspNet31TargetingPackVersion>3.1.10 - <_NETCoreApp30RuntimePackVersion>3.0.3 <_NETCoreApp30TargetingPackVersion>3.0.0 diff --git a/src/redist/targets/GenerateMSIs.targets b/src/redist/targets/GenerateMSIs.targets index 0c69a4db7..b3fbe8fab 100644 --- a/src/redist/targets/GenerateMSIs.targets +++ b/src/redist/targets/GenerateMSIs.targets @@ -27,6 +27,8 @@ $(MSBuildThisFileDirectory)packaging/windows/clisdk/generatebundle.ps1 $(MSBuildThisFileDirectory)packaging/windows/clisdk/generatenupkg.ps1 + $(ArtifactsDir)bin/finalizer/$(Architecture)/$(Configuration)/bin/finalizer.exe + $(MSBuildThisFileDirectory)packaging/windows/clisdk/VS.Redist.Common.NetCore.Toolset.nuspec $(ArtifactsNonShippingPackagesDir)VS.Redist.Common.NetCore.Toolset.$(Architecture).$(FullNugetVersion).nupkg $(MSBuildThisFileDirectory)packaging/windows/clisdk/VS.Redist.Common.NetCore.SdkPlaceholder.nuspec @@ -345,6 +347,7 @@ '$(DownloadsFolder)$(DownloadedArm64NetCoreAppHostPackInstallerFileName)' ^ '$(DownloadsFolder)$(DownloadedAspNetTargetingPackInstallerFileName)' ^ '$(DownloadsFolder)$(DownloadedWindowsDesktopTargetingPackInstallerFileName)' ^ + '$(FinalizerExe)' ^ '$(LatestTemplateMsiInstallerFile)' ^ '$(ManifestsMsiInstallerFile)' ^ '$(CombinedFrameworkSdkHostMSIInstallerFile)' ^ diff --git a/src/redist/targets/packaging/windows/clisdk/bundle.wxs b/src/redist/targets/packaging/windows/clisdk/bundle.wxs index aac49d06b..67cae8841 100644 --- a/src/redist/targets/packaging/windows/clisdk/bundle.wxs +++ b/src/redist/targets/packaging/windows/clisdk/bundle.wxs @@ -175,10 +175,10 @@ - + - + @@ -194,6 +194,20 @@ + + + diff --git a/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 b/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 index 58bbdde7a..d68bf8441 100644 --- a/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 +++ b/src/redist/targets/packaging/windows/clisdk/generatebundle.ps1 @@ -16,6 +16,7 @@ param( [Parameter(Mandatory=$true)][string]$Arm64NetCoreAppHostPackMSIFile, [Parameter(Mandatory=$true)][string]$AspNetTargetingPackMSIFile, [Parameter(Mandatory=$true)][string]$WindowsDesktopTargetingPackMSIFile, + [Parameter(Mandatory=$true)][string]$FinalizerExe, [Parameter(Mandatory=$true)][string]$TemplatesMSIFile, [Parameter(Mandatory=$true)][string]$ManifestsMSIFile, [Parameter(Mandatory=$true)][string]$DotnetBundleOutput, @@ -63,6 +64,7 @@ function RunCandleForBundle -dNetStandardTargetingPackMsiSourcePath="$NetStandardTargetingPackMSIFile" ` -dAspNetTargetingPackMsiSourcePath="$AspNetTargetingPackMSIFile" ` -dWindowsDesktopTargetingPackMsiSourcePath="$WindowsDesktopTargetingPackMSIFile" ` + -dFinalizerExeSourcePath="$FinalizerExe" ` -dTemplatesMsiSourcePath="$TemplatesMSIFile" ` -dManifestsMsiSourcePath="$ManifestsMSIFile" ` -dWinFormsAndWpfVersion="$WindowsDesktopVersion" ` diff --git a/src/redist/targets/packaging/windows/clisdk/variables.wxi b/src/redist/targets/packaging/windows/clisdk/variables.wxi index bad1ff7ef..414585175 100644 --- a/src/redist/targets/packaging/windows/clisdk/variables.wxi +++ b/src/redist/targets/packaging/windows/clisdk/variables.wxi @@ -45,4 +45,6 @@ + + diff --git a/src/snaps/dotnet-sdk-2.1/snap/snapcraft.yaml b/src/snaps/dotnet-sdk-2.1/snap/snapcraft.yaml index d73c54acc..ee58bc736 100755 --- a/src/snaps/dotnet-sdk-2.1/snap/snapcraft.yaml +++ b/src/snaps/dotnet-sdk-2.1/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: dotnet-sdk -version: 2.1.814 +version: 2.1.815 summary: Cross-Platform .NET Core SDK description: | .NET Core SDK. https://dot.net/core. @@ -16,8 +16,8 @@ base: core18 parts: dotnet-sdk: plugin: dump - source: https://download.visualstudio.microsoft.com/download/pr/b44d40e6-fa23-4f2d-a0a9-4199731f0b1e/5e62077a9e8014d8d4c74aee5406e0c7/dotnet-sdk-2.1.814-linux-x64.tar.gz - source-checksum: sha512/79408996f53650d0c3ac39348fa102537d14190ba5dcc4b9152cdb8fc72566608ad7430f196731eeb62dcfacdb0f2fa37577b5d51e165afd9dd9ae15f9d2aabc + source: https://download.visualstudio.microsoft.com/download/pr/7fba29f6-aac9-4b53-a5f9-9b421bec6288/70ac39be0282331d18b535f64ea5f40a/dotnet-sdk-2.1.815-linux-x64.tar.gz + source-checksum: sha512/e998ccb8b4e47a727141e85823637f2030df556d3056aadbdfbce4eca823fe4759ca0e0b2edaa6f83dd5b4cbb8a3b0046ff2c9eae96832e71dc6c13855998148 stage-packages: - libicu60 - libssl1.0.0 diff --git a/src/snaps/dotnet-sdk-3.1/snap/snapcraft.yaml b/src/snaps/dotnet-sdk-3.1/snap/snapcraft.yaml index 01f810e2b..1e6c874c9 100755 --- a/src/snaps/dotnet-sdk-3.1/snap/snapcraft.yaml +++ b/src/snaps/dotnet-sdk-3.1/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: dotnet-sdk -version: 3.1.407 +version: 3.1.408 summary: Cross-Platform .NET Core SDK description: | .NET Core SDK. https://dot.net/core. @@ -16,8 +16,8 @@ base: core18 parts: dotnet-sdk: plugin: dump - source: https://download.visualstudio.microsoft.com/download/pr/ab82011d-2549-4e23-a8a9-a2b522a31f27/6e615d6177e49c3e874d05ee3566e8bf/dotnet-sdk-3.1.407-linux-x64.tar.gz - source-checksum: sha512/b9c61061464a38df0a3eb5894a4a1229cd27d2ccba4168e434f4609b763630c01fbe1b2564826194d6d9b5ad86047e586312c0f35eafc3755dfe0ff9ba075c0c + source: https://download.visualstudio.microsoft.com/download/pr/2054b462-43da-4c61-9e2d-d02167c71c40/a8be03062d9d770c8025c7de47ca366d/dotnet-sdk-3.1.408-linux-x64.tar.gz + source-checksum: sha512/5e2c378addf337c1b7e44583718672e0791235150630f0b613353c8597342dcaae3b7c412b17d5e6d93d87b5708a6ca2dc16ff6e6c5a2101b224d24e6a5c4e7a stage-packages: - libicu60 - libssl1.0.0 diff --git a/src/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml b/src/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml index 93a84fff4..3ddf457ba 100755 --- a/src/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml +++ b/src/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: dotnet-sdk -version: 5.0.201 +version: 5.0.202 summary: Cross-Platform .NET Core SDK description: | .NET Core SDK. https://dot.net/core. @@ -16,8 +16,8 @@ base: core18 parts: dotnet-sdk: plugin: dump - source: https://download.visualstudio.microsoft.com/download/pr/73a9cb2a-1acd-4d20-b864-d12797ca3d40/075dbe1dc3bba4aa85ca420167b861b6/dotnet-sdk-5.0.201-linux-x64.tar.gz - source-checksum: sha512/099084cc7935482e363bd7802d2fdd909b3d72d2e9706e9ba4df95e3d142a28b780d2b85e5fb4662dcaad18e91c7e06519184fae981a521425eed605770c3c5a + source: https://download.visualstudio.microsoft.com/download/pr/5f0f07ab-cd9a-4498-a9f7-67d90d582180/2a3db6698751e6cbb93ec244cb81cc5f/dotnet-sdk-5.0.202-linux-x64.tar.gz + source-checksum: sha512/01ed59f236184987405673d24940d55ce29d830e7dbbc19556fdc03893039e6046712de6f901dc9911047a0dee4fd15319b7e94f8a31df6b981fa35bd93d9838 stage-packages: - libicu60 - libssl1.0.0 diff --git a/test/EndToEnd/ProjectBuildTests.cs b/test/EndToEnd/ProjectBuildTests.cs index b44c71202..3e71cff75 100644 --- a/test/EndToEnd/ProjectBuildTests.cs +++ b/test/EndToEnd/ProjectBuildTests.cs @@ -1,10 +1,12 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Xml.Linq; +using FluentAssertions; using Microsoft.DotNet.TestFramework; using Microsoft.DotNet.Tools.Test.Utilities; using Xunit; @@ -13,21 +15,6 @@ namespace EndToEnd.Tests { public class ProjectBuildTests : TestBase { - // TODO: Once console template is updated to target net6.0, remove this logic - // https://github.com/dotnet/installer/issues/8974 - void RetargetProject(string projectDirectory) - { - var projectFile = Directory.GetFiles(projectDirectory, "*.csproj").Single(); - - var projectXml = XDocument.Load(projectFile); - var ns = projectXml.Root.Name.Namespace; - - projectXml.Root.Element(ns + "PropertyGroup") - .Element(ns + "TargetFramework").Value = "net6.0"; - - projectXml.Save(projectFile); - } - [Fact] public void ItCanNewRestoreBuildRunCleanMSBuildProject() { @@ -40,8 +27,6 @@ namespace EndToEnd.Tests .Execute(newArgs) .Should().Pass(); - RetargetProject(projectDirectory); - new RestoreCommand() .WithWorkingDirectory(projectDirectory) .Execute() @@ -80,8 +65,6 @@ namespace EndToEnd.Tests .Execute(newArgs) .Should().Pass(); - RetargetProject(projectDirectory); - string projectPath = Path.Combine(projectDirectory, directory.Name + ".csproj"); var project = XDocument.Load(projectPath); @@ -156,15 +139,48 @@ namespace EndToEnd.Tests } [Theory] + // microsoft.dotnet.common.projectemplates templates [InlineData("console")] + [InlineData("console", "C#")] + [InlineData("console", "VB")] + [InlineData("console", "F#")] [InlineData("classlib")] + [InlineData("classlib", "C#")] + [InlineData("classlib", "VB")] + [InlineData("classlib", "F#")] + [InlineData("mstest")] [InlineData("nunit")] [InlineData("web")] [InlineData("mvc")] - public void ItCanBuildTemplates(string templateName) + public void ItCanBuildTemplates(string templateName, string language = "") { - TestTemplateBuild(templateName); + TestTemplateCreateAndBuild(templateName, language: language); + } + + [Theory] + // microsoft.dotnet.common.itemtemplates templates + [InlineData("globaljson")] + [InlineData("nugetconfig")] + [InlineData("webconfig")] + [InlineData("gitignore")] + [InlineData("tool-manifest")] + [InlineData("sln")] + public void ItCanCreateItemTemplate(string templateName) + { + DirectoryInfo directory = TestAssets.CreateTestDirectory(identifier: templateName); + string projectDirectory = directory.FullName; + + string newArgs = $"{templateName} --debug:ephemeral-hive"; + + new NewCommandShim() + .WithWorkingDirectory(projectDirectory) + .Execute(newArgs) + .Should().Pass(); + + //check if the template created files + Assert.True(directory.Exists); + Assert.True(directory.EnumerateFileSystemInfos().Any()); } [WindowsOnlyTheory] @@ -172,14 +188,14 @@ namespace EndToEnd.Tests [InlineData("winforms", Skip = "https://github.com/dotnet/wpf/issues/2363")] public void ItCanBuildDesktopTemplates(string templateName) { - TestTemplateBuild(templateName); + TestTemplateCreateAndBuild(templateName); } [WindowsOnlyTheory] [InlineData("wpf", Skip = "https://github.com/dotnet/wpf/issues/2363")] public void ItCanBuildDesktopTemplatesSelfContained(string templateName) { - TestTemplateBuild(templateName); + TestTemplateCreateAndBuild(templateName); } [Theory] @@ -187,27 +203,184 @@ namespace EndToEnd.Tests [InlineData("console")] public void ItCanBuildTemplatesSelfContained(string templateName) { - TestTemplateBuild(templateName, selfContained: true); + TestTemplateCreateAndBuild(templateName, selfContained: true); } - private void TestTemplateBuild(string templateName, bool selfContained = false) + /// + /// The test checks if the template creates the template for correct framework by default. + /// For .NET 6 the templates should create the projects targeting net6.0 + /// + [Theory] + [InlineData("console")] + [InlineData("console", "C#")] + [InlineData("console", "VB")] + [InlineData("console", "F#")] + [InlineData("classlib")] + [InlineData("classlib", "C#")] + [InlineData("classlib", "VB")] + [InlineData("classlib", "F#")] + [InlineData("worker")] + [InlineData("worker", "C#")] + [InlineData("worker", "F#")] + [InlineData("mstest")] + [InlineData("mstest", "C#")] + [InlineData("mstest", "VB")] + [InlineData("mstest", "F#")] + [InlineData("nunit")] + [InlineData("nunit", "C#")] + [InlineData("nunit", "VB")] + [InlineData("nunit", "F#")] + [InlineData("xunit")] + [InlineData("xunit", "C#")] + [InlineData("xunit", "VB")] + [InlineData("xunit", "F#")] + [InlineData("blazorserver")] + [InlineData("blazorwasm")] + [InlineData("web")] + [InlineData("web", "C#")] + [InlineData("web", "F#")] + [InlineData("mvc")] + [InlineData("mvc", "C#")] + [InlineData("mvc", "F#")] + [InlineData("webapi")] + [InlineData("webapi", "C#")] + [InlineData("webapi", "F#")] + [InlineData("webapp")] + [InlineData("razorclasslib")] + public void ItCanCreateAndBuildTemplatesWithDefaultFramework(string templateName, string language = "") { - var directory = TestAssets.CreateTestDirectory(identifier: templateName); + string framework = DetectExpectedDefaultFramework(); + TestTemplateCreateAndBuild(templateName, selfContained: true, language: language, framework: framework); + } + + /// + /// The test checks if the template creates the template for correct framework by default. + /// For .NET 6 the templates should create the projects targeting net6.0. + /// These templates require node.js to be built, so we just check if TargetFramework is present in csproj files + /// + [Theory] + [InlineData("angular")] + [InlineData("react")] + [InlineData("reactredux")] + public void ItCanCreateTemplateWithDefaultFramework(string templateName) + { + string framework = DetectExpectedDefaultFramework(); + TestTemplateCreateAndBuild(templateName, build: false, framework: framework); + } + + /// + /// [Windows only tests] + /// The test checks if the template creates the template for correct framework by default. + /// For .NET 6 the templates should create the projects targeting net6.0. + /// + [WindowsOnlyTheory] + [InlineData("wpf")] + [InlineData("wpf", "C#")] + [InlineData("wpf", "VB")] + [InlineData("wpflib")] + [InlineData("wpflib", "C#")] + [InlineData("wpflib", "VB")] + [InlineData("wpfcustomcontrollib")] + [InlineData("wpfcustomcontrollib", "C#")] + [InlineData("wpfcustomcontrollib", "VB")] + [InlineData("wpfusercontrollib")] + [InlineData("wpfusercontrollib", "C#")] + [InlineData("wpfusercontrollib", "VB")] + [InlineData("winforms")] + [InlineData("winforms", "C#")] + [InlineData("winforms", "VB")] + [InlineData("winformslib")] + [InlineData("winformslib", "C#")] + [InlineData("winformslib", "VB")] + [InlineData("winformscontrollib")] + [InlineData("winformscontrollib", "C#")] + [InlineData("winformscontrollib", "VB")] + public void ItCanCreateAndBuildTemplatesWithDefaultFramework_Windows(string templateName, string language = "") + { + string framework = DetectExpectedDefaultFramework(); + TestTemplateCreateAndBuild(templateName, selfContained: true, language: language, framework: $"{framework}-windows"); + } + + /// + /// [project is not built on linux-musl] + /// The test checks if the template creates the template for correct framework by default. + /// For .NET 6 the templates should create the projects targeting net6.0. + /// + [Theory] + [InlineData("grpc")] + public void ItCanCreateAndBuildTemplatesWithDefaultFramework_DisableBuildOnLinuxMusl(string templateName) + { + string framework = DetectExpectedDefaultFramework(); + + if (RuntimeInformation.RuntimeIdentifier.StartsWith("alpine")) //linux musl + { + TestTemplateCreateAndBuild(templateName, build: false, framework: framework); + } + else + { + TestTemplateCreateAndBuild(templateName, selfContained: true, framework: framework); + } + } + + private static string DetectExpectedDefaultFramework() + { + string dotnetFolder = Path.GetDirectoryName(RepoDirectoriesProvider.DotnetUnderTest); + string[] runtimeFolders = Directory.GetDirectories(Path.Combine(dotnetFolder, "shared", "Microsoft.NETCore.App")); + + int latestMajorVersion = runtimeFolders.Select(folder => int.Parse(Path.GetFileName(folder).Split('.').First())).Max(); + if (latestMajorVersion == 6) + { + return "net6.0"; + } + throw new Exception("Unsupported version of SDK"); + } + + private static void TestTemplateCreateAndBuild(string templateName, bool build = true, bool selfContained = false, string language = "", string framework = "") + { + DirectoryInfo directory = TestAssets.CreateTestDirectory(identifier: string.IsNullOrWhiteSpace(language) ? templateName : $"{templateName}[{language}]"); string projectDirectory = directory.FullName; string newArgs = $"{templateName} --debug:ephemeral-hive --no-restore"; + if (!string.IsNullOrWhiteSpace(language)) + { + newArgs += $" --language {language}"; + } + new NewCommandShim() .WithWorkingDirectory(projectDirectory) .Execute(newArgs) .Should().Pass(); - var buildArgs = selfContained ? "" :$"-r {RuntimeInformation.RuntimeIdentifier}"; - var dotnetRoot = Path.GetDirectoryName(RepoDirectoriesProvider.DotnetUnderTest); - new BuildCommand() - .WithEnvironmentVariable("PATH", dotnetRoot) // override PATH since razor rely on PATH to find dotnet - .WithWorkingDirectory(projectDirectory) - .Execute(buildArgs) - .Should().Pass(); + if (!string.IsNullOrWhiteSpace(framework)) + { + //check if MSBuild TargetFramework property for *proj is set to expected framework + string expectedExtension = language switch + { + "C#" => "*.csproj", + "F#" => "*.fsproj", + "VB" => "*.vbproj", + _ => "*.csproj" + }; + string projectFile = Directory.GetFiles(projectDirectory, expectedExtension).Single(); + XDocument projectXml = XDocument.Load(projectFile); + XNamespace ns = projectXml.Root.Name.Namespace; + Assert.Equal(framework, projectXml.Root.Element(ns + "PropertyGroup").Element(ns + "TargetFramework").Value); + } + + if (build) + { + string buildArgs = selfContained ? "" : $"-r {RuntimeInformation.RuntimeIdentifier}"; + if (!string.IsNullOrWhiteSpace(framework)) + { + buildArgs += $" --framework {framework}"; + } + string dotnetRoot = Path.GetDirectoryName(RepoDirectoriesProvider.DotnetUnderTest); + new BuildCommand() + .WithEnvironmentVariable("PATH", dotnetRoot) // override PATH since razor rely on PATH to find dotnet + .WithWorkingDirectory(projectDirectory) + .Execute(buildArgs) + .Should().Pass(); + } } } }