diff --git a/.github/workflows/ping.yml b/.github/workflows/ping.yml new file mode 100644 index 000000000000..4f66b07bc1c2 --- /dev/null +++ b/.github/workflows/ping.yml @@ -0,0 +1,24 @@ +name: Notify release branch change + +on: + # trigger for main and release branches. + push: + branches: + - main + - release/* + +jobs: + pingRemote: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@master + + - name: 'Ping remote repository' + uses: peter-evans/repository-dispatch@v1 + with: + token: ${{ secrets.SERVICEACCOUNT_PAT }} + event-type: ping-mirror + repository: ${{ secrets.ORG }}/${{ secrets.REPO }} + client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}' + diff --git a/.github/workflows/pong.yml b/.github/workflows/pong.yml new file mode 100644 index 000000000000..2a0cc8afdd07 --- /dev/null +++ b/.github/workflows/pong.yml @@ -0,0 +1,49 @@ +name: Update local copy + +on: repository_dispatch + +# lock to ensure we do not step on each other +concurrency: + group: 'pong-mirror' + cancel-in-progress: false + + +jobs: + updateRemote: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@master + + - name: 'Debug context' + run: echo "$GITHUB_CONTEXT" + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + + - name: 'Add remotes' + run: | + git remote add public "http://$Env:GITHUB_TOKEN@github.com/xamarin/xamarin-macios.git" + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.access-token }} + + - name: 'Fetch remote' + run: git fetch public + + - name: 'Update local branch' + run: | + $branch = "$Env:BRANCH".Replace("refs/heads/","") + git checkout $branch + git pull public $branch + git push origin $branch + shell: pwsh + env: + BRANCH: ${{ github.event.client_payload.ref }} + + - name: Merge public with private + uses: devmasx/merge-branch@v1.3.1 + with: + type: now + from_branch: ${{ github.event.client_payload.ref }} + target_branch: ${{ github.event.client_payload.ref }}-private + github_token: ${{ github.token }} diff --git a/builds/Makefile b/builds/Makefile index 2f29a1188afd..613385df5169 100644 --- a/builds/Makefile +++ b/builds/Makefile @@ -74,7 +74,7 @@ downloads/%: downloads/%.nupkg downloads/$(basename $(basename $(DOTNET6_TARBALL_NAME))): dotnet-install.sh $(Q) echo "Downloading and installing .NET $(DOTNET6_VERSION) into $@..." - $(Q) ./dotnet-install.sh --install-dir "$@.tmp" --version "$(DOTNET6_VERSION)" --architecture x64 --no-path + $(Q) ./dotnet-install.sh --install-dir "$@.tmp" --version "$(DOTNET6_VERSION)" --architecture x64 --no-path $$DOTNET_INSTALL_EXTRA_ARGS $(Q) rm -Rf "$@" $(Q) mv "$@.tmp" "$@" $(Q) echo "Downloaded and installed .NET $(DOTNET6_VERSION) into $@." diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index fd62d741b263..0aa3739153dc 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -193,11 +193,13 @@ + _CollectBundleResources; _RunRidSpecificBuild; _CompileEntitlements; _DetectAppManifest; _ReadAppManifest; _WriteAppManifest; + _CopyResourcesToBundle; _CreateMergedAppBundle; Codesign; CreateIpa; @@ -295,11 +297,26 @@ + + <_RidSpecificProperties> + _IsMultiRidBuild=true; + RuntimeIdentifiers=; + _ProcessedBundleResourcesPath=$(_ProcessedBundleResourcesPath); + _ProcessedContentPath=$(_ProcessedContentPath); + _ProcessedImageAssetsPath=$(_ProcessedImageAssetsPath); + _ProcessedInterfaceDefinitionsPath=$(_ProcessedInterfaceDefinitionsPath); + _ProcessedSceneKitAssetsPath=$(_ProcessedSceneKitAssetsPath); + _ProcessedColladaAssetsPath=$(_ProcessedColladaAssetsPath); + _ProcessedTextureAtlasesPath=$(_ProcessedTextureAtlasesPath); + _ProcessedCoreMLModelsPath=$(_ProcessedCoreMLModelsPath); + + + + Properties="RuntimeIdentifier=%(_RuntimeIdentifiersAsItems.Identity);$(_RidSpecificProperties)"> @@ -428,6 +445,7 @@ MarshalManagedExceptionMode=$(_MarshalManagedExceptionMode) MarshalObjectiveCExceptionMode=$(_MarshalObjectiveCExceptionMode) @(_MonoLibrary -> 'MonoLibrary=%(Identity)') + MtouchFloat32=$(MtouchFloat32) Optimize=$(_BundlerOptimize) PartialStaticRegistrarLibrary=$(_LibPartialStaticRegistrar) Platform=$(_PlatformName) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9a206a36ae86..f0af4339bb3f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/installer - b83da76f5fede9432ca6efce8652a616efff2ea6 + b2fac072e4480a39df132de7c152ff5466a1bbe3 https://github.com/dotnet/linker diff --git a/eng/Versions.props b/eng/Versions.props index 71d0426c54ce..7b8ad7b452ce 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,7 +1,7 @@ - 6.0.100-rtm.21478.8 + 6.0.100-rtm.21480.21 6.0.100-1.21473.1 6.0.0-beta.21212.6 6.0.0-rc.2.21468.3 diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1 new file mode 100644 index 000000000000..5f3105f21114 --- /dev/null +++ b/eng/common/SetupNugetSources.ps1 @@ -0,0 +1,167 @@ +# This file is a temporary workaround for internal builds to be able to restore from private AzDO feeds. +# This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080 +# +# What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry +# under for each Maestro managed private feed. Two additional credential +# entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport. +# +# This script needs to be called in every job that will restore packages and which the base repo has +# private AzDO feeds in the NuGet.config. +# +# See example YAML call for this script below. Note the use of the variable `$(dn-bot-dnceng-artifact-feeds-rw)` +# from the AzureDevOps-Artifact-Feeds-Pats variable group. +# +# Any disabledPackageSources entries which start with "darc-int" will be re-enabled as part of this script executing +# +# - task: PowerShell@2 +# displayName: Setup Private Feeds Credentials +# condition: eq(variables['Agent.OS'], 'Windows_NT') +# inputs: +# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1 +# arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token +# env: +# Token: $(dn-bot-dnceng-artifact-feeds-rw) + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $true)][string]$ConfigFile, + [Parameter(Mandatory = $true)][string]$Password +) + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version 2.0 +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +. $PSScriptRoot\tools.ps1 + +# Add source entry to PackageSources +function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $Password) { + $packageSource = $sources.SelectSingleNode("add[@key='$SourceName']") + + if ($packageSource -eq $null) + { + $packageSource = $doc.CreateElement("add") + $packageSource.SetAttribute("key", $SourceName) + $packageSource.SetAttribute("value", $SourceEndPoint) + $sources.AppendChild($packageSource) | Out-Null + } + else { + Write-Host "Package source $SourceName already present." + } + + AddCredential -Creds $creds -Source $SourceName -Username $Username -Password $Password +} + +# Add a credential node for the specified source +function AddCredential($creds, $source, $username, $password) { + # Looks for credential configuration for the given SourceName. Create it if none is found. + $sourceElement = $creds.SelectSingleNode($Source) + if ($sourceElement -eq $null) + { + $sourceElement = $doc.CreateElement($Source) + $creds.AppendChild($sourceElement) | Out-Null + } + + # Add the node to the credential if none is found. + $usernameElement = $sourceElement.SelectSingleNode("add[@key='Username']") + if ($usernameElement -eq $null) + { + $usernameElement = $doc.CreateElement("add") + $usernameElement.SetAttribute("key", "Username") + $sourceElement.AppendChild($usernameElement) | Out-Null + } + $usernameElement.SetAttribute("value", $Username) + + # Add the to the credential if none is found. + # Add it as a clear text because there is no support for encrypted ones in non-windows .Net SDKs. + # -> https://github.com/NuGet/Home/issues/5526 + $passwordElement = $sourceElement.SelectSingleNode("add[@key='ClearTextPassword']") + if ($passwordElement -eq $null) + { + $passwordElement = $doc.CreateElement("add") + $passwordElement.SetAttribute("key", "ClearTextPassword") + $sourceElement.AppendChild($passwordElement) | Out-Null + } + $passwordElement.SetAttribute("value", $Password) +} + +function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $Password) { + $maestroPrivateSources = $Sources.SelectNodes("add[contains(@key,'darc-int')]") + + Write-Host "Inserting credentials for $($maestroPrivateSources.Count) Maestro's private feeds." + + ForEach ($PackageSource in $maestroPrivateSources) { + Write-Host "`tInserting credential for Maestro's feed:" $PackageSource.Key + AddCredential -Creds $creds -Source $PackageSource.Key -Username $Username -Password $Password + } +} + +function EnablePrivatePackageSources($DisabledPackageSources) { + $maestroPrivateSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]") + ForEach ($DisabledPackageSource in $maestroPrivateSources) { + Write-Host "`tEnsuring private source '$($DisabledPackageSource.key)' is enabled by deleting it from disabledPackageSource" + # Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries + $DisabledPackageSources.RemoveChild($DisabledPackageSource) + } +} + +if (!(Test-Path $ConfigFile -PathType Leaf)) { + Write-PipelineTelemetryError -Category 'Build' -Message "Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile" + ExitWithExitCode 1 +} + +if (!$Password) { + Write-PipelineTelemetryError -Category 'Build' -Message 'Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Please supply a valid PAT' + ExitWithExitCode 1 +} + +# Load NuGet.config +$doc = New-Object System.Xml.XmlDocument +$filename = (Get-Item $ConfigFile).FullName +$doc.Load($filename) + +# Get reference to or create one if none exist already +$sources = $doc.DocumentElement.SelectSingleNode("packageSources") +if ($sources -eq $null) { + $sources = $doc.CreateElement("packageSources") + $doc.DocumentElement.AppendChild($sources) | Out-Null +} + +# Looks for a node. Create it if none is found. +$creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials") +if ($creds -eq $null) { + $creds = $doc.CreateElement("packageSourceCredentials") + $doc.DocumentElement.AppendChild($creds) | Out-Null +} + +# Check for disabledPackageSources; we'll enable any darc-int ones we find there +$disabledSources = $doc.DocumentElement.SelectSingleNode("disabledPackageSources") +if ($disabledSources -ne $null) { + Write-Host "Checking for any darc-int disabled package sources in the disabledPackageSources node" + EnablePrivatePackageSources -DisabledPackageSources $disabledSources +} + +$userName = "dn-bot" + +# Insert credential nodes for Maestro's private feeds +InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Username $userName -Password $Password + +$dotnet31Source = $sources.SelectSingleNode("add[@key='dotnet3.1']") +if ($dotnet31Source -ne $null) { + AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password + AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password +} + +$dotnet5Source = $sources.SelectSingleNode("add[@key='dotnet5']") +if ($dotnet5Source -ne $null) { + AddPackageSource -Sources $sources -SourceName "dotnet5-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password + AddPackageSource -Sources $sources -SourceName "dotnet5-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password +} + +$dotnet6Source = $sources.SelectSingleNode("add[@key='dotnet6']") +if ($dotnet6Source -ne $null) { + AddPackageSource -Sources $sources -SourceName "dotnet6-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password + AddPackageSource -Sources $sources -SourceName "dotnet6-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password +} + +$doc.Save($filename) \ No newline at end of file diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh new file mode 100644 index 000000000000..30964e5b9500 --- /dev/null +++ b/eng/common/SetupNugetSources.sh @@ -0,0 +1,191 @@ +#!/usr/bin/env bash + +# This file is a temporary workaround for internal builds to be able to restore from private AzDO feeds. +# This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080 +# +# What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry +# under for each Maestro's managed private feed. Two additional credential +# entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport. +# +# This script needs to be called in every job that will restore packages and which the base repo has +# private AzDO feeds in the NuGet.config. +# +# See example YAML call for this script below. Note the use of the variable `$(dn-bot-dnceng-artifact-feeds-rw)` +# from the AzureDevOps-Artifact-Feeds-Pats variable group. +# +# Any disabledPackageSources entries which start with "darc-int" will be re-enabled as part of this script executing. +# +# - task: Bash@3 +# displayName: Setup Private Feeds Credentials +# inputs: +# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh +# arguments: $(Build.SourcesDirectory)/NuGet.config $Token +# condition: ne(variables['Agent.OS'], 'Windows_NT') +# env: +# Token: $(dn-bot-dnceng-artifact-feeds-rw) + +ConfigFile=$1 +CredToken=$2 +NL='\n' +TB=' ' + +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/tools.sh" + +if [ ! -f "$ConfigFile" ]; then + Write-PipelineTelemetryError -Category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile" + ExitWithExitCode 1 +fi + +if [ -z "$CredToken" ]; then + Write-PipelineTelemetryError -category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Please supply a valid PAT" + ExitWithExitCode 1 +fi + +if [[ `uname -s` == "Darwin" ]]; then + NL=$'\\\n' + TB='' +fi + +# Ensure there is a ... section. +grep -i "" $ConfigFile +if [ "$?" != "0" ]; then + echo "Adding ... section." + ConfigNodeHeader="" + PackageSourcesTemplate="${TB}${NL}${TB}" + + sed -i.bak "s|$ConfigNodeHeader|$ConfigNodeHeader${NL}$PackageSourcesTemplate|" $ConfigFile +fi + +# Ensure there is a ... section. +grep -i "" $ConfigFile +if [ "$?" != "0" ]; then + echo "Adding ... section." + + PackageSourcesNodeFooter="" + PackageSourceCredentialsTemplate="${TB}${NL}${TB}" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourcesNodeFooter${NL}$PackageSourceCredentialsTemplate|" $ConfigFile +fi + +PackageSources=() + +# Ensure dotnet3.1-internal and dotnet3.1-internal-transport are in the packageSources if the public dotnet3.1 feeds are present +grep -i "" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet3.1-internal') + + grep -i "" $ConfigFile + if [ "$?" != "0" ]; then + echo "Adding dotnet3.1-internal-transport to the packageSources." + PackageSourcesNodeFooter="" + PackageSourceTemplate="${TB}" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet3.1-internal-transport') +fi + +# Ensure dotnet5-internal and dotnet5-internal-transport are in the packageSources if the public dotnet5 feeds are present +grep -i "" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet5-internal') + + grep -i "" $ConfigFile + if [ "$?" != "0" ]; then + echo "Adding dotnet5-internal-transport to the packageSources." + PackageSourcesNodeFooter="" + PackageSourceTemplate="${TB}" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet5-internal-transport') +fi + +# Ensure dotnet6-internal and dotnet6-internal-transport are in the packageSources if the public dotnet6 feeds are present +grep -i "" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet6-internal') + + grep -i "" $ConfigFile + if [ "$?" != "0" ]; then + echo "Adding dotnet6-internal-transport to the packageSources." + PackageSourcesNodeFooter="" + PackageSourceTemplate="${TB}" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet6-internal-transport') +fi + +# I want things split line by line +PrevIFS=$IFS +IFS=$'\n' +PackageSources+="$IFS" +PackageSources+=$(grep -oh '"darc-int-[^"]*"' $ConfigFile | tr -d '"') +IFS=$PrevIFS + +for FeedName in ${PackageSources[@]} ; do + # Check if there is no existing credential for this FeedName + grep -i "<$FeedName>" $ConfigFile + if [ "$?" != "0" ]; then + echo "Adding credentials for $FeedName." + + PackageSourceCredentialsNodeFooter="" + NewCredential="${TB}${TB}<$FeedName>${NL}${NL}${NL}" + + sed -i.bak "s|$PackageSourceCredentialsNodeFooter|$NewCredential${NL}$PackageSourceCredentialsNodeFooter|" $ConfigFile + fi +done + +# Re-enable any entries in disabledPackageSources where the feed name contains darc-int +grep -i "" $ConfigFile +if [ "$?" == "0" ]; then + DisabledDarcIntSources=() + echo "Re-enabling any disabled \"darc-int\" package sources in $ConfigFile" + DisabledDarcIntSources+=$(grep -oh '"darc-int-[^"]*" value="true"' $ConfigFile | tr -d '"') + for DisabledSourceName in ${DisabledDarcIntSources[@]} ; do + if [[ $DisabledSourceName == darc-int* ]] + then + OldDisableValue="" + NewDisableValue="" + sed -i.bak "s|$OldDisableValue|$NewDisableValue|" $ConfigFile + echo "Neutralized disablePackageSources entry for '$DisabledSourceName'" + fi + done +fi \ No newline at end of file diff --git a/eng/common/pipeline-logging-functions.ps1 b/eng/common/pipeline-logging-functions.ps1 new file mode 100644 index 000000000000..28d7823299eb --- /dev/null +++ b/eng/common/pipeline-logging-functions.ps1 @@ -0,0 +1,260 @@ +# Source for this file was taken from https://github.com/microsoft/azure-pipelines-task-lib/blob/11c9439d4af17e6475d9fe058e6b2e03914d17e6/powershell/VstsTaskSdk/LoggingCommandFunctions.ps1 and modified. + +# NOTE: You should not be calling these method directly as they are likely to change. Instead you should be calling the Write-Pipeline* functions defined in tools.ps1 + +$script:loggingCommandPrefix = '##vso[' +$script:loggingCommandEscapeMappings = @( # TODO: WHAT ABOUT "="? WHAT ABOUT "%"? + New-Object psobject -Property @{ Token = ';' ; Replacement = '%3B' } + New-Object psobject -Property @{ Token = "`r" ; Replacement = '%0D' } + New-Object psobject -Property @{ Token = "`n" ; Replacement = '%0A' } + New-Object psobject -Property @{ Token = "]" ; Replacement = '%5D' } +) +# TODO: BUG: Escape % ??? +# TODO: Add test to verify don't need to escape "=". + +# Specify "-Force" to force pipeline formatted output even if "$ci" is false or not set +function Write-PipelineTelemetryError { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Category, + [Parameter(Mandatory = $true)] + [string]$Message, + [Parameter(Mandatory = $false)] + [string]$Type = 'error', + [string]$ErrCode, + [string]$SourcePath, + [string]$LineNumber, + [string]$ColumnNumber, + [switch]$AsOutput, + [switch]$Force) + + $PSBoundParameters.Remove('Category') | Out-Null + + if ($Force -Or ((Test-Path variable:ci) -And $ci)) { + $Message = "(NETCORE_ENGINEERING_TELEMETRY=$Category) $Message" + } + $PSBoundParameters.Remove('Message') | Out-Null + $PSBoundParameters.Add('Message', $Message) + Write-PipelineTaskError @PSBoundParameters +} + +# Specify "-Force" to force pipeline formatted output even if "$ci" is false or not set +function Write-PipelineTaskError { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Message, + [Parameter(Mandatory = $false)] + [string]$Type = 'error', + [string]$ErrCode, + [string]$SourcePath, + [string]$LineNumber, + [string]$ColumnNumber, + [switch]$AsOutput, + [switch]$Force + ) + + if (!$Force -And (-Not (Test-Path variable:ci) -Or !$ci)) { + if ($Type -eq 'error') { + Write-Host $Message -ForegroundColor Red + return + } + elseif ($Type -eq 'warning') { + Write-Host $Message -ForegroundColor Yellow + return + } + } + + if (($Type -ne 'error') -and ($Type -ne 'warning')) { + Write-Host $Message + return + } + $PSBoundParameters.Remove('Force') | Out-Null + if (-not $PSBoundParameters.ContainsKey('Type')) { + $PSBoundParameters.Add('Type', 'error') + } + Write-LogIssue @PSBoundParameters +} + +function Write-PipelineSetVariable { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Name, + [string]$Value, + [switch]$Secret, + [switch]$AsOutput, + [bool]$IsMultiJobVariable = $true) + + if ((Test-Path variable:ci) -And $ci) { + Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{ + 'variable' = $Name + 'isSecret' = $Secret + 'isOutput' = $IsMultiJobVariable + } -AsOutput:$AsOutput + } +} + +function Write-PipelinePrependPath { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Path, + [switch]$AsOutput) + + if ((Test-Path variable:ci) -And $ci) { + Write-LoggingCommand -Area 'task' -Event 'prependpath' -Data $Path -AsOutput:$AsOutput + } +} + +function Write-PipelineSetResult { + [CmdletBinding()] + param( + [ValidateSet("Succeeded", "SucceededWithIssues", "Failed", "Cancelled", "Skipped")] + [Parameter(Mandatory = $true)] + [string]$Result, + [string]$Message) + if ((Test-Path variable:ci) -And $ci) { + Write-LoggingCommand -Area 'task' -Event 'complete' -Data $Message -Properties @{ + 'result' = $Result + } + } +} + +<######################################## +# Private functions. +########################################> +function Format-LoggingCommandData { + [CmdletBinding()] + param([string]$Value, [switch]$Reverse) + + if (!$Value) { + return '' + } + + if (!$Reverse) { + foreach ($mapping in $script:loggingCommandEscapeMappings) { + $Value = $Value.Replace($mapping.Token, $mapping.Replacement) + } + } + else { + for ($i = $script:loggingCommandEscapeMappings.Length - 1 ; $i -ge 0 ; $i--) { + $mapping = $script:loggingCommandEscapeMappings[$i] + $Value = $Value.Replace($mapping.Replacement, $mapping.Token) + } + } + + return $Value +} + +function Format-LoggingCommand { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Area, + [Parameter(Mandatory = $true)] + [string]$Event, + [string]$Data, + [hashtable]$Properties) + + # Append the preamble. + [System.Text.StringBuilder]$sb = New-Object -TypeName System.Text.StringBuilder + $null = $sb.Append($script:loggingCommandPrefix).Append($Area).Append('.').Append($Event) + + # Append the properties. + if ($Properties) { + $first = $true + foreach ($key in $Properties.Keys) { + [string]$value = Format-LoggingCommandData $Properties[$key] + if ($value) { + if ($first) { + $null = $sb.Append(' ') + $first = $false + } + else { + $null = $sb.Append(';') + } + + $null = $sb.Append("$key=$value") + } + } + } + + # Append the tail and output the value. + $Data = Format-LoggingCommandData $Data + $sb.Append(']').Append($Data).ToString() +} + +function Write-LoggingCommand { + [CmdletBinding(DefaultParameterSetName = 'Parameters')] + param( + [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')] + [string]$Area, + [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')] + [string]$Event, + [Parameter(ParameterSetName = 'Parameters')] + [string]$Data, + [Parameter(ParameterSetName = 'Parameters')] + [hashtable]$Properties, + [Parameter(Mandatory = $true, ParameterSetName = 'Object')] + $Command, + [switch]$AsOutput) + + if ($PSCmdlet.ParameterSetName -eq 'Object') { + Write-LoggingCommand -Area $Command.Area -Event $Command.Event -Data $Command.Data -Properties $Command.Properties -AsOutput:$AsOutput + return + } + + $command = Format-LoggingCommand -Area $Area -Event $Event -Data $Data -Properties $Properties + if ($AsOutput) { + $command + } + else { + Write-Host $command + } +} + +function Write-LogIssue { + [CmdletBinding()] + param( + [ValidateSet('warning', 'error')] + [Parameter(Mandatory = $true)] + [string]$Type, + [string]$Message, + [string]$ErrCode, + [string]$SourcePath, + [string]$LineNumber, + [string]$ColumnNumber, + [switch]$AsOutput) + + $command = Format-LoggingCommand -Area 'task' -Event 'logissue' -Data $Message -Properties @{ + 'type' = $Type + 'code' = $ErrCode + 'sourcepath' = $SourcePath + 'linenumber' = $LineNumber + 'columnnumber' = $ColumnNumber + } + if ($AsOutput) { + return $command + } + + if ($Type -eq 'error') { + $foregroundColor = $host.PrivateData.ErrorForegroundColor + $backgroundColor = $host.PrivateData.ErrorBackgroundColor + if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { + $foregroundColor = [System.ConsoleColor]::Red + $backgroundColor = [System.ConsoleColor]::Black + } + } + else { + $foregroundColor = $host.PrivateData.WarningForegroundColor + $backgroundColor = $host.PrivateData.WarningBackgroundColor + if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { + $foregroundColor = [System.ConsoleColor]::Yellow + $backgroundColor = [System.ConsoleColor]::Black + } + } + + Write-Host $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor +} \ No newline at end of file diff --git a/eng/common/pipeline-logging-functions.sh b/eng/common/pipeline-logging-functions.sh new file mode 100644 index 000000000000..2eaafa8f323b --- /dev/null +++ b/eng/common/pipeline-logging-functions.sh @@ -0,0 +1,206 @@ +#!/usr/bin/env bash + +function Write-PipelineTelemetryError { + local telemetry_category='' + local force=false + local function_args=() + local message='' + while [[ $# -gt 0 ]]; do + opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -category|-c) + telemetry_category=$2 + shift + ;; + -force|-f) + force=true + ;; + -*) + function_args+=("$1 $2") + shift + ;; + *) + message=$* + ;; + esac + shift + done + + if [[ $force != true ]] && [[ "$ci" != true ]]; then + echo "$message" >&2 + return + fi + + if [[ $force == true ]]; then + function_args+=("-force") + fi + message="(NETCORE_ENGINEERING_TELEMETRY=$telemetry_category) $message" + function_args+=("$message") + Write-PipelineTaskError ${function_args[@]} +} + +function Write-PipelineTaskError { + local message_type="error" + local sourcepath='' + local linenumber='' + local columnnumber='' + local error_code='' + local force=false + + while [[ $# -gt 0 ]]; do + opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -type|-t) + message_type=$2 + shift + ;; + -sourcepath|-s) + sourcepath=$2 + shift + ;; + -linenumber|-ln) + linenumber=$2 + shift + ;; + -columnnumber|-cn) + columnnumber=$2 + shift + ;; + -errcode|-e) + error_code=$2 + shift + ;; + -force|-f) + force=true + ;; + *) + break + ;; + esac + + shift + done + + if [[ $force != true ]] && [[ "$ci" != true ]]; then + echo "$@" >&2 + return + fi + + local message="##vso[task.logissue" + + message="$message type=$message_type" + + if [ -n "$sourcepath" ]; then + message="$message;sourcepath=$sourcepath" + fi + + if [ -n "$linenumber" ]; then + message="$message;linenumber=$linenumber" + fi + + if [ -n "$columnnumber" ]; then + message="$message;columnnumber=$columnnumber" + fi + + if [ -n "$error_code" ]; then + message="$message;code=$error_code" + fi + + message="$message]$*" + echo "$message" +} + +function Write-PipelineSetVariable { + if [[ "$ci" != true ]]; then + return + fi + + local name='' + local value='' + local secret=false + local as_output=false + local is_multi_job_variable=true + + while [[ $# -gt 0 ]]; do + opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -name|-n) + name=$2 + shift + ;; + -value|-v) + value=$2 + shift + ;; + -secret|-s) + secret=true + ;; + -as_output|-a) + as_output=true + ;; + -is_multi_job_variable|-i) + is_multi_job_variable=$2 + shift + ;; + esac + shift + done + + value=${value/;/%3B} + value=${value/\\r/%0D} + value=${value/\\n/%0A} + value=${value/]/%5D} + + local message="##vso[task.setvariable variable=$name;isSecret=$secret;isOutput=$is_multi_job_variable]$value" + + if [[ "$as_output" == true ]]; then + $message + else + echo "$message" + fi +} + +function Write-PipelinePrependPath { + local prepend_path='' + + while [[ $# -gt 0 ]]; do + opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -path|-p) + prepend_path=$2 + shift + ;; + esac + shift + done + + export PATH="$prepend_path:$PATH" + + if [[ "$ci" == true ]]; then + echo "##vso[task.prependpath]$prepend_path" + fi +} + +function Write-PipelineSetResult { + local result='' + local message='' + + while [[ $# -gt 0 ]]; do + opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -result|-r) + result=$2 + shift + ;; + -message|-m) + message=$2 + shift + ;; + esac + shift + done + + if [[ "$ci" == true ]]; then + echo "##vso[task.complete result=$result;]$message" + fi +} \ No newline at end of file diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 new file mode 100644 index 000000000000..a4745b344456 --- /dev/null +++ b/eng/common/tools.ps1 @@ -0,0 +1,916 @@ +# Initialize variables if they aren't already defined. +# These may be defined as parameters of the importing script, or set after importing this script. + +# CI mode - set to true on CI server for PR validation build or official build. +[bool]$ci = if (Test-Path variable:ci) { $ci } else { $false } + +# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names. +[string]$configuration = if (Test-Path variable:configuration) { $configuration } else { 'Debug' } + +# Set to true to opt out of outputting binary log while running in CI +[bool]$excludeCIBinarylog = if (Test-Path variable:excludeCIBinarylog) { $excludeCIBinarylog } else { $false } + +# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build. +[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci -and !$excludeCIBinarylog } + +# Set to true to use the pipelines logger which will enable Azure logging output. +# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md +# This flag is meant as a temporary opt-opt for the feature while validate it across +# our consumers. It will be deleted in the future. +[bool]$pipelinesLog = if (Test-Path variable:pipelinesLog) { $pipelinesLog } else { $ci } + +# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes). +[bool]$prepareMachine = if (Test-Path variable:prepareMachine) { $prepareMachine } else { $false } + +# True to restore toolsets and dependencies. +[bool]$restore = if (Test-Path variable:restore) { $restore } else { $true } + +# Adjusts msbuild verbosity level. +[string]$verbosity = if (Test-Path variable:verbosity) { $verbosity } else { 'minimal' } + +# Set to true to reuse msbuild nodes. Recommended to not reuse on CI. +[bool]$nodeReuse = if (Test-Path variable:nodeReuse) { $nodeReuse } else { !$ci } + +# Configures warning treatment in msbuild. +[bool]$warnAsError = if (Test-Path variable:warnAsError) { $warnAsError } else { $true } + +# Specifies which msbuild engine to use for build: 'vs', 'dotnet' or unspecified (determined based on presence of tools.vs in global.json). +[string]$msbuildEngine = if (Test-Path variable:msbuildEngine) { $msbuildEngine } else { $null } + +# True to attempt using .NET Core already that meets requirements specified in global.json +# installed on the machine instead of downloading one. +[bool]$useInstalledDotNetCli = if (Test-Path variable:useInstalledDotNetCli) { $useInstalledDotNetCli } else { $true } + +# Enable repos to use a particular version of the on-line dotnet-install scripts. +# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.ps1 +[string]$dotnetInstallScriptVersion = if (Test-Path variable:dotnetInstallScriptVersion) { $dotnetInstallScriptVersion } else { 'v1' } + +# True to use global NuGet cache instead of restoring packages to repository-local directory. +[bool]$useGlobalNuGetCache = if (Test-Path variable:useGlobalNuGetCache) { $useGlobalNuGetCache } else { !$ci } + +# True to exclude prerelease versions Visual Studio during build +[bool]$excludePrereleaseVS = if (Test-Path variable:excludePrereleaseVS) { $excludePrereleaseVS } else { $false } + +# An array of names of processes to stop on script exit if prepareMachine is true. +$processesToStopOnExit = if (Test-Path variable:processesToStopOnExit) { $processesToStopOnExit } else { @('msbuild', 'dotnet', 'vbcscompiler') } + +$disableConfigureToolsetImport = if (Test-Path variable:disableConfigureToolsetImport) { $disableConfigureToolsetImport } else { $null } + +set-strictmode -version 2.0 +$ErrorActionPreference = 'Stop' +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +# If specifies, provides an alternate path for getting .NET Core SDKs and Runtimes. This script will still try public sources first. +[string]$runtimeSourceFeed = if (Test-Path variable:runtimeSourceFeed) { $runtimeSourceFeed } else { $null } +# Base-64 encoded SAS token that has permission to storage container described by $runtimeSourceFeed +[string]$runtimeSourceFeedKey = if (Test-Path variable:runtimeSourceFeedKey) { $runtimeSourceFeedKey } else { $null } + +function Create-Directory ([string[]] $path) { + New-Item -Path $path -Force -ItemType 'Directory' | Out-Null +} + +function Unzip([string]$zipfile, [string]$outpath) { + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath) +} + +# This will exec a process using the console and return it's exit code. +# This will not throw when the process fails. +# Returns process exit code. +function Exec-Process([string]$command, [string]$commandArgs) { + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = $command + $startInfo.Arguments = $commandArgs + $startInfo.UseShellExecute = $false + $startInfo.WorkingDirectory = Get-Location + + $process = New-Object System.Diagnostics.Process + $process.StartInfo = $startInfo + $process.Start() | Out-Null + + $finished = $false + try { + while (-not $process.WaitForExit(100)) { + # Non-blocking loop done to allow ctr-c interrupts + } + + $finished = $true + return $global:LASTEXITCODE = $process.ExitCode + } + finally { + # If we didn't finish then an error occurred or the user hit ctrl-c. Either + # way kill the process + if (-not $finished) { + $process.Kill() + } + } +} + +# Take the given block, print it, print what the block probably references from the current set of +# variables using low-effort string matching, then run the block. +# +# This is intended to replace the pattern of manually copy-pasting a command, wrapping it in quotes, +# and printing it using "Write-Host". The copy-paste method is more readable in build logs, but less +# maintainable and less reliable. It is easy to make a mistake and modify the command without +# properly updating the "Write-Host" line, resulting in misleading build logs. The probability of +# this mistake makes the pattern hard to trust when it shows up in build logs. Finding the bug in +# existing source code can also be difficult, because the strings are not aligned to each other and +# the line may be 300+ columns long. +# +# By removing the need to maintain two copies of the command, Exec-BlockVerbosely avoids the issues. +# +# In Bash (or any posix-like shell), "set -x" prints usable verbose output automatically. +# "Set-PSDebug" appears to be similar at first glance, but unfortunately, it isn't very useful: it +# doesn't print any info about the variables being used by the command, which is normally the +# interesting part to diagnose. +function Exec-BlockVerbosely([scriptblock] $block) { + Write-Host "--- Running script block:" + $blockString = $block.ToString().Trim() + Write-Host $blockString + + Write-Host "--- List of variables that might be used:" + # For each variable x in the environment, check the block for a reference to x via simple "$x" or + # "@x" syntax. This doesn't detect other ways to reference variables ("${x}" nor "$variable:x", + # among others). It only catches what this function was originally written for: simple + # command-line commands. + $variableTable = Get-Variable | + Where-Object { + $blockString.Contains("`$$($_.Name)") -or $blockString.Contains("@$($_.Name)") + } | + Format-Table -AutoSize -HideTableHeaders -Wrap | + Out-String + Write-Host $variableTable.Trim() + + Write-Host "--- Executing:" + & $block + Write-Host "--- Done running script block!" +} + +# createSdkLocationFile parameter enables a file being generated under the toolset directory +# which writes the sdk's location into. This is only necessary for cmd --> powershell invocations +# as dot sourcing isn't possible. +function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) { + if (Test-Path variable:global:_DotNetInstallDir) { + return $global:_DotNetInstallDir + } + + # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism + $env:DOTNET_MULTILEVEL_LOOKUP=0 + + # Disable first run since we do not need all ASP.NET packages restored. + $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + + # Disable telemetry on CI. + if ($ci) { + $env:DOTNET_CLI_TELEMETRY_OPTOUT=1 + + # In case of network error, try to log the current IP for reference + Try-LogClientIpAddress + } + + # Source Build uses DotNetCoreSdkDir variable + if ($env:DotNetCoreSdkDir -ne $null) { + $env:DOTNET_INSTALL_DIR = $env:DotNetCoreSdkDir + } + + # Find the first path on %PATH% that contains the dotnet.exe + if ($useInstalledDotNetCli -and (-not $globalJsonHasRuntimes) -and ($env:DOTNET_INSTALL_DIR -eq $null)) { + $dotnetExecutable = GetExecutableFileName 'dotnet' + $dotnetCmd = Get-Command $dotnetExecutable -ErrorAction SilentlyContinue + + if ($dotnetCmd -ne $null) { + $env:DOTNET_INSTALL_DIR = Split-Path $dotnetCmd.Path -Parent + } + } + + $dotnetSdkVersion = $GlobalJson.tools.dotnet + + # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version, + # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues. + if ((-not $globalJsonHasRuntimes) -and (-not [string]::IsNullOrEmpty($env:DOTNET_INSTALL_DIR)) -and (Test-Path(Join-Path $env:DOTNET_INSTALL_DIR "sdk\$dotnetSdkVersion"))) { + $dotnetRoot = $env:DOTNET_INSTALL_DIR + } else { + $dotnetRoot = Join-Path $RepoRoot '.dotnet' + + if (-not (Test-Path(Join-Path $dotnetRoot "sdk\$dotnetSdkVersion"))) { + if ($install) { + InstallDotNetSdk $dotnetRoot $dotnetSdkVersion + } else { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to find dotnet with SDK version '$dotnetSdkVersion'" + ExitWithExitCode 1 + } + } + + $env:DOTNET_INSTALL_DIR = $dotnetRoot + } + + # Creates a temporary file under the toolset dir. + # The following code block is protecting against concurrent access so that this function can + # be called in parallel. + if ($createSdkLocationFile) { + do { + $sdkCacheFileTemp = Join-Path $ToolsetDir $([System.IO.Path]::GetRandomFileName()) + } + until (!(Test-Path $sdkCacheFileTemp)) + Set-Content -Path $sdkCacheFileTemp -Value $dotnetRoot + + try { + Move-Item -Force $sdkCacheFileTemp (Join-Path $ToolsetDir 'sdk.txt') + } catch { + # Somebody beat us + Remove-Item -Path $sdkCacheFileTemp + } + } + + # Add dotnet to PATH. This prevents any bare invocation of dotnet in custom + # build steps from using anything other than what we've downloaded. + # It also ensures that VS msbuild will use the downloaded sdk targets. + $env:PATH = "$dotnetRoot;$env:PATH" + + # Make Sure that our bootstrapped dotnet cli is available in future steps of the Azure Pipelines build + Write-PipelinePrependPath -Path $dotnetRoot + + Write-PipelineSetVariable -Name 'DOTNET_MULTILEVEL_LOOKUP' -Value '0' + Write-PipelineSetVariable -Name 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' -Value '1' + + return $global:_DotNetInstallDir = $dotnetRoot +} + +function Retry($downloadBlock, $maxRetries = 5) { + $retries = 1 + + while($true) { + try { + & $downloadBlock + break + } + catch { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_ + } + + if (++$retries -le $maxRetries) { + $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff + Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)." + Start-Sleep -Seconds $delayInSeconds + } + else { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to download file in $maxRetries attempts." + break + } + + } +} + +function GetDotNetInstallScript([string] $dotnetRoot) { + $installScript = Join-Path $dotnetRoot 'dotnet-install.ps1' + if (!(Test-Path $installScript)) { + Create-Directory $dotnetRoot + $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit + $uri = "https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1" + + Retry({ + Write-Host "GET $uri" + Invoke-WebRequest $uri -OutFile $installScript + }) + } + + return $installScript +} + +function InstallDotNetSdk([string] $dotnetRoot, [string] $version, [string] $architecture = '', [switch] $noPath) { + InstallDotNet $dotnetRoot $version $architecture '' $false $runtimeSourceFeed $runtimeSourceFeedKey -noPath:$noPath +} + +function InstallDotNet([string] $dotnetRoot, + [string] $version, + [string] $architecture = '', + [string] $runtime = '', + [bool] $skipNonVersionedFiles = $false, + [string] $runtimeSourceFeed = '', + [string] $runtimeSourceFeedKey = '', + [switch] $noPath) { + + $installScript = GetDotNetInstallScript $dotnetRoot + $installParameters = @{ + Version = $version + InstallDir = $dotnetRoot + } + + if ($architecture) { $installParameters.Architecture = $architecture } + if ($runtime) { $installParameters.Runtime = $runtime } + if ($skipNonVersionedFiles) { $installParameters.SkipNonVersionedFiles = $skipNonVersionedFiles } + if ($noPath) { $installParameters.NoPath = $True } + + try { + & $installScript @installParameters + } + catch { + if ($runtimeSourceFeed -or $runtimeSourceFeedKey) { + Write-Host "Failed to install dotnet from public location. Trying from '$runtimeSourceFeed'" + if ($runtimeSourceFeed) { $installParameters.AzureFeed = $runtimeSourceFeed } + + if ($runtimeSourceFeedKey) { + $decodedBytes = [System.Convert]::FromBase64String($runtimeSourceFeedKey) + $decodedString = [System.Text.Encoding]::UTF8.GetString($decodedBytes) + $installParameters.FeedCredential = $decodedString + } + + try { + & $installScript @installParameters + } + catch { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install dotnet from custom location '$runtimeSourceFeed'." + ExitWithExitCode 1 + } + } else { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install dotnet from public location." + ExitWithExitCode 1 + } + } +} + +# +# Locates Visual Studio MSBuild installation. +# The preference order for MSBuild to use is as follows: +# +# 1. MSBuild from an active VS command prompt +# 2. MSBuild from a compatible VS installation +# 3. MSBuild from the xcopy tool package +# +# Returns full path to msbuild.exe. +# Throws on failure. +# +function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = $null) { + if (-not (IsWindowsPlatform)) { + throw "Cannot initialize Visual Studio on non-Windows" + } + + if (Test-Path variable:global:_MSBuildExe) { + return $global:_MSBuildExe + } + + # Minimum VS version to require. + $vsMinVersionReqdStr = '16.8' + $vsMinVersionReqd = [Version]::new($vsMinVersionReqdStr) + + # If the version of msbuild is going to be xcopied, + # use this version. Version matches a package here: + # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=16.10.0-preview2&view=overview + $defaultXCopyMSBuildVersion = '16.10.0-preview2' + + if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs } + $vsMinVersionStr = if ($vsRequirements.version) { $vsRequirements.version } else { $vsMinVersionReqdStr } + $vsMinVersion = [Version]::new($vsMinVersionStr) + + # Try msbuild command available in the environment. + if ($env:VSINSTALLDIR -ne $null) { + $msbuildCmd = Get-Command 'msbuild.exe' -ErrorAction SilentlyContinue + if ($msbuildCmd -ne $null) { + # Workaround for https://github.com/dotnet/roslyn/issues/35793 + # Due to this issue $msbuildCmd.Version returns 0.0.0.0 for msbuild.exe 16.2+ + $msbuildVersion = [Version]::new((Get-Item $msbuildCmd.Path).VersionInfo.ProductVersion.Split([char[]]@('-', '+'))[0]) + + if ($msbuildVersion -ge $vsMinVersion) { + return $global:_MSBuildExe = $msbuildCmd.Path + } + + # Report error - the developer environment is initialized with incompatible VS version. + throw "Developer Command Prompt for VS $($env:VisualStudioVersion) is not recent enough. Please upgrade to $vsMinVersionStr or build from a plain CMD window" + } + } + + # Locate Visual Studio installation or download x-copy msbuild. + $vsInfo = LocateVisualStudio $vsRequirements + if ($vsInfo -ne $null) { + $vsInstallDir = $vsInfo.installationPath + $vsMajorVersion = $vsInfo.installationVersion.Split('.')[0] + + InitializeVisualStudioEnvironmentVariables $vsInstallDir $vsMajorVersion + } else { + + if (Get-Member -InputObject $GlobalJson.tools -Name 'xcopy-msbuild') { + $xcopyMSBuildVersion = $GlobalJson.tools.'xcopy-msbuild' + $vsMajorVersion = $xcopyMSBuildVersion.Split('.')[0] + } else { + #if vs version provided in global.json is incompatible (too low) then use the default version for xcopy msbuild download + if($vsMinVersion -lt $vsMinVersionReqd){ + Write-Host "Using xcopy-msbuild version of $defaultXCopyMSBuildVersion since VS version $vsMinVersionStr provided in global.json is not compatible" + $xcopyMSBuildVersion = $defaultXCopyMSBuildVersion + } + else{ + # If the VS version IS compatible, look for an xcopy msbuild package + # with a version matching VS. + # Note: If this version does not exist, then an explicit version of xcopy msbuild + # can be specified in global.json. This will be required for pre-release versions of msbuild. + $vsMajorVersion = $vsMinVersion.Major + $vsMinorVersion = $vsMinVersion.Minor + $xcopyMSBuildVersion = "$vsMajorVersion.$vsMinorVersion.0" + } + } + + $vsInstallDir = $null + if ($xcopyMSBuildVersion.Trim() -ine "none") { + $vsInstallDir = InitializeXCopyMSBuild $xcopyMSBuildVersion $install + if ($vsInstallDir -eq $null) { + throw "Could not xcopy msbuild. Please check that package 'RoslynTools.MSBuild @ $xcopyMSBuildVersion' exists on feed 'dotnet-eng'." + } + } + if ($vsInstallDir -eq $null) { + throw 'Unable to find Visual Studio that has required version and components installed' + } + } + + $msbuildVersionDir = if ([int]$vsMajorVersion -lt 16) { "$vsMajorVersion.0" } else { "Current" } + + $local:BinFolder = Join-Path $vsInstallDir "MSBuild\$msbuildVersionDir\Bin" + $local:Prefer64bit = if (Get-Member -InputObject $vsRequirements -Name 'Prefer64bit') { $vsRequirements.Prefer64bit } else { $false } + if ($local:Prefer64bit -and (Test-Path(Join-Path $local:BinFolder "amd64"))) { + $global:_MSBuildExe = Join-Path $local:BinFolder "amd64\msbuild.exe" + } else { + $global:_MSBuildExe = Join-Path $local:BinFolder "msbuild.exe" + } + + return $global:_MSBuildExe +} + +function InitializeVisualStudioEnvironmentVariables([string] $vsInstallDir, [string] $vsMajorVersion) { + $env:VSINSTALLDIR = $vsInstallDir + Set-Item "env:VS$($vsMajorVersion)0COMNTOOLS" (Join-Path $vsInstallDir "Common7\Tools\") + + $vsSdkInstallDir = Join-Path $vsInstallDir "VSSDK\" + if (Test-Path $vsSdkInstallDir) { + Set-Item "env:VSSDK$($vsMajorVersion)0Install" $vsSdkInstallDir + $env:VSSDKInstall = $vsSdkInstallDir + } +} + +function InstallXCopyMSBuild([string]$packageVersion) { + return InitializeXCopyMSBuild $packageVersion -install $true +} + +function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) { + $packageName = 'RoslynTools.MSBuild' + $packageDir = Join-Path $ToolsDir "msbuild\$packageVersion" + $packagePath = Join-Path $packageDir "$packageName.$packageVersion.nupkg" + + if (!(Test-Path $packageDir)) { + if (!$install) { + return $null + } + + Create-Directory $packageDir + + Write-Host "Downloading $packageName $packageVersion" + $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit + Retry({ + Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath + }) + + Unzip $packagePath $packageDir + } + + return Join-Path $packageDir 'tools' +} + +# +# Locates Visual Studio instance that meets the minimal requirements specified by tools.vs object in global.json. +# +# The following properties of tools.vs are recognized: +# "version": "{major}.{minor}" +# Two part minimal VS version, e.g. "15.9", "16.0", etc. +# "components": ["componentId1", "componentId2", ...] +# Array of ids of workload components that must be available in the VS instance. +# See e.g. https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-enterprise?view=vs-2017 +# +# Returns JSON describing the located VS instance (same format as returned by vswhere), +# or $null if no instance meeting the requirements is found on the machine. +# +function LocateVisualStudio([object]$vsRequirements = $null){ + if (-not (IsWindowsPlatform)) { + throw "Cannot run vswhere on non-Windows platforms." + } + + if (Get-Member -InputObject $GlobalJson.tools -Name 'vswhere') { + $vswhereVersion = $GlobalJson.tools.vswhere + } else { + $vswhereVersion = '2.5.2' + } + + $vsWhereDir = Join-Path $ToolsDir "vswhere\$vswhereVersion" + $vsWhereExe = Join-Path $vsWhereDir 'vswhere.exe' + + if (!(Test-Path $vsWhereExe)) { + Create-Directory $vsWhereDir + Write-Host 'Downloading vswhere' + Retry({ + Invoke-WebRequest "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe + }) + } + + if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs } + $args = @('-latest', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*') + + if (!$excludePrereleaseVS) { + $args += '-prerelease' + } + + if (Get-Member -InputObject $vsRequirements -Name 'version') { + $args += '-version' + $args += $vsRequirements.version + } + + if (Get-Member -InputObject $vsRequirements -Name 'components') { + foreach ($component in $vsRequirements.components) { + $args += '-requires' + $args += $component + } + } + + $vsInfo =& $vsWhereExe $args | ConvertFrom-Json + + if ($lastExitCode -ne 0) { + return $null + } + + # use first matching instance + return $vsInfo[0] +} + +function InitializeBuildTool() { + if (Test-Path variable:global:_BuildTool) { + # If the requested msbuild parameters do not match, clear the cached variables. + if($global:_BuildTool.Contains('ExcludePrereleaseVS') -and $global:_BuildTool.ExcludePrereleaseVS -ne $excludePrereleaseVS) { + Remove-Item variable:global:_BuildTool + Remove-Item variable:global:_MSBuildExe + } else { + return $global:_BuildTool + } + } + + if (-not $msbuildEngine) { + $msbuildEngine = GetDefaultMSBuildEngine + } + + # Initialize dotnet cli if listed in 'tools' + $dotnetRoot = $null + if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') { + $dotnetRoot = InitializeDotNetCli -install:$restore + } + + if ($msbuildEngine -eq 'dotnet') { + if (!$dotnetRoot) { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "/global.json must specify 'tools.dotnet'." + ExitWithExitCode 1 + } + $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet') + $buildTool = @{ Path = $dotnetPath; Command = 'msbuild'; Tool = 'dotnet'; Framework = 'netcoreapp3.1' } + } elseif ($msbuildEngine -eq "vs") { + try { + $msbuildPath = InitializeVisualStudioMSBuild -install:$restore + } catch { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_ + ExitWithExitCode 1 + } + + $buildTool = @{ Path = $msbuildPath; Command = ""; Tool = "vs"; Framework = "net472"; ExcludePrereleaseVS = $excludePrereleaseVS } + } else { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unexpected value of -msbuildEngine: '$msbuildEngine'." + ExitWithExitCode 1 + } + + return $global:_BuildTool = $buildTool +} + +function GetDefaultMSBuildEngine() { + # Presence of tools.vs indicates the repo needs to build using VS msbuild on Windows. + if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') { + return 'vs' + } + + if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') { + return 'dotnet' + } + + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "-msbuildEngine must be specified, or /global.json must specify 'tools.dotnet' or 'tools.vs'." + ExitWithExitCode 1 +} + +function GetNuGetPackageCachePath() { + if ($env:NUGET_PACKAGES -eq $null) { + # Use local cache on CI to ensure deterministic build. + # Avoid using the http cache as workaround for https://github.com/NuGet/Home/issues/3116 + # use global cache in dev builds to avoid cost of downloading packages. + # For directory normalization, see also: https://github.com/NuGet/Home/issues/7968 + if ($useGlobalNuGetCache) { + $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages\' + } else { + $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages\' + $env:RESTORENOCACHE = $true + } + } + + return $env:NUGET_PACKAGES +} + +# Returns a full path to an Arcade SDK task project file. +function GetSdkTaskProject([string]$taskName) { + return Join-Path (Split-Path (InitializeToolset) -Parent) "SdkTasks\$taskName.proj" +} + +function InitializeNativeTools() { + if (-Not (Test-Path variable:DisableNativeToolsetInstalls) -And (Get-Member -InputObject $GlobalJson -Name "native-tools")) { + $nativeArgs= @{} + if ($ci) { + $nativeArgs = @{ + InstallDirectory = "$ToolsDir" + } + } + & "$PSScriptRoot/init-tools-native.ps1" @nativeArgs + } +} + +function InitializeToolset() { + if (Test-Path variable:global:_ToolsetBuildProj) { + return $global:_ToolsetBuildProj + } + + $nugetCache = GetNuGetPackageCachePath + + $toolsetVersion = $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk' + $toolsetLocationFile = Join-Path $ToolsetDir "$toolsetVersion.txt" + + if (Test-Path $toolsetLocationFile) { + $path = Get-Content $toolsetLocationFile -TotalCount 1 + if (Test-Path $path) { + return $global:_ToolsetBuildProj = $path + } + } + + if (-not $restore) { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Toolset version $toolsetVersion has not been restored." + ExitWithExitCode 1 + } + + $buildTool = InitializeBuildTool + + $proj = Join-Path $ToolsetDir 'restore.proj' + $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'ToolsetRestore.binlog') } else { '' } + + '' | Set-Content $proj + + MSBuild-Core $proj $bl /t:__WriteToolsetLocation /clp:ErrorsOnly`;NoSummary /p:__ToolsetLocationOutputFile=$toolsetLocationFile + + $path = Get-Content $toolsetLocationFile -Encoding UTF8 -TotalCount 1 + if (!(Test-Path $path)) { + throw "Invalid toolset path: $path" + } + + return $global:_ToolsetBuildProj = $path +} + +function ExitWithExitCode([int] $exitCode) { + if ($ci -and $prepareMachine) { + Stop-Processes + } + exit $exitCode +} + +# Check if $LASTEXITCODE is a nonzero exit code (NZEC). If so, print a Azure Pipeline error for +# diagnostics, then exit the script with the $LASTEXITCODE. +function Exit-IfNZEC([string] $category = "General") { + Write-Host "Exit code $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + $message = "Last command failed with exit code $LASTEXITCODE." + Write-PipelineTelemetryError -Force -Category $category -Message $message + ExitWithExitCode $LASTEXITCODE + } +} + +function Stop-Processes() { + Write-Host 'Killing running build processes...' + foreach ($processName in $processesToStopOnExit) { + Get-Process -Name $processName -ErrorAction SilentlyContinue | Stop-Process + } +} + +# +# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function. +# The arguments are automatically quoted. +# Terminates the script if the build fails. +# +function MSBuild() { + if ($pipelinesLog) { + $buildTool = InitializeBuildTool + + if ($ci -and $buildTool.Tool -eq 'dotnet') { + $env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS = 20 + $env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS = 20 + Write-PipelineSetVariable -Name 'NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS' -Value '20' + Write-PipelineSetVariable -Name 'NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS' -Value '20' + } + + Enable-Nuget-EnhancedRetry + + $toolsetBuildProject = InitializeToolset + $basePath = Split-Path -parent $toolsetBuildProject + $possiblePaths = @( + # new scripts need to work with old packages, so we need to look for the old names/versions + (Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.ArcadeLogging.dll')), + (Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.Arcade.Sdk.dll')), + (Join-Path $basePath (Join-Path netcoreapp2.1 'Microsoft.DotNet.ArcadeLogging.dll')), + (Join-Path $basePath (Join-Path netcoreapp2.1 'Microsoft.DotNet.Arcade.Sdk.dll')) + (Join-Path $basePath (Join-Path netcoreapp3.1 'Microsoft.DotNet.ArcadeLogging.dll')), + (Join-Path $basePath (Join-Path netcoreapp3.1 'Microsoft.DotNet.Arcade.Sdk.dll')) + ) + $selectedPath = $null + foreach ($path in $possiblePaths) { + if (Test-Path $path -PathType Leaf) { + $selectedPath = $path + break + } + } + if (-not $selectedPath) { + Write-PipelineTelemetryError -Category 'Build' -Message 'Unable to find arcade sdk logger assembly.' + ExitWithExitCode 1 + } + $args += "/logger:$selectedPath" + } + + MSBuild-Core @args +} + +# +# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function. +# The arguments are automatically quoted. +# Terminates the script if the build fails. +# +function MSBuild-Core() { + if ($ci) { + if (!$binaryLog -and !$excludeCIBinarylog) { + Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build, or explicitly opted-out from with the -excludeCIBinarylog switch.' + ExitWithExitCode 1 + } + + if ($nodeReuse) { + Write-PipelineTelemetryError -Category 'Build' -Message 'Node reuse must be disabled in CI build.' + ExitWithExitCode 1 + } + } + + Enable-Nuget-EnhancedRetry + + $buildTool = InitializeBuildTool + + $cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci" + + if ($warnAsError) { + $cmdArgs += ' /warnaserror /p:TreatWarningsAsErrors=true' + } + else { + $cmdArgs += ' /p:TreatWarningsAsErrors=false' + } + + foreach ($arg in $args) { + if ($null -ne $arg -and $arg.Trim() -ne "") { + if ($arg.EndsWith('\')) { + $arg = $arg + "\" + } + $cmdArgs += " `"$arg`"" + } + } + + $env:ARCADE_BUILD_TOOL_COMMAND = "$($buildTool.Path) $cmdArgs" + + $exitCode = Exec-Process $buildTool.Path $cmdArgs + + if ($exitCode -ne 0) { + # We should not Write-PipelineTaskError here because that message shows up in the build summary + # The build already logged an error, that's the reason it failed. Producing an error here only adds noise. + Write-Host "Build failed with exit code $exitCode. Check errors above." -ForegroundColor Red + + $buildLog = GetMSBuildBinaryLogCommandLineArgument $args + if ($null -ne $buildLog) { + Write-Host "See log: $buildLog" -ForegroundColor DarkGray + } + + if ($ci) { + Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed." + # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error + # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error + ExitWithExitCode 0 + } else { + ExitWithExitCode $exitCode + } + } +} + +function GetMSBuildBinaryLogCommandLineArgument($arguments) { + foreach ($argument in $arguments) { + if ($argument -ne $null) { + $arg = $argument.Trim() + if ($arg.StartsWith('/bl:', "OrdinalIgnoreCase")) { + return $arg.Substring('/bl:'.Length) + } + + if ($arg.StartsWith('/binaryLogger:', 'OrdinalIgnoreCase')) { + return $arg.Substring('/binaryLogger:'.Length) + } + } + } + + return $null +} + +function GetExecutableFileName($baseName) { + if (IsWindowsPlatform) { + return "$baseName.exe" + } + else { + return $baseName + } +} + +function IsWindowsPlatform() { + return [environment]::OSVersion.Platform -eq [PlatformID]::Win32NT +} + +function Get-Darc($version) { + $darcPath = "$TempDir\darc\$(New-Guid)" + if ($version -ne $null) { + & $PSScriptRoot\darc-init.ps1 -toolpath $darcPath -darcVersion $version | Out-Host + } else { + & $PSScriptRoot\darc-init.ps1 -toolpath $darcPath | Out-Host + } + return "$darcPath\darc.exe" +} + +. $PSScriptRoot\pipeline-logging-functions.ps1 + +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\') +$EngRoot = Resolve-Path (Join-Path $PSScriptRoot '..') +$ArtifactsDir = Join-Path $RepoRoot 'artifacts' +$ToolsetDir = Join-Path $ArtifactsDir 'toolset' +$ToolsDir = Join-Path $RepoRoot '.tools' +$LogDir = Join-Path (Join-Path $ArtifactsDir 'log') $configuration +$TempDir = Join-Path (Join-Path $ArtifactsDir 'tmp') $configuration +$GlobalJson = Get-Content -Raw -Path (Join-Path $RepoRoot 'global.json') | ConvertFrom-Json +# true if global.json contains a "runtimes" section +$globalJsonHasRuntimes = if ($GlobalJson.tools.PSObject.Properties.Name -Match 'runtimes') { $true } else { $false } + +Create-Directory $ToolsetDir +Create-Directory $TempDir +Create-Directory $LogDir + +Write-PipelineSetVariable -Name 'Artifacts' -Value $ArtifactsDir +Write-PipelineSetVariable -Name 'Artifacts.Toolset' -Value $ToolsetDir +Write-PipelineSetVariable -Name 'Artifacts.Log' -Value $LogDir +Write-PipelineSetVariable -Name 'TEMP' -Value $TempDir +Write-PipelineSetVariable -Name 'TMP' -Value $TempDir + +# Import custom tools configuration, if present in the repo. +# Note: Import in global scope so that the script set top-level variables without qualification. +if (!$disableConfigureToolsetImport) { + $configureToolsetScript = Join-Path $EngRoot 'configure-toolset.ps1' + if (Test-Path $configureToolsetScript) { + . $configureToolsetScript + if ((Test-Path variable:failOnConfigureToolsetError) -And $failOnConfigureToolsetError) { + if ((Test-Path variable:LastExitCode) -And ($LastExitCode -ne 0)) { + Write-PipelineTelemetryError -Category 'Build' -Message 'configure-toolset.ps1 returned a non-zero exit code' + ExitWithExitCode $LastExitCode + } + } + } +} + +function Try-LogClientIpAddress() +{ + Write-Host "Attempting to log this client's IP for Azure Package feed telemetry purposes" + try + { + $result = Invoke-WebRequest -Uri "http://co1.msedge.net/fdv2/diagnostics.aspx" -UseBasicParsing + $lines = $result.Content.Split([Environment]::NewLine) + $socketIp = $lines | Select-String -Pattern "^Socket IP:.*" + Write-Host $socketIp + $clientIp = $lines | Select-String -Pattern "^Client IP:.*" + Write-Host $clientIp + } + catch + { + Write-Host "Unable to get this machine's effective IP address for logging: $_" + } +} + +# +# If $ci flag is set, turn on (and log that we did) special environment variables for improved Nuget client retry logic. +# +function Enable-Nuget-EnhancedRetry() { + if ($ci) { + Write-Host "Setting NUGET enhanced retry environment variables" + $env:NUGET_ENABLE_EXPERIMENTAL_HTTP_RETRY = 'true' + $env:NUGET_EXPERIMENTAL_MAX_NETWORK_TRY_COUNT = 6 + $env:NUGET_EXPERIMENTAL_NETWORK_RETRY_DELAY_MILLISECONDS = 1000 + Write-PipelineSetVariable -Name 'NUGET_ENABLE_EXPERIMENTAL_HTTP_RETRY' -Value 'true' + Write-PipelineSetVariable -Name 'NUGET_EXPERIMENTAL_MAX_NETWORK_TRY_COUNT' -Value '6' + Write-PipelineSetVariable -Name 'NUGET_EXPERIMENTAL_NETWORK_RETRY_DELAY_MILLISECONDS' -Value '1000' + } +} \ No newline at end of file diff --git a/eng/common/tools.sh b/eng/common/tools.sh new file mode 100644 index 000000000000..bd89e2a2c952 --- /dev/null +++ b/eng/common/tools.sh @@ -0,0 +1,551 @@ +#!/usr/bin/env bash + +# Initialize variables if they aren't already defined. + +# CI mode - set to true on CI server for PR validation build or official build. +ci=${ci:-false} + +# Set to true to use the pipelines logger which will enable Azure logging output. +# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md +# This flag is meant as a temporary opt-opt for the feature while validate it across +# our consumers. It will be deleted in the future. +if [[ "$ci" == true ]]; then + pipelines_log=${pipelines_log:-true} +else + pipelines_log=${pipelines_log:-false} +fi + +# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names. +configuration=${configuration:-'Debug'} + +# Set to true to opt out of outputting binary log while running in CI +exclude_ci_binary_log=${exclude_ci_binary_log:-false} + +if [[ "$ci" == true && "$exclude_ci_binary_log" == false ]]; then + binary_log_default=true +else + binary_log_default=false +fi + +# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build. +binary_log=${binary_log:-$binary_log_default} + +# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes). +prepare_machine=${prepare_machine:-false} + +# True to restore toolsets and dependencies. +restore=${restore:-true} + +# Adjusts msbuild verbosity level. +verbosity=${verbosity:-'minimal'} + +# Set to true to reuse msbuild nodes. Recommended to not reuse on CI. +if [[ "$ci" == true ]]; then + node_reuse=${node_reuse:-false} +else + node_reuse=${node_reuse:-true} +fi + +# Configures warning treatment in msbuild. +warn_as_error=${warn_as_error:-true} + +# True to attempt using .NET Core already that meets requirements specified in global.json +# installed on the machine instead of downloading one. +use_installed_dotnet_cli=${use_installed_dotnet_cli:-true} + +# Enable repos to use a particular version of the on-line dotnet-install scripts. +# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh +dotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'} + +# True to use global NuGet cache instead of restoring packages to repository-local directory. +if [[ "$ci" == true ]]; then + use_global_nuget_cache=${use_global_nuget_cache:-false} +else + use_global_nuget_cache=${use_global_nuget_cache:-true} +fi + +# Used when restoring .NET SDK from alternative feeds +runtime_source_feed=${runtime_source_feed:-''} +runtime_source_feed_key=${runtime_source_feed_key:-''} + +# Resolve any symlinks in the given path. +function ResolvePath { + local path=$1 + + while [[ -h $path ]]; do + local dir="$( cd -P "$( dirname "$path" )" && pwd )" + path="$(readlink "$path")" + + # if $path was a relative symlink, we need to resolve it relative to the path where the + # symlink file was located + [[ $path != /* ]] && path="$dir/$path" + done + + # return value + _ResolvePath="$path" +} + +# ReadVersionFromJson [json key] +function ReadGlobalVersion { + local key=$1 + + if command -v jq &> /dev/null; then + _ReadGlobalVersion="$(jq -r ".[] | select(has(\"$key\")) | .\"$key\"" "$global_json_file")" + elif [[ "$(cat "$global_json_file")" =~ \"$key\"[[:space:]\:]*\"([^\"]+) ]]; then + _ReadGlobalVersion=${BASH_REMATCH[1]} + fi + + if [[ -z "$_ReadGlobalVersion" ]]; then + Write-PipelineTelemetryError -category 'Build' "Error: Cannot find \"$key\" in $global_json_file" + ExitWithExitCode 1 + fi +} + +function InitializeDotNetCli { + if [[ -n "${_InitializeDotNetCli:-}" ]]; then + return + fi + + local install=$1 + + # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism + export DOTNET_MULTILEVEL_LOOKUP=0 + + # Disable first run since we want to control all package sources + export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + + # Disable telemetry on CI + if [[ $ci == true ]]; then + export DOTNET_CLI_TELEMETRY_OPTOUT=1 + fi + + # LTTNG is the logging infrastructure used by Core CLR. Need this variable set + # so it doesn't output warnings to the console. + export LTTNG_HOME="$HOME" + + # Source Build uses DotNetCoreSdkDir variable + if [[ -n "${DotNetCoreSdkDir:-}" ]]; then + export DOTNET_INSTALL_DIR="$DotNetCoreSdkDir" + fi + + # Find the first path on $PATH that contains the dotnet.exe + if [[ "$use_installed_dotnet_cli" == true && $global_json_has_runtimes == false && -z "${DOTNET_INSTALL_DIR:-}" ]]; then + local dotnet_path=`command -v dotnet` + if [[ -n "$dotnet_path" ]]; then + ResolvePath "$dotnet_path" + export DOTNET_INSTALL_DIR=`dirname "$_ResolvePath"` + fi + fi + + ReadGlobalVersion "dotnet" + local dotnet_sdk_version=$_ReadGlobalVersion + local dotnet_root="" + + # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version, + # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues. + if [[ $global_json_has_runtimes == false && -n "${DOTNET_INSTALL_DIR:-}" && -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then + dotnet_root="$DOTNET_INSTALL_DIR" + else + dotnet_root="$repo_root/.dotnet" + + export DOTNET_INSTALL_DIR="$dotnet_root" + + if [[ ! -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then + if [[ "$install" == true ]]; then + InstallDotNetSdk "$dotnet_root" "$dotnet_sdk_version" + else + Write-PipelineTelemetryError -category 'InitializeToolset' "Unable to find dotnet with SDK version '$dotnet_sdk_version'" + ExitWithExitCode 1 + fi + fi + fi + + # Add dotnet to PATH. This prevents any bare invocation of dotnet in custom + # build steps from using anything other than what we've downloaded. + Write-PipelinePrependPath -path "$dotnet_root" + + Write-PipelineSetVariable -name "DOTNET_MULTILEVEL_LOOKUP" -value "0" + Write-PipelineSetVariable -name "DOTNET_SKIP_FIRST_TIME_EXPERIENCE" -value "1" + + # return value + _InitializeDotNetCli="$dotnet_root" +} + +function InstallDotNetSdk { + local root=$1 + local version=$2 + local architecture="unset" + if [[ $# -ge 3 ]]; then + architecture=$3 + fi + InstallDotNet "$root" "$version" $architecture 'sdk' 'false' $runtime_source_feed $runtime_source_feed_key +} + +function InstallDotNet { + local root=$1 + local version=$2 + + GetDotNetInstallScript "$root" + local install_script=$_GetDotNetInstallScript + + local archArg='' + if [[ -n "${3:-}" ]] && [ "$3" != 'unset' ]; then + archArg="--architecture $3" + fi + local runtimeArg='' + if [[ -n "${4:-}" ]] && [ "$4" != 'sdk' ]; then + runtimeArg="--runtime $4" + fi + local skipNonVersionedFilesArg="" + if [[ "$#" -ge "5" ]] && [[ "$5" != 'false' ]]; then + skipNonVersionedFilesArg="--skip-non-versioned-files" + fi + bash "$install_script" --version $version --install-dir "$root" $archArg $runtimeArg $skipNonVersionedFilesArg || { + local exit_code=$? + echo "Failed to install dotnet SDK from public location (exit code '$exit_code')." + + local runtimeSourceFeed='' + if [[ -n "${6:-}" ]]; then + runtimeSourceFeed="--azure-feed $6" + fi + + local runtimeSourceFeedKey='' + if [[ -n "${7:-}" ]]; then + # The 'base64' binary on alpine uses '-d' and doesn't support '--decode' + # '-d'. To work around this, do a simple detection and switch the parameter + # accordingly. + decodeArg="--decode" + if base64 --help 2>&1 | grep -q "BusyBox"; then + decodeArg="-d" + fi + decodedFeedKey=`echo $7 | base64 $decodeArg` + runtimeSourceFeedKey="--feed-credential $decodedFeedKey" + fi + + if [[ -n "$runtimeSourceFeed" || -n "$runtimeSourceFeedKey" ]]; then + bash "$install_script" --version $version --install-dir "$root" $archArg $runtimeArg $skipNonVersionedFilesArg $runtimeSourceFeed $runtimeSourceFeedKey || { + local exit_code=$? + Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK from custom location '$runtimeSourceFeed' (exit code '$exit_code')." + ExitWithExitCode $exit_code + } + else + if [[ $exit_code != 0 ]]; then + Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK from public location (exit code '$exit_code')." + fi + ExitWithExitCode $exit_code + fi + } +} + +function with_retries { + local maxRetries=5 + local retries=1 + echo "Trying to run '$@' for maximum of $maxRetries attempts." + while [[ $((retries++)) -le $maxRetries ]]; do + "$@" + + if [[ $? == 0 ]]; then + echo "Ran '$@' successfully." + return 0 + fi + + timeout=$((3**$retries-1)) + echo "Failed to execute '$@'. Waiting $timeout seconds before next attempt ($retries out of $maxRetries)." 1>&2 + sleep $timeout + done + + echo "Failed to execute '$@' for $maxRetries times." 1>&2 + + return 1 +} + +function GetDotNetInstallScript { + local root=$1 + local install_script="$root/dotnet-install.sh" + local install_script_url="https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh" + + if [[ ! -a "$install_script" ]]; then + mkdir -p "$root" + + echo "Downloading '$install_script_url'" + + # Use curl if available, otherwise use wget + if command -v curl > /dev/null; then + # first, try directly, if this fails we will retry with verbose logging + curl "$install_script_url" -sSL --retry 10 --create-dirs -o "$install_script" || { + if command -v openssl &> /dev/null; then + echo "Curl failed; dumping some information about dotnet.microsoft.com for later investigation" + echo | openssl s_client -showcerts -servername dotnet.microsoft.com -connect dotnet.microsoft.com:443 + fi + echo "Will now retry the same URL with verbose logging." + with_retries curl "$install_script_url" -sSL --verbose --retry 10 --create-dirs -o "$install_script" || { + local exit_code=$? + Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnet install script (exit code '$exit_code')." + ExitWithExitCode $exit_code + } + } + else + with_retries wget -v -O "$install_script" "$install_script_url" || { + local exit_code=$? + Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnet install script (exit code '$exit_code')." + ExitWithExitCode $exit_code + } + fi + fi + # return value + _GetDotNetInstallScript="$install_script" +} + +function InitializeBuildTool { + if [[ -n "${_InitializeBuildTool:-}" ]]; then + return + fi + + InitializeDotNetCli $restore + + # return values + _InitializeBuildTool="$_InitializeDotNetCli/dotnet" + _InitializeBuildToolCommand="msbuild" + _InitializeBuildToolFramework="netcoreapp3.1" +} + +# Set RestoreNoCache as a workaround for https://github.com/NuGet/Home/issues/3116 +function GetNuGetPackageCachePath { + if [[ -z ${NUGET_PACKAGES:-} ]]; then + if [[ "$use_global_nuget_cache" == true ]]; then + export NUGET_PACKAGES="$HOME/.nuget/packages" + else + export NUGET_PACKAGES="$repo_root/.packages" + export RESTORENOCACHE=true + fi + fi + + # return value + _GetNuGetPackageCachePath=$NUGET_PACKAGES +} + +function InitializeNativeTools() { + if [[ -n "${DisableNativeToolsetInstalls:-}" ]]; then + return + fi + if grep -Fq "native-tools" $global_json_file + then + local nativeArgs="" + if [[ "$ci" == true ]]; then + nativeArgs="--installDirectory $tools_dir" + fi + "$_script_dir/init-tools-native.sh" $nativeArgs + fi +} + +function InitializeToolset { + if [[ -n "${_InitializeToolset:-}" ]]; then + return + fi + + GetNuGetPackageCachePath + + ReadGlobalVersion "Microsoft.DotNet.Arcade.Sdk" + + local toolset_version=$_ReadGlobalVersion + local toolset_location_file="$toolset_dir/$toolset_version.txt" + + if [[ -a "$toolset_location_file" ]]; then + local path=`cat "$toolset_location_file"` + if [[ -a "$path" ]]; then + # return value + _InitializeToolset="$path" + return + fi + fi + + if [[ "$restore" != true ]]; then + Write-PipelineTelemetryError -category 'InitializeToolset' "Toolset version $toolset_version has not been restored." + ExitWithExitCode 2 + fi + + local proj="$toolset_dir/restore.proj" + + local bl="" + if [[ "$binary_log" == true ]]; then + bl="/bl:$log_dir/ToolsetRestore.binlog" + fi + + echo '' > "$proj" + MSBuild-Core "$proj" $bl /t:__WriteToolsetLocation /clp:ErrorsOnly\;NoSummary /p:__ToolsetLocationOutputFile="$toolset_location_file" + + local toolset_build_proj=`cat "$toolset_location_file"` + + if [[ ! -a "$toolset_build_proj" ]]; then + Write-PipelineTelemetryError -category 'Build' "Invalid toolset path: $toolset_build_proj" + ExitWithExitCode 3 + fi + + # return value + _InitializeToolset="$toolset_build_proj" +} + +function ExitWithExitCode { + if [[ "$ci" == true && "$prepare_machine" == true ]]; then + StopProcesses + fi + exit $1 +} + +function StopProcesses { + echo "Killing running build processes..." + pkill -9 "dotnet" || true + pkill -9 "vbcscompiler" || true + return 0 +} + +function TryLogClientIpAddress () { + echo 'Attempting to log this client''s IP for Azure Package feed telemetry purposes' + if command -v curl > /dev/null; then + curl -s 'http://co1.msedge.net/fdv2/diagnostics.aspx' | grep ' IP: ' || true + fi +} + +function MSBuild { + local args=$@ + if [[ "$pipelines_log" == true ]]; then + InitializeBuildTool + InitializeToolset + + if [[ "$ci" == true ]]; then + export NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS=20 + export NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS=20 + Write-PipelineSetVariable -name "NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS" -value "20" + Write-PipelineSetVariable -name "NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS" -value "20" + + export NUGET_ENABLE_EXPERIMENTAL_HTTP_RETRY=true + export NUGET_EXPERIMENTAL_MAX_NETWORK_TRY_COUNT=6 + export NUGET_EXPERIMENTAL_NETWORK_RETRY_DELAY_MILLISECONDS=1000 + Write-PipelineSetVariable -name "NUGET_ENABLE_EXPERIMENTAL_HTTP_RETRY" -value "true" + Write-PipelineSetVariable -name "NUGET_EXPERIMENTAL_MAX_NETWORK_TRY_COUNT" -value "6" + Write-PipelineSetVariable -name "NUGET_EXPERIMENTAL_NETWORK_RETRY_DELAY_MILLISECONDS" -value "1000" + fi + + local toolset_dir="${_InitializeToolset%/*}" + # new scripts need to work with old packages, so we need to look for the old names/versions + local selectedPath= + local possiblePaths=() + possiblePaths+=( "$toolset_dir/$_InitializeBuildToolFramework/Microsoft.DotNet.ArcadeLogging.dll" ) + possiblePaths+=( "$toolset_dir/$_InitializeBuildToolFramework/Microsoft.DotNet.Arcade.Sdk.dll" ) + possiblePaths+=( "$toolset_dir/netcoreapp2.1/Microsoft.DotNet.ArcadeLogging.dll" ) + possiblePaths+=( "$toolset_dir/netcoreapp2.1/Microsoft.DotNet.Arcade.Sdk.dll" ) + possiblePaths+=( "$toolset_dir/netcoreapp3.1/Microsoft.DotNet.ArcadeLogging.dll" ) + possiblePaths+=( "$toolset_dir/netcoreapp3.1/Microsoft.DotNet.Arcade.Sdk.dll" ) + for path in "${possiblePaths[@]}"; do + if [[ -f $path ]]; then + selectedPath=$path + break + fi + done + if [[ -z "$selectedPath" ]]; then + Write-PipelineTelemetryError -category 'Build' "Unable to find arcade sdk logger assembly." + ExitWithExitCode 1 + fi + args+=( "-logger:$selectedPath" ) + fi + + MSBuild-Core ${args[@]} +} + +function MSBuild-Core { + if [[ "$ci" == true ]]; then + if [[ "$binary_log" != true && "$exclude_ci_binary_log" != true ]]; then + Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build, or explicitly opted-out from with the -noBinaryLog switch." + ExitWithExitCode 1 + fi + + if [[ "$node_reuse" == true ]]; then + Write-PipelineTelemetryError -category 'Build' "Node reuse must be disabled in CI build." + ExitWithExitCode 1 + fi + fi + + InitializeBuildTool + + local warnaserror_switch="" + if [[ $warn_as_error == true ]]; then + warnaserror_switch="/warnaserror" + fi + + function RunBuildTool { + export ARCADE_BUILD_TOOL_COMMAND="$_InitializeBuildTool $@" + + "$_InitializeBuildTool" "$@" || { + local exit_code=$? + # We should not Write-PipelineTaskError here because that message shows up in the build summary + # The build already logged an error, that's the reason it failed. Producing an error here only adds noise. + echo "Build failed with exit code $exit_code. Check errors above." + if [[ "$ci" == "true" ]]; then + Write-PipelineSetResult -result "Failed" -message "msbuild execution failed." + # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error + # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error + ExitWithExitCode 0 + else + ExitWithExitCode $exit_code + fi + } + } + + RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@" +} + +ResolvePath "${BASH_SOURCE[0]}" +_script_dir=`dirname "$_ResolvePath"` + +. "$_script_dir/pipeline-logging-functions.sh" + +eng_root=`cd -P "$_script_dir/.." && pwd` +repo_root=`cd -P "$_script_dir/../.." && pwd` +repo_root="${repo_root}/" +artifacts_dir="${repo_root}artifacts" +toolset_dir="$artifacts_dir/toolset" +tools_dir="${repo_root}.tools" +log_dir="$artifacts_dir/log/$configuration" +temp_dir="$artifacts_dir/tmp/$configuration" + +global_json_file="${repo_root}global.json" +# determine if global.json contains a "runtimes" entry +global_json_has_runtimes=false +if command -v jq &> /dev/null; then + if jq -er '. | select(has("runtimes"))' "$global_json_file" &> /dev/null; then + global_json_has_runtimes=true + fi +elif [[ "$(cat "$global_json_file")" =~ \"runtimes\"[[:space:]\:]*\{ ]]; then + global_json_has_runtimes=true +fi + +# HOME may not be defined in some scenarios, but it is required by NuGet +if [[ -z $HOME ]]; then + export HOME="${repo_root}artifacts/.home/" + mkdir -p "$HOME" +fi + +mkdir -p "$toolset_dir" +mkdir -p "$temp_dir" +mkdir -p "$log_dir" + +Write-PipelineSetVariable -name "Artifacts" -value "$artifacts_dir" +Write-PipelineSetVariable -name "Artifacts.Toolset" -value "$toolset_dir" +Write-PipelineSetVariable -name "Artifacts.Log" -value "$log_dir" +Write-PipelineSetVariable -name "Temp" -value "$temp_dir" +Write-PipelineSetVariable -name "TMP" -value "$temp_dir" + +# Import custom tools configuration, if present in the repo. +if [ -z "${disable_configure_toolset_import:-}" ]; then + configure_toolset_script="$eng_root/configure-toolset.sh" + if [[ -a "$configure_toolset_script" ]]; then + . "$configure_toolset_script" + fi +fi + +# TODO: https://github.com/dotnet/arcade/issues/1468 +# Temporary workaround to avoid breaking change. +# Remove once repos are updated. +if [[ -n "${useInstalledDotNetCli:-}" ]]; then + use_installed_dotnet_cli="$useInstalledDotNetCli" +fi \ No newline at end of file diff --git a/mk/mono.mk b/mk/mono.mk index c29f5e41671f..e8db7ff08978 100644 --- a/mk/mono.mk +++ b/mk/mono.mk @@ -1,4 +1,4 @@ -NEEDED_MONO_VERSION := 3cf59ad33daa57120ec2d3ca97cfdff4c89ca372 +NEEDED_MONO_VERSION := 4150e65c9e3fb6a63afe6ac7f6ad9e90a7df971b NEEDED_MONO_BRANCH := 2020-02 MONO_DIRECTORY := mono diff --git a/mk/xamarin.mk b/mk/xamarin.mk index d422819760fe..a28524f8772d 100644 --- a/mk/xamarin.mk +++ b/mk/xamarin.mk @@ -7,7 +7,7 @@ MONO_BRANCH := $(shell cd $(MONO_PATH) 2> /dev/null && git symbolic-ref --sho endif ifdef ENABLE_XAMARIN -NEEDED_MACCORE_VERSION := 6f0bf5e2f40be0afe10b23995604808a5bc48959 +NEEDED_MACCORE_VERSION := 0be9399a534a1b7d28275a1629d95ed092fbfaa8 NEEDED_MACCORE_BRANCH := main MACCORE_DIRECTORY := maccore diff --git a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.Designer.cs b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.Designer.cs index da8834ab7862..5b96842decbd 100644 --- a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.Designer.cs +++ b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.Designer.cs @@ -1930,6 +1930,15 @@ public static string E7084 { } } + /// + /// Looks up a localized string similar to The value '{0}' is invalid for the Compress property. Valid values: 'true', 'false' or 'auto'.. + /// + public static string E7086 { + get { + return ResourceManager.GetString("E7086", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid framework: {0}. /// @@ -2528,5 +2537,23 @@ public static string W0176 { return ResourceManager.GetString("W0176", resourceCulture); } } + + /// + /// Looks up a localized string similar to Creating a compressed binding resource package because there are symlinks in the input.. + /// + public static string W7085 { + get { + return ResourceManager.GetString("W7085", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected a 'manifest' file in the directory {0}.. + /// + public static string W7087 { + get { + return ResourceManager.GetString("W7087", resourceCulture); + } + } } } diff --git a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx index 1a290defab80..d1020f2eeca7 100644 --- a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx +++ b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx @@ -1329,4 +1329,18 @@ {0}: the target directory (in the app bundle) for the font file + + + Creating a compressed binding resource package because there are symlinks in the input. + + + + The value '{0}' is invalid for the Compress property. Valid values: 'true', 'false' or 'auto'. + The following are literal names and should not be translated: Compress, true, false, auto. + + + + Expected a 'manifest' file in the directory {0}. + The following are literal names and should not be translated: manifest + diff --git a/msbuild/Xamarin.Mac.Tasks/Tasks/BTouch.cs b/msbuild/Xamarin.Mac.Tasks/Tasks/BTouch.cs deleted file mode 100644 index 7fcd6d2100a3..000000000000 --- a/msbuild/Xamarin.Mac.Tasks/Tasks/BTouch.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Xamarin.MacDev.Tasks; - -namespace Xamarin.Mac.Tasks -{ - public class BTouch : BTouchTaskBase - { - } -} diff --git a/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Tasks.csproj b/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Tasks.csproj index 0a8a6907c881..9f8020603f0d 100644 --- a/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Tasks.csproj +++ b/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Tasks.csproj @@ -5,6 +5,7 @@ false true ../../product.snk + $(NoWarn);8002 diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CreateBindingResourcePackageBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CreateBindingResourcePackageBase.cs index ac5478e8d26b..7c0f2e62dbea 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CreateBindingResourcePackageBase.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CreateBindingResourcePackageBase.cs @@ -7,24 +7,23 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; + using Xamarin.Localization.MSBuild; +using Xamarin.Utils; namespace Xamarin.MacDev.Tasks { public abstract class CreateBindingResourcePackageBase : XamarinTask { [Required] - public string OutputPath { get; set; } - - [Required] - public ITaskItem[] NativeReferences { get; set; } - + public string Compress { get; set; } + [Required] - public string ProjectDir { get; set; } - + public string BindingResourcePath { get; set; } + [Required] - public string BindingAssembly { get; set; } - - [Output] - public ITaskItem Manifest { get; set; } + public string IntermediateOutputPath { get; set; } + + [Required] + public ITaskItem[] NativeReferences { get; set; } public override bool Execute () { @@ -34,18 +33,65 @@ public override bool Execute () return false; } - string bindingResourcePath = Path.Combine (ProjectDir, OutputPath, Path.ChangeExtension (Path.GetFileName (BindingAssembly), ".resources")); - Log.LogMessage (MSBStrings.M0121, bindingResourcePath); + var compress = false; + if (string.Equals (Compress, "true", StringComparison.OrdinalIgnoreCase)) { + compress = true; + } else if (string.Equals (Compress, "false", StringComparison.OrdinalIgnoreCase)) { + compress = false; + } else if (string.Equals (Compress, "auto", StringComparison.OrdinalIgnoreCase)) { + compress = ContainsSymlinks (NativeReferences); + if (compress) + Log.LogMessage (MessageImportance.Low, MSBStrings.W7085 /* "Creating a compressed binding resource package because there are symlinks in the input." */); + } else { + Log.LogError (MSBStrings.E7086 /* "The value '{0}' is invalid for the Compress property. Valid values: 'true', 'false' or 'auto'." */, Compress); + } + + Directory.CreateDirectory (compress ? IntermediateOutputPath : BindingResourcePath); + + var manifestDirectory = compress ? IntermediateOutputPath : BindingResourcePath; + var manifestPath = CreateManifest (manifestDirectory); - Directory.CreateDirectory (bindingResourcePath); - foreach (var nativeRef in NativeReferences) - Xamarin.Bundler.FileCopier.UpdateDirectory (nativeRef.ItemSpec, bindingResourcePath); + if (compress) { + var zipFile = Path.GetFullPath (BindingResourcePath + ".zip"); + Log.LogMessage (MSBStrings.M0121, zipFile); + if (File.Exists (zipFile)) + File.Delete (zipFile); + Directory.CreateDirectory (Path.GetDirectoryName (zipFile)); - string manifestPath = CreateManifest (bindingResourcePath); + var filesToZip = NativeReferences.Select (v => v.ItemSpec).ToList (); + filesToZip.Add (manifestPath); - Manifest = new TaskItem ("Manifest") { ItemSpec = manifestPath }; + foreach (var nativeRef in filesToZip) { + var zipArguments = new List (); + zipArguments.Add ("-9"); + zipArguments.Add ("-r"); + zipArguments.Add ("-y"); + zipArguments.Add (zipFile); + + var fullPath = Path.GetFullPath (nativeRef); + var workingDirectory = Path.GetDirectoryName (fullPath); + zipArguments.Add (Path.GetFileName (fullPath)); + ExecuteAsync ("zip", zipArguments, workingDirectory: workingDirectory).Wait (); + } + } else { + var bindingResourcePath = BindingResourcePath; + Log.LogMessage (MSBStrings.M0121, bindingResourcePath); + Directory.CreateDirectory (bindingResourcePath); + foreach (var nativeRef in NativeReferences) + Xamarin.Bundler.FileCopier.UpdateDirectory (nativeRef.ItemSpec, bindingResourcePath); + } + + return !Log.HasLoggedErrors; + } + + static bool ContainsSymlinks (ITaskItem[] items) + { + foreach (var item in items) { + if (PathUtils.IsSymlinkOrContainsSymlinks (item.ItemSpec)) + return true; + } - return true; + return false; } string [] NativeReferenceAttributeNames = new string [] { "Kind", "ForceLoad", "SmartLink", "Frameworks", "WeakFrameworks", "LinkerFlags", "NeedsGccExceptionHandling", "IsCxx"}; diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ResolveFrameworksBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ResolveFrameworksBase.cs index 0e8b4c528d64..54dd3101f008 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ResolveFrameworksBase.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ResolveFrameworksBase.cs @@ -22,6 +22,9 @@ public abstract class ResolveNativeReferencesBase : XamarinTask [Required] public string? Architectures { get; set; } + [Required] + public string? IntermediateOutputPath { get; set; } + public ITaskItem []? NativeReferences { get; set; } public ITaskItem []? References { get; set; } @@ -77,9 +80,29 @@ public override bool Execute () foreach (var r in References) { // look for sidecar's manifest var resources = Path.ChangeExtension (r.ItemSpec, ".resources"); + if (!Directory.Exists (resources)) { + // if we don't have a sidecar, we might have a zipped sidecar + var zipPath = resources + ".zip"; + if (!File.Exists (zipPath)) + continue; + + // Yes! we have a zipped sidecar + var path = Path.Combine (IntermediateOutputPath, Path.GetFileName (resources)); + var arguments = new [] { + "-u", + "-o", + "-d", + path, + zipPath, + }; + ExecuteAsync ("/usr/bin/unzip", arguments).Wait (); + resources = path; + } var manifest = Path.Combine (resources, "manifest"); - if (!File.Exists (manifest)) + if (!File.Exists (manifest)) { + Log.LogWarning (MSBStrings.W7087 /* Expected a 'manifest' file in the directory {0} */, resources); continue; + } XmlDocument document = new XmlDocument (); document.LoadWithoutNetworkAccess (manifest); diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs index 584c58573bae..65f04348ed0b 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs @@ -4,6 +4,8 @@ using Microsoft.Build.Utilities; using Microsoft.Build.Framework; +using Xamarin.Utils; + namespace Xamarin.MacDev.Tasks { public abstract class ScnToolTaskBase : XamarinToolTask @@ -18,9 +20,14 @@ public abstract class ScnToolTaskBase : XamarinToolTask [Required] public string InputScene { get; set; } + public bool IsWatchApp { get; set; } + [Required] public string OutputScene { get; set; } + [Required] + public string SdkPlatform { get; set; } + [Required] public string SdkRoot { get; set; } @@ -99,8 +106,14 @@ protected override string GenerateCommandLineCommands () args.Add ("-o"); args.AddQuoted (OutputScene); args.AddQuotedFormat ("--sdk-root={0}", SdkRoot); - args.AddQuotedFormat ("--target-version-{0}={1}", OperatingSystem, SdkVersion); args.AddQuotedFormat ("--target-build-dir={0}", IntermediateOutputPath); + if (AppleSdkSettings.XcodeVersion.Major >= 13) { + // I'm not sure which Xcode version these options are available in, but it's at least Xcode 13+ + args.AddQuotedFormat ("--target-version={0}", SdkVersion); + args.AddQuotedFormat ("--target-platform={0}", PlatformUtils.GetTargetPlatform (SdkPlatform, IsWatchApp)); + } else { + args.AddQuotedFormat ("--target-version-{0}={1}", OperatingSystem, SdkVersion); + } return args.ToString (); } diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XamarinTask.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XamarinTask.cs index 2accf23709d0..66b2a944e177 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XamarinTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/XamarinTask.cs @@ -85,7 +85,7 @@ protected string GetSdkPlatform (bool isSimulator) return PlatformFrameworkHelper.GetSdkPlatform (Platform, isSimulator); } - protected async System.Threading.Tasks.Task ExecuteAsync (string fileName, IList arguments, string sdkDevPath = null, Dictionary environment = null, bool mergeOutput = true, bool showErrorIfFailure = true) + protected async System.Threading.Tasks.Task ExecuteAsync (string fileName, IList arguments, string sdkDevPath = null, Dictionary environment = null, bool mergeOutput = true, bool showErrorIfFailure = true, string workingDirectory = null) { // Create a new dictionary if we're given one, to make sure we don't change the caller's dictionary. var launchEnvironment = environment == null ? new Dictionary () : new Dictionary (environment); @@ -93,7 +93,7 @@ protected async System.Threading.Tasks.Task ExecuteAsync (string file launchEnvironment ["DEVELOPER_DIR"] = sdkDevPath; Log.LogMessage (MessageImportance.Normal, MSBStrings.M0001, fileName, StringUtils.FormatArguments (arguments)); - var rv = await Execution.RunAsync (fileName, arguments, environment: launchEnvironment, mergeOutput: mergeOutput); + var rv = await Execution.RunAsync (fileName, arguments, environment: launchEnvironment, mergeOutput: mergeOutput, workingDirectory: workingDirectory); Log.LogMessage (rv.ExitCode == 0 ? MessageImportance.Low : MessageImportance.High, MSBStrings.M0002, fileName, rv.ExitCode); // Show the output diff --git a/msbuild/Xamarin.iOS.Tasks/Tasks/BTouch.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/BTouch.cs similarity index 98% rename from msbuild/Xamarin.iOS.Tasks/Tasks/BTouch.cs rename to msbuild/Xamarin.MacDev.Tasks/Tasks/BTouch.cs index 376275075ce7..c45252524a03 100644 --- a/msbuild/Xamarin.iOS.Tasks/Tasks/BTouch.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/BTouch.cs @@ -8,7 +8,9 @@ using Microsoft.Build.Utilities; using Xamarin.Messaging; -namespace Xamarin.iOS.Tasks +using Xamarin.iOS.Tasks; + +namespace Xamarin.MacDev.Tasks { public class BTouch : BTouchTaskBase, ITaskCallback { diff --git a/msbuild/Xamarin.iOS.Tasks/Tasks/TaskItemFixer.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/TaskItemFixer.cs similarity index 100% rename from msbuild/Xamarin.iOS.Tasks/Tasks/TaskItemFixer.cs rename to msbuild/Xamarin.MacDev.Tasks/Tasks/TaskItemFixer.cs diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index 9e099ee36ca6..b5333e9e4447 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -34,7 +34,6 @@ Copyright (C) 2018 Microsoft. All rights reserved. - @@ -63,7 +62,6 @@ Copyright (C) 2018 Microsoft. All rights reserved. - @@ -81,6 +79,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. + @@ -145,6 +144,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true' And '$(IsBindingProject)' != 'true'" Architectures="$(TargetArchitectures)" + IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)" NativeReferences="@(_XCFrameworkNativeReference);@(_FrameworkNativeReference)" References="@(ReferencePath)" SdkIsSimulator="$(_SdkIsSimulator)" @@ -155,21 +155,104 @@ Copyright (C) 2018 Microsoft. All rights reserved. - $(ProjectDir)$(OutputPath)$(AssemblyName).resources + $(OutputPath)$(AssemblyName).resources + Outputs="$(BindingResourcePath).stamp"> + + + + auto + false + + - + BindingResourcePath="$(BindingResourcePath)" + Compress="$(CompressBindingResourcePackage)" + IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)" + > + + + + + + + + + + $(GenerateNuspecDependsOn); + _RemoveNativeManifestFromPack; + + + + + <_BuildOutputInPackage Remove="@(_BuildOutputInPackage)" Condition="'%(Filename)%(Extension)' == '$(_DeploymentTargetApplicationManifestFileName)'" /> + + + + + + $(TargetsForTfmSpecificContentInPackage);_IncludeBindingResourcesInNuGetPackage + + + + <_HasOldStyleBindingItems Condition="@(ObjcBindingNativeLibrary->Count()) > 0">true + + + + + + + + + + + <_AppleBindingResourceBasePath>$(TargetDir)$(TargetName).resources + + + + + <_AppleBindingResource Include="$(_AppleBindingResourceBasePath)\**\*" PackagePath="lib\$(_NuGetShortFolderName)\$(TargetName).resources" /> + + <_AppleBindingResource Include="$(_AppleBindingResourceBasePath).zip" PackagePath="lib\$(_NuGetShortFolderName)" Condition="Exists('$(_AppleBindingResourceBasePath).zip')" /> + + + + + + @@ -245,19 +328,37 @@ Copyright (C) 2018 Microsoft. All rights reserved. - + <_CollectBundleResourcesDependsOn> + $(_CollectBundleResourcesDependsOn); + _ComputeTargetArchitectures; + + <_CollectBundleResourcesDependsOn Condition="'$(IsBindingProject)' != 'true'"> + $(_CollectBundleResourcesDependsOn); _CompileImageAssets; _CompileInterfaceDefinitions; _CompileSceneKitAssets; _CompileColladaAssets; _CompileTextureAtlases; _CompileCoreMLModels; - $(_CollectBundleResourcesDependsOn); + + + + + + + + + + + + + + + + + + + + + + + <_CompileInterfaceDefinitionsDependsOn> + $(_CompileInterfaceDefinitionsDependsOn); + _DetectAppManifest; + _DetectSdkLocations; + _ComputeTargetArchitectures; + _RemoveProcessedInterfaceDefinitions; + _BeforeCoreCompileInterfaceDefinitions; + _ReadCoreCompileInterfaceDefinitions; + _CoreCompileInterfaceDefinitions; + + + + + + + + + + + + + + + + + + + - + + + + <_CompileImageAssetsDependsOn> + $(_CompileImageAssetsDependsOn); + _DetectAppManifest; + _DetectSdkLocations; + _ComputeTargetArchitectures; + _RemoveProcessedImageAssets; + _BeforeCoreCompileImageAssets; + _ReadCompileImageAssets; + _CoreCompileImageAssets; + + + + + + + + + + + + + + + + + + - + + + + <_CompileSceneKitAssetsDependsOn> + $(_CompileSceneKitAssetsDependsOn); + _DetectAppManifest; + _DetectSdkLocations; + _ComputeTargetArchitectures; + _RemoveProcessedSceneKitAssets; + _BeforeCoreCompileSceneKitAssets; + _ReadCoreCompileSceneKitAssets; + _CoreCompileSceneKitAssets; + + + + + + + + + + + + + + + + + + @@ -683,6 +886,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. + _RemoveProcessedColladaAssets; _CollectColladaAssets; _CoreCompileColladaAssets @@ -690,6 +894,19 @@ Copyright (C) 2018 Microsoft. All rights reserved. + + + + + + + + + + + + + + + + + @@ -776,6 +1001,17 @@ Copyright (C) 2018 Microsoft. All rights reserved. <_TextureAtlasCache>$(DeviceSpecificIntermediateOutputPath)atlas\_BundleResourceWithLogicalName.items + + + <_ProcessedBundleResourcesPath Condition="'$(_ProcessedBundleResourcesPath)' == ''">$(DeviceSpecificIntermediateOutputPath)\_ProcessedBundleResourcesPath.items + <_ProcessedContentPath Condition="'$(_ProcessedContentPath)' == ''">$(DeviceSpecificIntermediateOutputPath)\_ProcessedContentPath.items + <_ProcessedImageAssetsPath Condition="'$(_ProcessedImageAssetsPath)' == ''">$(DeviceSpecificIntermediateOutputPath)actool\_ProcessedImageAssetsPath.items + <_ProcessedInterfaceDefinitionsPath Condition="'$(_ProcessedInterfaceDefinitionsPath)' == ''">$(DeviceSpecificIntermediateOutputPath)ibtool\_ProcessedInterfaceDefinitionsPath.items + <_ProcessedSceneKitAssetsPath Condition="'$(_ProcessedSceneKitAssetsPath)' == ''">$(DeviceSpecificIntermediateOutputPath)copySceneKitAssets\_ProcessedSceneKitAssetsPath.items + <_ProcessedColladaAssetsPath Condition="'$(_ProcessedColladaAssetsPath)' == ''">$(DeviceSpecificIntermediateOutputPath)collada\_ProcessedColladaAssetsPath.items + <_ProcessedTextureAtlasesPath Condition="'$(_ProcessedTextureAtlasesPath)' == ''">$(DeviceSpecificIntermediateOutputPath)atlas\_ProcessedTextureAtlasesPath.items + <_ProcessedCoreMLModelsPath Condition="'$(_ProcessedCoreMLModelsPath)' == ''">$(DeviceSpecificIntermediateOutputPath)coremlc\_ProcessedCoreMLModelsPath.items + <_SaveProcessedItems Condition="'$(RuntimeIdentifiers)' != '' And '$(UsingAppleNETSdk)' == 'true'">true @@ -825,6 +1061,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. <_CompileTextureAtlasesDependsOn> $(_CompileTextureAtlasesDependsOn); _DetectSdkLocations; + _RemoveProcessedTextureAtlases; _BeforeCompileTextureAtlases; _ReadCoreCompileTextureAtlases; _CoreCompileTextureAtlases; @@ -833,6 +1070,19 @@ Copyright (C) 2018 Microsoft. All rights reserved. + + + + + + + + + + + @@ -878,12 +1128,43 @@ Copyright (C) 2018 Microsoft. All rights reserved. + + + - + + + + <_CompileCoreMLModelsDependsOn> + $(_CompileCoreMLModelsDependsOn); + _DetectAppManifest; + _DetectSdkLocations; + _ComputeTargetArchitectures; + _RemoveProcessedCoreMLModels; + _BeforeCompileCoreMLModels; + _ReadCompileCoreMLModels; + _CoreCompileCoreMLModels; + + + + + + + + + + + + + + + + + + diff --git a/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.props b/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.props index a9c5e7891b40..93bfbd32a919 100644 --- a/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.props +++ b/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.props @@ -25,7 +25,7 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved. False False False - False + False False False $(MSBuildProjectDirectory) diff --git a/msbuild/Xamarin.iOS.Tasks/Xamarin.iOS.Tasks.csproj b/msbuild/Xamarin.iOS.Tasks/Xamarin.iOS.Tasks.csproj index 153fff7175fd..f24ad966168e 100644 --- a/msbuild/Xamarin.iOS.Tasks/Xamarin.iOS.Tasks.csproj +++ b/msbuild/Xamarin.iOS.Tasks/Xamarin.iOS.Tasks.csproj @@ -6,6 +6,7 @@ compile true ../../product.snk + $(NoWarn);8002 diff --git a/src/AppKit/Enums.cs b/src/AppKit/Enums.cs index e97d2fafdc53..d6f1fc90a3b8 100644 --- a/src/AppKit/Enums.cs +++ b/src/AppKit/Enums.cs @@ -1990,13 +1990,13 @@ public enum NSFontCollectionOptions : long { ApplicationOnlyMask = 1 } - [NoMacCatalyst] + [MacCatalyst (13,1)] [Native] public enum NSCollectionViewDropOperation : long { On = 0, Before = 1 } - [NoMacCatalyst] + [MacCatalyst (13,1)] [Mac (10,11)] [Native] public enum NSCollectionViewItemHighlightState : long @@ -2007,7 +2007,7 @@ public enum NSCollectionViewItemHighlightState : long AsDropTarget = 3 } - [NoMacCatalyst] + [MacCatalyst (13,0)] [Mac (10,11)] // Not marked 10.11 in the headers, but doesn't exist in the 10.10 headers [Native] [Flags] @@ -2026,7 +2026,7 @@ public enum NSCollectionViewScrollPosition : ulong NearestVerticalEdge = 1 << 8 } - [NoMacCatalyst] + [MacCatalyst (13,1)] [Mac (10,11)] [Native] public enum NSCollectionElementCategory : long @@ -2049,7 +2049,7 @@ public enum NSCollectionUpdateAction : long None } - [NoMacCatalyst] + [MacCatalyst (13,1)] [Mac (10,11)] [Native] public enum NSCollectionViewScrollDirection : long diff --git a/src/AppKit/Functions.cs b/src/AppKit/Functions.cs index 2d84c2055ff7..f819eed339f5 100644 --- a/src/AppKit/Functions.cs +++ b/src/AppKit/Functions.cs @@ -31,10 +31,12 @@ namespace AppKit { +#if MONOMAC // Class to access C functions public partial class AppKitFramework { [DllImport (Constants.AppKitLibrary)] public static extern void NSBeep(); } +#endif } diff --git a/src/appkit.cs b/src/appkit.cs index d2c16276305a..0b6fbcde0b26 100644 --- a/src/appkit.cs +++ b/src/appkit.cs @@ -9527,6 +9527,7 @@ public enum NSImageName [Field ("NSImageNameBluetoothTemplate")] BluetoothTemplate, + [NoMacCatalyst] [Field ("NSImageNameIChatTheaterTemplate")] IChatTheaterTemplate, @@ -9536,12 +9537,14 @@ public enum NSImageName [Field ("NSImageNameActionTemplate")] ActionTemplate, + [NoMacCatalyst] [Field ("NSImageNameSmartBadgeTemplate")] SmartBadgeTemplate, [Field ("NSImageNamePathTemplate")] PathTemplate, + [NoMacCatalyst] [Field ("NSImageNameInvalidDataFreestandingTemplate")] InvalidDataFreestandingTemplate, @@ -9557,9 +9560,11 @@ public enum NSImageName [Field ("NSImageNameGoLeftTemplate")] GoLeftTemplate, + [NoMacCatalyst] [Field ("NSImageNameRightFacingTriangleTemplate")] RightFacingTriangleTemplate, + [NoMacCatalyst] [Field ("NSImageNameLeftFacingTriangleTemplate")] LeftFacingTriangleTemplate, @@ -9569,36 +9574,45 @@ public enum NSImageName [Field ("NSImageNameRemoveTemplate")] RemoveTemplate, + [NoMacCatalyst] [Field ("NSImageNameRevealFreestandingTemplate")] RevealFreestandingTemplate, + [NoMacCatalyst] [Field ("NSImageNameFollowLinkFreestandingTemplate")] FollowLinkFreestandingTemplate, + [NoMacCatalyst] [Field ("NSImageNameEnterFullScreenTemplate")] EnterFullScreenTemplate, + [NoMacCatalyst] [Field ("NSImageNameExitFullScreenTemplate")] ExitFullScreenTemplate, [Field ("NSImageNameStopProgressTemplate")] StopProgressTemplate, + [NoMacCatalyst] [Field ("NSImageNameStopProgressFreestandingTemplate")] StopProgressFreestandingTemplate, [Field ("NSImageNameRefreshTemplate")] RefreshTemplate, + [NoMacCatalyst] [Field ("NSImageNameRefreshFreestandingTemplate")] RefreshFreestandingTemplate, + [NoMacCatalyst] [Field ("NSImageNameFolder")] Folder, + [NoMacCatalyst] [Field ("NSImageNameTrashEmpty")] TrashEmpty, + [NoMacCatalyst] [Field ("NSImageNameTrashFull")] TrashFull, @@ -9608,33 +9622,43 @@ public enum NSImageName [Field ("NSImageNameBookmarksTemplate")] BookmarksTemplate, + [NoMacCatalyst] [Field ("NSImageNameCaution")] Caution, + [NoMacCatalyst] [Field ("NSImageNameStatusAvailable")] StatusAvailable, + [NoMacCatalyst] [Field ("NSImageNameStatusPartiallyAvailable")] StatusPartiallyAvailable, + [NoMacCatalyst] [Field ("NSImageNameStatusUnavailable")] StatusUnavailable, + [NoMacCatalyst] [Field ("NSImageNameStatusNone")] StatusNone, + [NoMacCatalyst] [Field ("NSImageNameApplicationIcon")] ApplicationIcon, + [NoMacCatalyst] [Field ("NSImageNameMenuOnStateTemplate")] MenuOnStateTemplate, + [NoMacCatalyst] [Field ("NSImageNameMenuMixedStateTemplate")] MenuMixedStateTemplate, + [NoMacCatalyst] [Field ("NSImageNameUserGuest")] UserGuest, + [NoMacCatalyst] [Field ("NSImageNameMobileMe")] MobileMe, @@ -9794,6 +9818,7 @@ public enum NSImageName TouchBarPauseTemplate, [Mac (10, 12, 2)] + [NoMacCatalyst] [Field ("NSImageNameTouchBarPlayheadTemplate")] TouchBarPlayheadTemplate, @@ -19413,6 +19438,7 @@ partial interface NSToolbar { [Export ("autosavesConfiguration")] bool AutosavesConfiguration { get; set; } + [NoMacCatalyst] [Field ("NSToolbarSeparatorItemIdentifier")] [Deprecated (PlatformName.MacOSX, 11, 0, message: "Ignored by system.")] NSString NSToolbarSeparatorItemIdentifier { get; } @@ -19429,6 +19455,7 @@ partial interface NSToolbar { [Field ("NSToolbarShowFontsItemIdentifier")] NSString NSToolbarShowFontsItemIdentifier { get; } + [NoMacCatalyst] [Field ("NSToolbarCustomizeToolbarItemIdentifier")] [Deprecated (PlatformName.MacOSX, 11, 0, message: "Ignored by system.")] NSString NSToolbarCustomizeToolbarItemIdentifier { get; } @@ -19452,6 +19479,7 @@ partial interface NSToolbar { [NullAllowed, Export ("centeredItemIdentifier")] string CenteredItemIdentifier { get; set; } + [NoMacCatalyst] [Mac (11, 0)] [Field ("NSToolbarSidebarTrackingSeparatorItemIdentifier")] NSString NSToolbarSidebarTrackingSeparatorItemIdentifier { get; } @@ -19585,7 +19613,7 @@ interface NSToolbarItem : NSCopying, NSMenuItemValidation, NSValidatedUserInterf bool Navigational { [Bind ("isNavigational")] get; set; } } - [NoMacCatalyst] + [MacCatalyst (13,0)] [BaseType (typeof (NSToolbarItem))] interface NSToolbarItemGroup { @@ -19756,39 +19784,49 @@ interface NSTouchBarItem : NSCoding } [Mac (10,12,2)] - [MacCatalyst (13, 0)] public enum NSTouchBarItemIdentifier { + [MacCatalyst (13, 0)] [Field ("NSTouchBarItemIdentifierFixedSpaceSmall")] FixedSpaceSmall, + [MacCatalyst (13, 0)] [Field ("NSTouchBarItemIdentifierFixedSpaceLarge")] FixedSpaceLarge, + [MacCatalyst (13, 0)] [Field ("NSTouchBarItemIdentifierFlexibleSpace")] FlexibleSpace, + [MacCatalyst (13, 0)] [Field ("NSTouchBarItemIdentifierOtherItemsProxy")] OtherItemsProxy, + [NoMacCatalyst] [Field ("NSTouchBarItemIdentifierCharacterPicker")] CharacterPicker, + [NoMacCatalyst] [Field ("NSTouchBarItemIdentifierTextColorPicker")] TextColorPicker, + [NoMacCatalyst] [Field ("NSTouchBarItemIdentifierTextStyle")] TextStyle, + [NoMacCatalyst] [Field ("NSTouchBarItemIdentifierTextAlignment")] TextAlignment, + [NoMacCatalyst] [Field ("NSTouchBarItemIdentifierTextList")] TextList, + [NoMacCatalyst] [Field ("NSTouchBarItemIdentifierTextFormat")] TextFormat, + [NoMacCatalyst] [Field ("NSTouchBarItemIdentifierCandidateList")] CandidateList } @@ -26982,10 +27020,11 @@ interface NSSwitch : NSAccessibilitySwitch } [Mac (10,15)] - [NoMacCatalyst] + [MacCatalyst (13,0)] [BaseType (typeof (NSToolbarItem))] interface NSMenuToolbarItem { + [NoMacCatalyst] [Export ("menu", ArgumentSemantic.Strong)] NSMenu Menu { get; set; } diff --git a/tests/common/DotNet.cs b/tests/common/DotNet.cs index fda216713643..8656f153819f 100644 --- a/tests/common/DotNet.cs +++ b/tests/common/DotNet.cs @@ -24,6 +24,18 @@ public static string Executable { } } + public static ExecutionResult AssertPack (string project, Dictionary properties = null) + { + return Execute ("pack", project, properties, true); + } + + public static ExecutionResult AssertPackFailure (string project, Dictionary properties = null) + { + var rv = Execute ("pack", project, properties, false); + Assert.AreNotEqual (0, rv.ExitCode, "Unexpected success"); + return rv; + } + public static ExecutionResult AssertPublish (string project, Dictionary properties = null) { return Execute ("publish", project, properties, true); @@ -75,6 +87,7 @@ public static ExecutionResult Execute (string verb, string project, Dictionary (); args.Add (verb); diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0001.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0001.png new file mode 100755 index 000000000000..dc402d053af5 Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0001.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0002.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0002.png new file mode 100755 index 000000000000..2b582a026859 Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0002.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0003.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0003.png new file mode 100755 index 000000000000..c918758fc835 Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0003.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0004.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0004.png new file mode 100755 index 000000000000..cbb733eea0dd Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0004.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0005.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0005.png new file mode 100755 index 000000000000..f65b92a4c8c2 Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0005.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0006.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0006.png new file mode 100755 index 000000000000..0f1aba579ed8 Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0006.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0007.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0007.png new file mode 100755 index 000000000000..7d89c0b22d05 Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0007.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0008.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0008.png new file mode 100755 index 000000000000..0eb8f42d171f Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0008.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0009.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0009.png new file mode 100755 index 000000000000..30173910a945 Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0009.png differ diff --git a/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0010.png b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0010.png new file mode 100755 index 000000000000..973a9ce9e6cf Binary files /dev/null and b/tests/dotnet/AppWithResources/Archer_Attack.atlas/archer_attack_0010.png differ diff --git a/tests/dotnet/AppWithResources/MacCatalyst/Main.storyboard b/tests/dotnet/AppWithResources/MacCatalyst/Main.storyboard new file mode 100644 index 000000000000..6a96318d776e --- /dev/null +++ b/tests/dotnet/AppWithResources/MacCatalyst/Main.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Contents.json b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Contents.json b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 000000000000..4449069d93ca --- /dev/null +++ b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon64.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon16.png b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon16.png new file mode 100644 index 000000000000..35c074e65fce Binary files /dev/null and b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon16.png differ diff --git a/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon32.png b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon32.png new file mode 100644 index 000000000000..a488140938ed Binary files /dev/null and b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon32.png differ diff --git a/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon64.png b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon64.png new file mode 100644 index 000000000000..4027b6bf9ada Binary files /dev/null and b/tests/dotnet/AppWithResources/MacCatalyst/Resources/Images.xcassets/Image.imageset/Icon64.png differ diff --git a/tests/dotnet/AppWithResources/SqueezeNet.mlmodel b/tests/dotnet/AppWithResources/SqueezeNet.mlmodel new file mode 100644 index 000000000000..86cff1eb4690 Binary files /dev/null and b/tests/dotnet/AppWithResources/SqueezeNet.mlmodel differ diff --git a/tests/dotnet/AppWithResources/arm.txt b/tests/dotnet/AppWithResources/arm.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/AppWithResources/arm64.txt b/tests/dotnet/AppWithResources/arm64.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/AppWithResources/art.scnassets/scene.scn b/tests/dotnet/AppWithResources/art.scnassets/scene.scn new file mode 100644 index 000000000000..5b0d1c58aa14 Binary files /dev/null and b/tests/dotnet/AppWithResources/art.scnassets/scene.scn differ diff --git a/tests/dotnet/AppWithResources/art.scnassets/texture.png b/tests/dotnet/AppWithResources/art.scnassets/texture.png new file mode 100644 index 000000000000..ba392589b700 Binary files /dev/null and b/tests/dotnet/AppWithResources/art.scnassets/texture.png differ diff --git a/tests/dotnet/AppWithResources/iOS/Main.storyboard b/tests/dotnet/AppWithResources/iOS/Main.storyboard new file mode 100644 index 000000000000..15478fed9bf6 --- /dev/null +++ b/tests/dotnet/AppWithResources/iOS/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Contents.json b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Contents.json b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 000000000000..4449069d93ca --- /dev/null +++ b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon64.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon16.png b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon16.png new file mode 100644 index 000000000000..35c074e65fce Binary files /dev/null and b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon16.png differ diff --git a/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon32.png b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon32.png new file mode 100644 index 000000000000..a488140938ed Binary files /dev/null and b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon32.png differ diff --git a/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon64.png b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon64.png new file mode 100644 index 000000000000..4027b6bf9ada Binary files /dev/null and b/tests/dotnet/AppWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon64.png differ diff --git a/tests/dotnet/AppWithResources/macOS/Main.storyboard b/tests/dotnet/AppWithResources/macOS/Main.storyboard new file mode 100644 index 000000000000..2c81cc6cab30 --- /dev/null +++ b/tests/dotnet/AppWithResources/macOS/Main.storyboard @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Contents.json b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Contents.json b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 000000000000..4449069d93ca --- /dev/null +++ b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon64.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon16.png b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon16.png new file mode 100644 index 000000000000..35c074e65fce Binary files /dev/null and b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon16.png differ diff --git a/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon32.png b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon32.png new file mode 100644 index 000000000000..a488140938ed Binary files /dev/null and b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon32.png differ diff --git a/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon64.png b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon64.png new file mode 100644 index 000000000000..4027b6bf9ada Binary files /dev/null and b/tests/dotnet/AppWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon64.png differ diff --git a/tests/dotnet/AppWithResources/scene.dae b/tests/dotnet/AppWithResources/scene.dae new file mode 100644 index 000000000000..d0235f58160b --- /dev/null +++ b/tests/dotnet/AppWithResources/scene.dae @@ -0,0 +1,37 @@ + + + + + SceneKit Collada Exporter v1.0 + + 2021-09-23T09:36:40Z + 2021-09-23T09:36:40Z + + Y_UP + + + + + + + 45 + 0.111134 + 27.7834 + + + + + + + + + 0.9999999 0 0 0 0 1 0 0.3 0 0 0.9999999 2.5 0 0 0 1 + + + + + + + + + diff --git a/tests/dotnet/AppWithResources/shared.csproj b/tests/dotnet/AppWithResources/shared.csproj index 305c637d3b65..4603f2c62982 100644 --- a/tests/dotnet/AppWithResources/shared.csproj +++ b/tests/dotnet/AppWithResources/shared.csproj @@ -13,5 +13,21 @@ + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/AppWithResources/shared.plist b/tests/dotnet/AppWithResources/shared.plist new file mode 100644 index 000000000000..6631ffa6f242 --- /dev/null +++ b/tests/dotnet/AppWithResources/shared.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/dotnet/AppWithResources/tvOS/Main.storyboard b/tests/dotnet/AppWithResources/tvOS/Main.storyboard new file mode 100644 index 000000000000..6a96318d776e --- /dev/null +++ b/tests/dotnet/AppWithResources/tvOS/Main.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Contents.json b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Contents.json b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 000000000000..4449069d93ca --- /dev/null +++ b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon64.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon16.png b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon16.png new file mode 100644 index 000000000000..35c074e65fce Binary files /dev/null and b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon16.png differ diff --git a/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon32.png b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon32.png new file mode 100644 index 000000000000..a488140938ed Binary files /dev/null and b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon32.png differ diff --git a/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon64.png b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon64.png new file mode 100644 index 000000000000..4027b6bf9ada Binary files /dev/null and b/tests/dotnet/AppWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon64.png differ diff --git a/tests/dotnet/AppWithResources/x64.txt b/tests/dotnet/AppWithResources/x64.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/dotnet/MyClassLibrary/MyClassLibrary.csproj b/tests/dotnet/MyClassLibrary/MyClassLibrary.csproj deleted file mode 100644 index 7af2c032af2f..000000000000 --- a/tests/dotnet/MyClassLibrary/MyClassLibrary.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - - net6.0-ios - - diff --git a/tests/dotnet/UnitTests/ApplePlatformExtensions.cs b/tests/dotnet/UnitTests/ApplePlatformExtensions.cs new file mode 100644 index 000000000000..cd6a7de30c73 --- /dev/null +++ b/tests/dotnet/UnitTests/ApplePlatformExtensions.cs @@ -0,0 +1,22 @@ +using System; + +namespace Xamarin.Utils { + public static class ApplePlatformExtensionsWithVersions { + public static string ToFrameworkWithDefaultVersion (this ApplePlatform @this) + { + var netVersion = "net6.0"; + switch (@this) { + case ApplePlatform.iOS: + return netVersion + "-ios" + SdkVersions.iOS; + case ApplePlatform.MacOSX: + return netVersion + "-macos" + SdkVersions.OSX; + case ApplePlatform.TVOS: + return netVersion + "-tvos" + SdkVersions.TVOS; + case ApplePlatform.MacCatalyst: + return netVersion + "-maccatalyst" + SdkVersions.MacCatalyst; + default: + return "Unknown"; + } + } + } +} diff --git a/tests/dotnet/UnitTests/DotNetUnitTests.csproj b/tests/dotnet/UnitTests/DotNetUnitTests.csproj index 773bd6711704..0c8c920a7cf1 100644 --- a/tests/dotnet/UnitTests/DotNetUnitTests.csproj +++ b/tests/dotnet/UnitTests/DotNetUnitTests.csproj @@ -48,6 +48,9 @@ external\PListObject.cs + + external\SdkVersions.cs + diff --git a/tests/dotnet/UnitTests/PackTest.cs b/tests/dotnet/UnitTests/PackTest.cs new file mode 100644 index 000000000000..0eb62c67ea4d --- /dev/null +++ b/tests/dotnet/UnitTests/PackTest.cs @@ -0,0 +1,175 @@ +#nullable enable + +using System; +using System.IO; +using System.IO.Compression; +using System.Linq; + +using NUnit.Framework; + +using Xamarin.Utils; +using Xamarin.MacDev; + +namespace Xamarin.Tests { + public class PackTest : TestBaseClass { + + + [Test] + [TestCase (ApplePlatform.iOS)] + [TestCase (ApplePlatform.MacCatalyst)] + [TestCase (ApplePlatform.TVOS)] + [TestCase (ApplePlatform.MacOSX)] + public void BindingProject (ApplePlatform platform) + { + var project = "bindings-test"; + Configuration.IgnoreIfIgnoredPlatform (platform); + + var project_path = Path.Combine (Configuration.RootPath, "tests", project, "dotnet", platform.AsString (), $"{project}.csproj"); + Clean (project_path); + Configuration.CopyDotNetSupportingFiles (Path.GetDirectoryName (project_path)); + + var tmpdir = Cache.CreateTemporaryDirectory (); + var outputPath = Path.Combine (tmpdir, "OutputPath"); + var intermediateOutputPath = Path.Combine (tmpdir, "IntermediateOutputPath"); + var properties = GetDefaultProperties (); + properties ["OutputPath"] = outputPath + Path.DirectorySeparatorChar; + properties ["IntermediateOutputPath"] = intermediateOutputPath + Path.DirectorySeparatorChar; + + var rv =DotNet.AssertPackFailure (project_path, properties); + var errors = BinLog.GetBuildLogErrors (rv.BinLogPath).ToArray (); + Assert.AreEqual (1, errors.Length, "Error count"); + Assert.AreEqual ($"Creating a NuGet package is not supported for projects that have ObjcBindingNativeLibrary items. Migrate to use NativeReference items instead.", errors [0].Message, "Error message"); + } + + [Test] + [TestCase (ApplePlatform.iOS, true)] + [TestCase (ApplePlatform.iOS, false)] + [TestCase (ApplePlatform.MacCatalyst, true)] + [TestCase (ApplePlatform.MacCatalyst, false)] + [TestCase (ApplePlatform.TVOS, true)] + [TestCase (ApplePlatform.TVOS, false)] + [TestCase (ApplePlatform.MacOSX, true)] + [TestCase (ApplePlatform.MacOSX, false)] + public void BindingFrameworksProject (ApplePlatform platform, bool noBindingEmbedding) + { + var project = "bindings-framework-test"; + Configuration.IgnoreIfIgnoredPlatform (platform); + + var project_path = Path.Combine (Configuration.RootPath, "tests", project, "dotnet", platform.AsString (), $"{project}.csproj"); + Clean (project_path); + Configuration.CopyDotNetSupportingFiles (Path.GetDirectoryName (project_path)); + + var tmpdir = Cache.CreateTemporaryDirectory (); + var outputPath = Path.Combine (tmpdir, "OutputPath"); + var intermediateOutputPath = Path.Combine (tmpdir, "IntermediateOutputPath"); + var properties = GetDefaultProperties (); + properties ["OutputPath"] = outputPath + Path.DirectorySeparatorChar; + properties ["IntermediateOutputPath"] = intermediateOutputPath + Path.DirectorySeparatorChar; + properties ["NoBindingEmbedding"] = noBindingEmbedding ? "true" : "false"; + + DotNet.AssertPack (project_path, properties); + + var nupkg = Path.Combine (outputPath, project + ".1.0.0.nupkg"); + Assert.That (nupkg, Does.Exist, "nupkg existence"); + + var archive = ZipFile.OpenRead (nupkg); + var files = archive.Entries.Select (v => v.FullName).ToHashSet (); + var hasSymlinks = noBindingEmbedding && (platform == ApplePlatform.MacCatalyst || platform == ApplePlatform.MacOSX); + if (noBindingEmbedding) { + Assert.That (archive.Entries.Count, Is.EqualTo (hasSymlinks ? 6 : 10), $"nupkg file count - {nupkg}"); + } else { + Assert.That (archive.Entries.Count, Is.EqualTo (5), $"nupkg file count - {nupkg}"); + } + Assert.That (files, Does.Contain (project + ".nuspec"), "nuspec"); + Assert.That (files, Does.Contain ("_rels/.rels"), ".rels"); + Assert.That (files, Does.Contain ("[Content_Types].xml"), "[Content_Types].xml"); + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.dll"), $"{project}.dll"); + Assert.That (files, Has.Some.Matches (v => v.StartsWith ("package/services/metadata/core-properties/", StringComparison.Ordinal) && v.EndsWith (".psmdcp", StringComparison.Ordinal)), "psmdcp"); + if (noBindingEmbedding) { + if (hasSymlinks) { + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.resources.zip"), $"{project}.resources.zip"); + } else { + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.resources/XStaticArTest.framework/XStaticArTest"), $"XStaticArTest.framework/XStaticArTest"); + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.resources/XStaticObjectTest.framework/XStaticObjectTest"), $"XStaticObjectTest.framework/XStaticObjectTest"); + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.resources/XTest.framework/XTest"), $"XTest.framework/XTest"); + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.resources/XTest.framework/Info.plist"), $"XTest.framework/Info.plist"); + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.resources/manifest"), $"manifest"); + } + } + } + + [Test] + [TestCase (ApplePlatform.iOS, true)] + [TestCase (ApplePlatform.iOS, false)] + [TestCase (ApplePlatform.MacCatalyst, true)] + [TestCase (ApplePlatform.MacCatalyst, false)] + [TestCase (ApplePlatform.TVOS, true)] + [TestCase (ApplePlatform.TVOS, false)] + [TestCase (ApplePlatform.MacOSX, true)] + [TestCase (ApplePlatform.MacOSX, false)] + public void BindingXcFrameworksProject (ApplePlatform platform, bool noBindingEmbedding) + { + var project = "bindings-xcframework-test"; + Configuration.IgnoreIfIgnoredPlatform (platform); + + var project_path = Path.Combine (Configuration.RootPath, "tests", project, "dotnet", platform.AsString (), $"{project}.csproj"); + Clean (project_path); + Configuration.CopyDotNetSupportingFiles (Path.GetDirectoryName (project_path)); + + var tmpdir = Cache.CreateTemporaryDirectory (); + var outputPath = Path.Combine (tmpdir, "OutputPath"); + var intermediateOutputPath = Path.Combine (tmpdir, "IntermediateOutputPath"); + var properties = GetDefaultProperties (); + properties ["OutputPath"] = outputPath + Path.DirectorySeparatorChar; + properties ["IntermediateOutputPath"] = intermediateOutputPath + Path.DirectorySeparatorChar; + properties ["NoBindingEmbedding"] = noBindingEmbedding ? "true" : "false"; + properties ["AssemblyName"] = project; + + DotNet.AssertPack (project_path, properties); + + var nupkg = Path.Combine (outputPath, project + ".1.0.0.nupkg"); + Assert.That (nupkg, Does.Exist, "nupkg existence"); + + var archive = ZipFile.OpenRead (nupkg); + var files = archive.Entries.Select (v => v.FullName).ToHashSet (); + Assert.That (archive.Entries.Count, Is.EqualTo (noBindingEmbedding ? 6 : 5), $"nupkg file count - {nupkg}"); + Assert.That (files, Does.Contain (project + ".nuspec"), "nuspec"); + Assert.That (files, Does.Contain ("_rels/.rels"), ".rels"); + Assert.That (files, Does.Contain ("[Content_Types].xml"), "[Content_Types].xml"); + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.dll"), $"{project}.dll"); + Assert.That (files, Has.Some.Matches (v => v.StartsWith ("package/services/metadata/core-properties/", StringComparison.Ordinal) && v.EndsWith (".psmdcp", StringComparison.Ordinal)), "psmdcp"); + if (noBindingEmbedding) { + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.resources.zip"), $"{project}.resources.zip"); + } + } + + [Test] + [TestCase (ApplePlatform.iOS)] + [TestCase (ApplePlatform.MacCatalyst)] + [TestCase (ApplePlatform.TVOS)] + [TestCase (ApplePlatform.MacOSX)] + public void LibraryProject (ApplePlatform platform) + { + var project = "MyClassLibrary"; + Configuration.IgnoreIfIgnoredPlatform (platform); + + var project_path = GetProjectPath (project, runtimeIdentifiers: string.Empty, platform: platform, out var appPath); + Clean (project_path); + var properties = GetDefaultProperties (); + + DotNet.AssertPack (project_path, properties); + + var nupkg = Path.Combine (Path.GetDirectoryName (project_path)!, "bin", "Debug", project + ".1.0.0.nupkg"); + Assert.That (nupkg, Does.Exist, "nupkg existence"); + + var archive = ZipFile.OpenRead (nupkg); + var files = archive.Entries.Select (v => v.FullName).ToHashSet (); + Assert.That (archive.Entries.Count, Is.EqualTo (5), "nupkg file count"); + Assert.That (files, Does.Contain (project + ".nuspec"), "nuspec"); + Assert.That (files, Does.Contain ("_rels/.rels"), ".rels"); + Assert.That (files, Does.Contain ("[Content_Types].xml"), "[Content_Types].xml"); + Assert.That (files, Does.Contain ($"lib/{platform.ToFrameworkWithDefaultVersion ()}/{project}.dll"), $"{project}.dll"); + Assert.That (files, Has.Some.Matches (v => v.StartsWith ("package/services/metadata/core-properties/", StringComparison.Ordinal) && v.EndsWith (".psmdcp", StringComparison.Ordinal)), "psmdcp"); + } + } +} diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs index 29ba3de02d72..98aff1df7899 100644 --- a/tests/dotnet/UnitTests/ProjectTest.cs +++ b/tests/dotnet/UnitTests/ProjectTest.cs @@ -603,9 +603,12 @@ public void BindingWithDefaultCompileInclude (ApplePlatform platform) } [TestCase (ApplePlatform.iOS, "iossimulator-x64")] + [TestCase (ApplePlatform.iOS, "ios-arm64;ios-arm")] [TestCase (ApplePlatform.TVOS, "tvossimulator-x64")] [TestCase (ApplePlatform.MacCatalyst, "maccatalyst-x64")] + [TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64;maccatalyst-x64")] [TestCase (ApplePlatform.MacOSX, "osx-x64")] + [TestCase (ApplePlatform.MacOSX, "osx-arm64;osx-x64")] // https://github.com/xamarin/xamarin-macios/issues/12410 public void AppWithResources (ApplePlatform platform, string runtimeIdentifiers) { var project = "AppWithResources"; @@ -619,7 +622,9 @@ public void AppWithResources (ApplePlatform platform, string runtimeIdentifiers) var appExecutable = GetNativeExecutable (platform, appPath); ExecuteWithMagicWordAndAssert (platform, runtimeIdentifiers, appExecutable); - string fontDirectory = GetResourcesDirectory (platform, appPath); + var resourcesDirectory = GetResourcesDirectory (platform, appPath); + + var fontDirectory = resourcesDirectory; var fontAFile = Path.Combine (fontDirectory, "A.ttc"); var fontBFile = Path.Combine (fontDirectory, "B.otf"); var fontCFile = Path.Combine (fontDirectory, "C.ttf"); @@ -645,6 +650,32 @@ public void AppWithResources (ApplePlatform platform, string runtimeIdentifiers) default: throw new ArgumentOutOfRangeException ($"Unknown platform: {platform}"); } + + var assetsCar = Path.Combine (resourcesDirectory, "Assets.car"); + Assert.That (assetsCar, Does.Exist, "Assets.car"); + + var mainStoryboard = Path.Combine (resourcesDirectory, "Main.storyboardc"); + Assert.That (mainStoryboard, Does.Exist, "Main.storyboardc"); + + var scnAssetsDir = Path.Combine (resourcesDirectory, "art.scnassets"); + Assert.That (Path.Combine (scnAssetsDir, "scene.scn"), Does.Exist, "scene.scn"); + Assert.That (Path.Combine (scnAssetsDir, "texture.png"), Does.Exist, "texture.png"); + + var colladaScene = Path.Combine (resourcesDirectory, "scene.dae"); + Assert.That (colladaScene, Does.Exist, "Collada - scene.dae"); + + var atlasTexture = Path.Combine (resourcesDirectory, "Archer_Attack.atlasc", "Archer_Attack.plist"); + Assert.That (atlasTexture, Does.Exist, "AtlasTexture - Archer_Attack"); + + var mlModel = Path.Combine (resourcesDirectory, "SqueezeNet.mlmodelc"); + Assert.That (mlModel, Does.Exist, "CoreMLModel"); + + var arm64txt = Path.Combine (resourcesDirectory, "arm64.txt"); + var armtxt = Path.Combine (resourcesDirectory, "arm.txt"); + var x64txt = Path.Combine (resourcesDirectory, "x64.txt"); + Assert.AreEqual (runtimeIdentifiers.Split (';').Any (v => v.EndsWith ("-arm64")), File.Exists (arm64txt), "arm64.txt"); + Assert.AreEqual (runtimeIdentifiers.Split (';').Any (v => v.EndsWith ("-arm")), File.Exists (armtxt), "arm.txt"); + Assert.AreEqual (runtimeIdentifiers.Split (';').Any (v => v.EndsWith ("-x64")), File.Exists (x64txt), "x64.txt"); } void ExecuteWithMagicWordAndAssert (ApplePlatform platform, string runtimeIdentifiers, string executable) diff --git a/tests/dotnet/UnitTests/TestBaseClass.cs b/tests/dotnet/UnitTests/TestBaseClass.cs index 834b3e3bd058..88833cc545a2 100644 --- a/tests/dotnet/UnitTests/TestBaseClass.cs +++ b/tests/dotnet/UnitTests/TestBaseClass.cs @@ -36,18 +36,18 @@ protected void SetRuntimeIdentifiers (Dictionary properties, str properties [multiRid] = runtimeIdentifiers; } - protected string GetProjectPath (string project, string runtimeIdentifiers, ApplePlatform platform, out string appPath, string subdir = null, string configuration = "Debug") + protected string GetProjectPath (string project, string runtimeIdentifiers, ApplePlatform platform, out string appPath, string? subdir = null, string configuration = "Debug") { return GetProjectPath (project, null, runtimeIdentifiers, platform, out appPath, configuration); } - protected string GetProjectPath (string project, string subdir, string runtimeIdentifiers, ApplePlatform platform, out string appPath, string configuration = "Debug") + protected string GetProjectPath (string project, string? subdir, string runtimeIdentifiers, ApplePlatform platform, out string appPath, string configuration = "Debug") { var rv = GetProjectPath (project, subdir, platform); if (string.IsNullOrEmpty (runtimeIdentifiers)) runtimeIdentifiers = GetDefaultRuntimeIdentifier (platform); var appPathRuntimeIdentifier = runtimeIdentifiers.IndexOf (';') >= 0 ? "" : runtimeIdentifiers; - appPath = Path.Combine (Path.GetDirectoryName (rv), "bin", configuration, platform.ToFramework (), appPathRuntimeIdentifier, project + ".app"); + appPath = Path.Combine (Path.GetDirectoryName (rv)!, "bin", configuration, platform.ToFramework (), appPathRuntimeIdentifier, project + ".app"); return rv; } @@ -67,7 +67,7 @@ protected string GetDefaultRuntimeIdentifier (ApplePlatform platform) } } - protected string GetProjectPath (string project, string subdir = null, ApplePlatform? platform = null) + protected string GetProjectPath (string project, string? subdir = null, ApplePlatform? platform = null) { var project_dir = Path.Combine (Configuration.SourceRoot, "tests", "dotnet", project); if (!string.IsNullOrEmpty (subdir)) @@ -92,7 +92,7 @@ protected string GetProjectPath (string project, string subdir = null, ApplePlat protected void Clean (string project_path) { - var dirs = Directory.GetDirectories (Path.GetDirectoryName (project_path), "*", SearchOption.AllDirectories); + var dirs = Directory.GetDirectories (Path.GetDirectoryName (project_path)!, "*", SearchOption.AllDirectories); dirs = dirs.OrderBy (v => v.Length).Reverse ().ToArray (); // If we have nested directories, make sure to delete the nested one first foreach (var dir in dirs) { var name = Path.GetFileName (dir); diff --git a/tests/interdependent-binding-projects/dotnet/shared.csproj b/tests/interdependent-binding-projects/dotnet/shared.csproj index ac9e039cf643..ede579a1679a 100644 --- a/tests/interdependent-binding-projects/dotnet/shared.csproj +++ b/tests/interdependent-binding-projects/dotnet/shared.csproj @@ -21,6 +21,7 @@ + diff --git a/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs b/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs index 705b5d9e7d23..7e4c9588abbc 100644 --- a/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs +++ b/tests/monotouch-test/ObjCRuntime/RuntimeTest.cs @@ -857,5 +857,11 @@ public void CurrentDirectory () #endif Assert.AreEqual (expectedDirectory, actualDirectory, "Current directory at launch"); } + + [Test] + public void CurrentDomain_BaseDirectory_Test () + { + Assert.That (AppDomain.CurrentDomain.BaseDirectory, Is.Not.Null.And.Not.Empty, "AppDomain.CurrentDomain.BaseDirectory"); + } } } diff --git a/tests/monotouch-test/System.Net.Http/MessageHandlers.cs b/tests/monotouch-test/System.Net.Http/MessageHandlers.cs index f4af11eb6c1d..5d12c08978f2 100644 --- a/tests/monotouch-test/System.Net.Http/MessageHandlers.cs +++ b/tests/monotouch-test/System.Net.Http/MessageHandlers.cs @@ -566,7 +566,7 @@ public void GHIssue8342 (HttpStatusCode expectedStatus, string validUsername, st if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail Assert.Inconclusive ("Request timedout."); } else { - if (httpStatus == HttpStatusCode.BadGateway) + if (httpStatus == HttpStatusCode.BadGateway || httpStatus == HttpStatusCode.GatewayTimeout) TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI"); Assert.IsNull (ex, "Exception not null"); Assert.AreEqual (expectedStatus, httpStatus, "Status not ok"); @@ -606,7 +606,7 @@ public void GHIssue8344 () if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail Assert.Inconclusive ("First request timedout."); } else { - if (httpStatus == HttpStatusCode.BadGateway) + if (httpStatus == HttpStatusCode.BadGateway || httpStatus == HttpStatusCode.GatewayTimeout) TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI"); Assert.IsNull (ex, "First request exception not null"); Assert.AreEqual (HttpStatusCode.OK, httpStatus, "First status not ok"); @@ -637,7 +637,7 @@ public void GHIssue8344 () if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail Assert.Inconclusive ("Second request timedout."); } else { - if (httpStatus == HttpStatusCode.BadGateway) + if (httpStatus == HttpStatusCode.BadGateway || httpStatus == HttpStatusCode.GatewayTimeout) TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI"); Assert.IsNull (ex, "Second request exception not null"); Assert.AreEqual (HttpStatusCode.Unauthorized, httpStatus, "Second status not ok"); diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/BTouchTaskTest.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/BTouchTaskTest.cs index 71ca93cb1dcd..b702ccf655f4 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/BTouchTaskTest.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/BTouchTaskTest.cs @@ -5,7 +5,9 @@ using NUnit.Framework; -namespace Xamarin.iOS.Tasks +using Xamarin.iOS.Tasks; + +namespace Xamarin.MacDev.Tasks { class CustomBTouchTask : BTouch { diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CreateBindingResourceTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CreateBindingResourceTaskTests.cs new file mode 100644 index 000000000000..bf16ccc756cd --- /dev/null +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CreateBindingResourceTaskTests.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +using NUnit.Framework; + +using Xamarin.iOS.Tasks; +using Xamarin.Utils; + +namespace Xamarin.MacDev.Tasks { + [TestFixture] + public class CreateBindingResourceTaskTests : TestBase { + CreateBindingResourcePackage ExecuteTask (string compress, bool symlinks, out string tmpdir) + { + tmpdir = Cache.CreateTemporaryDirectory (); + var task = CreateTask (); + task.Compress = compress; + task.BindingResourcePath = Path.Combine (tmpdir, "CreateBindingResourceTaskTest"); + task.IntermediateOutputPath = Path.Combine (tmpdir, "IntermediateOutputPath"); + task.NativeReferences = CreateNativeReferences (tmpdir, symlinks); + + var currentDir = Environment.CurrentDirectory; + try { + Environment.CurrentDirectory = tmpdir; + Assert.IsTrue (task.Execute (), "Execute"); + } finally { + Environment.CurrentDirectory = currentDir; + } + + return task; + } + + [Test] + [TestCase (true)] + [TestCase (false)] + public void Compressed (bool symlinks) + { + var task = ExecuteTask ("true", symlinks, out var tmpdir); + + var zipFile = task.BindingResourcePath + ".zip"; + Assert.That (zipFile, Does.Exist, "Zip existence"); + + var extracted = Path.Combine (tmpdir, "Extracted"); + Extract (zipFile, extracted); + AssertResourceDirectory (extracted, symlinks); + } + + [Test] + [TestCase (true)] + [TestCase (false)] + public void Uncompressed (bool symlinks) + { + var task = ExecuteTask ("false", symlinks, out var tmpdir); + + AssertResourceDirectory (task.BindingResourcePath, symlinks); + } + + [Test] + [TestCase (true)] + [TestCase (false)] + public void Auto (bool symlinks) + { + var task = ExecuteTask ("auto", symlinks, out var tmpdir); + + string extracted; + if (symlinks) { + var zipFile = task.BindingResourcePath + ".zip"; + Assert.That (zipFile, Does.Exist, "Zip existence"); + + extracted = Path.Combine (tmpdir, "Extracted"); + Extract (zipFile, extracted); + } else { + extracted = task.BindingResourcePath; + } + AssertResourceDirectory (extracted, symlinks); + } + + void Extract (string zipArchive, string targetDirectory) + { + var unzipArguments = new List (); + unzipArguments.Add ("-d"); + unzipArguments.Add (targetDirectory); + unzipArguments.Add (zipArchive); + var output = new StringBuilder (); + var rv = Execution.RunWithStringBuildersAsync ("unzip", unzipArguments, standardOutput: output, standardError: output).Result; + Assert.AreEqual (0, rv.ExitCode, "ExitCode\n" + output.ToString ()); + } + + void AssertResourceDirectory (string directory, bool symlinks) + { + var allFiles = Directory.GetFileSystemEntries (directory, "*", SearchOption.AllDirectories).OrderBy (v => v).Select (v => v.Substring (directory.Length + 1)).ToArray (); + foreach (var file in allFiles) + Console.WriteLine (file); + if (symlinks) { + Assert.AreEqual (7, allFiles.Length, "Length"); + } else { + Assert.AreEqual (5, allFiles.Length, "Length"); + } + Assert.AreEqual ("ABCDEFGHIJKLMAAA", File.ReadAllText (Path.Combine (directory, "A.txt")), "A.txt"); + Assert.AreEqual ("ABCDEFGHIJKLMBBB", File.ReadAllText (Path.Combine (directory, "B.txt")), "B.txt"); + Assert.AreEqual ("ABCDEFGHIJKLMCCC", File.ReadAllText (Path.Combine (directory, "C.framework/C.txt")), "C.txt"); + if (symlinks) { + var linkToCPath = Path.Combine (directory, "C.framework/LinkToC.txt"); + Assert.AreEqual ("ABCDEFGHIJKLMCCC", File.ReadAllText (linkToCPath), "LinkToC.txt"); + Assert.IsTrue (PathUtils.IsSymlink (linkToCPath), "LinkToC.txt - IsSymlink"); + Assert.AreEqual ("C.txt", PathUtils.GetSymlinkTarget (linkToCPath), "LinkToC.txt - IsSymlink target"); + + var linkToNowherePath = Path.Combine (directory, "C.framework/LinkToNowhere.txt"); + Assert.Throws (() => File.ReadAllText (linkToNowherePath), "LinkToNowhere.txt"); + Assert.AreEqual ("Nowhere.txt", PathUtils.GetSymlinkTarget (linkToNowherePath), "LinkToNowhere.txt - IsSymlink target"); + } + + var manifest = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + Assert.AreEqual (manifest, File.ReadAllText (Path.Combine (directory, "manifest")), "Manifest"); + } + + ITaskItem[] CreateNativeReferences (string tmpdir, bool symlinks) + { + var rv = new List (); + + // Full path + var fn = Path.Combine (tmpdir, "A.txt"); + File.WriteAllText (fn, "ABCDEFGHIJKLMAAA"); + rv.Add (new TaskItem (fn)); + + // Relative path + fn = Path.Combine (tmpdir, "B.txt"); + File.WriteAllText (fn, "ABCDEFGHIJKLMBBB"); + rv.Add (new TaskItem (Path.GetFileName (fn))); + + // Directory with symlink + var dir = Path.Combine (tmpdir, "C.framework"); + Directory.CreateDirectory (dir); + rv.Add (new TaskItem (dir)); + File.WriteAllText (Path.Combine (dir, "C.txt"), "ABCDEFGHIJKLMCCC"); + if (symlinks) { + PathUtils.CreateSymlink (Path.Combine (dir, "LinkToC.txt"), "C.txt"); + PathUtils.CreateSymlink (Path.Combine (dir, "LinkToNowhere.txt"), "Nowhere.txt"); + } + + return rv.ToArray (); + } + + } +} + diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TestHelpers/TestEngine.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TestHelpers/TestEngine.cs index 926bec7e456f..c7a5f81c52ed 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TestHelpers/TestEngine.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TestHelpers/TestEngine.cs @@ -27,20 +27,30 @@ public bool BuildProjectFile (string projectFileName, string [] targetNames, IDi throw new NotImplementedException (); } + bool Verbose => false; // change to true while debugging output + public void LogCustomEvent (CustomBuildEventArgs e) { + if (Verbose) + Console.WriteLine (e.Message); Logger.CustomEvents.Add (e); } public void LogErrorEvent (BuildErrorEventArgs e) { + if (Verbose) + Console.WriteLine (e.Message); Logger.ErrorEvents.Add (e); } public void LogMessageEvent (BuildMessageEventArgs e) { + if (Verbose) + Console.WriteLine (e.Message); Logger.MessageEvents.Add (e); } public void LogWarningEvent (BuildWarningEventArgs e) { + if (Verbose) + Console.WriteLine (e.Message); Logger.WarningsEvents.Add (e); } diff --git a/tests/xharness/Harness.cs b/tests/xharness/Harness.cs index 735d06c50551..8323814cec79 100644 --- a/tests/xharness/Harness.cs +++ b/tests/xharness/Harness.cs @@ -287,7 +287,6 @@ void AutoConfigureDotNet () SkipwatchOSVariation = true, SkipTodayExtensionVariation = true, SkipDeviceVariations = false, - SkipiOS32Variation = true, TestPlatform = TestPlatform.iOS_Unified, Ignore = dotnetIgnored, Configurations = projectInfo.Configurations, @@ -301,7 +300,6 @@ void AutoConfigureDotNet () SkipwatchOSVariation = true, SkipTodayExtensionVariation = true, SkipDeviceVariations = false, - SkipiOS32Variation = true, GenerateVariations = false, TestPlatform = TestPlatform.tvOS, Ignore = dotnetIgnored, diff --git a/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs b/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs index c6f3c6e8c69d..4d8c5ddcc791 100644 --- a/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs +++ b/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs @@ -125,24 +125,10 @@ IEnumerable CreateAsync (Jenkins jenkins, IMlaunchProcessManag ignored = new [] { false }; break; case TestPlatform.iOS_Unified: - var iOSProject = (iOSTestProject) buildTask.TestProject; - if (iOSProject.SkipiOS32Variation && iOSProject.SkipiOS64Variation) { - return runtasks; - } else if (iOSProject.SkipiOS32Variation) { - targets = new TestTarget [] { TestTarget.Simulator_iOS64 }; - platforms = new TestPlatform [] { TestPlatform.iOS_Unified64 }; - ignored = new [] { false }; - } else if (iOSProject.SkipiOS64Variation) { - targets = new TestTarget [] { TestTarget.Simulator_iOS32 }; - platforms = new TestPlatform [] { TestPlatform.iOS_Unified32 }; - ignored = new [] { !jenkins.IncludeiOS32 }; - } else { - platforms = new TestPlatform [] { TestPlatform.iOS_Unified32, TestPlatform.iOS_Unified64 }; - ignored = new [] { !jenkins.IncludeiOS32, false }; - } + platforms = new TestPlatform [] { TestPlatform.iOS_Unified64 }; + ignored = new [] { false }; break; case TestPlatform.iOS_TodayExtension64: - targets = new TestTarget [] { TestTarget.Simulator_iOS64 }; platforms = new TestPlatform [] { TestPlatform.iOS_TodayExtension64 }; ignored = new [] { false }; break; diff --git a/tests/xharness/TestTargetExtensions.cs b/tests/xharness/TestTargetExtensions.cs index a77c425315f2..906479a5d3e7 100644 --- a/tests/xharness/TestTargetExtensions.cs +++ b/tests/xharness/TestTargetExtensions.cs @@ -15,9 +15,9 @@ public static TestTarget[] GetAppRunnerTargets (this TestPlatform platform) case TestPlatform.watchOS_64_32: return new TestTarget [] { TestTarget.Simulator_watchOS }; case TestPlatform.iOS_Unified: - return new TestTarget [] { TestTarget.Simulator_iOS32, TestTarget.Simulator_iOS64 }; + return new TestTarget [] { TestTarget.Simulator_iOS64 }; case TestPlatform.iOS_Unified32: - return new TestTarget [] { TestTarget.Simulator_iOS32 }; + throw new NotSupportedException ($"32-bit simulators aren't supported anymore."); case TestPlatform.iOS_Unified64: case TestPlatform.iOS_TodayExtension64: return new TestTarget [] { TestTarget.Simulator_iOS64 }; diff --git a/tests/xharness/Xharness.Tests/Tests/TestTargetExtensionsTests.cs b/tests/xharness/Xharness.Tests/Tests/TestTargetExtensionsTests.cs index 9615992cb1d3..7c9073b5143a 100644 --- a/tests/xharness/Xharness.Tests/Tests/TestTargetExtensionsTests.cs +++ b/tests/xharness/Xharness.Tests/Tests/TestTargetExtensionsTests.cs @@ -12,8 +12,7 @@ public class TestTargetExtensionsTests { [TestCase (TestPlatform.watchOS, new [] { TestTarget.Simulator_watchOS })] [TestCase (TestPlatform.watchOS_32, new [] { TestTarget.Simulator_watchOS })] [TestCase (TestPlatform.watchOS_64_32, new [] { TestTarget.Simulator_watchOS })] - [TestCase (TestPlatform.iOS_Unified, new [] { TestTarget.Simulator_iOS32, TestTarget.Simulator_iOS64 })] - [TestCase (TestPlatform.iOS_Unified32, new [] { TestTarget.Simulator_iOS32 })] + [TestCase (TestPlatform.iOS_Unified, new [] { TestTarget.Simulator_iOS64 })] [TestCase (TestPlatform.iOS_Unified64, new [] { TestTarget.Simulator_iOS64 })] [TestCase (TestPlatform.iOS_TodayExtension64, new [] { TestTarget.Simulator_iOS64 })] public void GetAppRunnerTargetsTest (TestPlatform platform, TestTarget[] expectedTargets) diff --git a/tests/xharness/iOSTestProject.cs b/tests/xharness/iOSTestProject.cs index 60a385a92431..2c6fca728ca0 100644 --- a/tests/xharness/iOSTestProject.cs +++ b/tests/xharness/iOSTestProject.cs @@ -4,8 +4,6 @@ namespace Xharness { public class iOSTestProject : TestProject { public bool SkipiOSVariation; - public bool SkipiOS32Variation; - public bool SkipiOS64Variation; public bool SkipwatchOSVariation; // skip both public bool SkipwatchOSARM64_32Variation; public bool SkipwatchOS32Variation; @@ -36,8 +34,6 @@ public override TestProject Clone () { var rv = (iOSTestProject) base.Clone (); rv.SkipiOSVariation = SkipiOSVariation; - rv.SkipiOS32Variation = SkipiOS32Variation; - rv.SkipiOS64Variation = SkipiOS64Variation; rv.SkipwatchOSVariation = SkipwatchOSVariation; rv.SkipwatchOSARM64_32Variation = SkipwatchOSARM64_32Variation; rv.SkipwatchOS32Variation = SkipwatchOS32Variation; diff --git a/tests/xtro-sharpie/MacCatalyst-AppKit.todo b/tests/xtro-sharpie/MacCatalyst-AppKit.todo deleted file mode 100644 index a0688ce1ab39..000000000000 --- a/tests/xtro-sharpie/MacCatalyst-AppKit.todo +++ /dev/null @@ -1,58 +0,0 @@ -!missing-enum! NSCollectionElementCategory not bound -!missing-enum! NSCollectionViewDropOperation not bound -!missing-enum! NSCollectionViewItemHighlightState not bound -!missing-enum! NSCollectionViewScrollDirection not bound -!missing-enum! NSCollectionViewScrollPosition not bound -!missing-selector! +NSToolbarItemGroup::groupWithItemIdentifier:images:selectionMode:labels:target:action: not bound -!missing-selector! +NSToolbarItemGroup::groupWithItemIdentifier:titles:selectionMode:labels:target:action: not bound -!missing-selector! NSMenuToolbarItem::setShowsIndicator: not bound -!missing-selector! NSMenuToolbarItem::showsIndicator not bound -!missing-selector! NSToolbarItemGroup::controlRepresentation not bound -!missing-selector! NSToolbarItemGroup::isSelectedAtIndex: not bound -!missing-selector! NSToolbarItemGroup::selectedIndex not bound -!missing-selector! NSToolbarItemGroup::selectionMode not bound -!missing-selector! NSToolbarItemGroup::setControlRepresentation: not bound -!missing-selector! NSToolbarItemGroup::setSelected:atIndex: not bound -!missing-selector! NSToolbarItemGroup::setSelectedIndex: not bound -!missing-selector! NSToolbarItemGroup::setSelectionMode: not bound -!missing-selector! NSToolbarItemGroup::setSubitems: not bound -!missing-selector! NSToolbarItemGroup::subitems not bound -!missing-type! NSMenuToolbarItem not bound -!missing-type! NSToolbarItemGroup not bound -## appended from unclassified file -!unknown-field! NSImageNameApplicationIcon bound -!unknown-field! NSImageNameCaution bound -!unknown-field! NSImageNameEnterFullScreenTemplate bound -!unknown-field! NSImageNameExitFullScreenTemplate bound -!unknown-field! NSImageNameFolder bound -!unknown-field! NSImageNameFollowLinkFreestandingTemplate bound -!unknown-field! NSImageNameIChatTheaterTemplate bound -!unknown-field! NSImageNameInvalidDataFreestandingTemplate bound -!unknown-field! NSImageNameLeftFacingTriangleTemplate bound -!unknown-field! NSImageNameMenuMixedStateTemplate bound -!unknown-field! NSImageNameMenuOnStateTemplate bound -!unknown-field! NSImageNameMobileMe bound -!unknown-field! NSImageNameRefreshFreestandingTemplate bound -!unknown-field! NSImageNameRevealFreestandingTemplate bound -!unknown-field! NSImageNameRightFacingTriangleTemplate bound -!unknown-field! NSImageNameSmartBadgeTemplate bound -!unknown-field! NSImageNameStatusAvailable bound -!unknown-field! NSImageNameStatusNone bound -!unknown-field! NSImageNameStatusPartiallyAvailable bound -!unknown-field! NSImageNameStatusUnavailable bound -!unknown-field! NSImageNameStopProgressFreestandingTemplate bound -!unknown-field! NSImageNameTouchBarPlayheadTemplate bound -!unknown-field! NSImageNameTrashEmpty bound -!unknown-field! NSImageNameTrashFull bound -!unknown-field! NSImageNameUserGuest bound -!unknown-field! NSToolbarCustomizeToolbarItemIdentifier bound -!unknown-field! NSToolbarSeparatorItemIdentifier bound -!unknown-field! NSToolbarSidebarTrackingSeparatorItemIdentifier bound -!unknown-field! NSTouchBarItemIdentifierCandidateList bound -!unknown-field! NSTouchBarItemIdentifierCharacterPicker bound -!unknown-field! NSTouchBarItemIdentifierTextAlignment bound -!unknown-field! NSTouchBarItemIdentifierTextColorPicker bound -!unknown-field! NSTouchBarItemIdentifierTextFormat bound -!unknown-field! NSTouchBarItemIdentifierTextList bound -!unknown-field! NSTouchBarItemIdentifierTextStyle bound -!unknown-pinvoke! NSBeep bound diff --git a/tools/common/Application.cs b/tools/common/Application.cs index 639d1646f055..9d15249cd86d 100644 --- a/tools/common/Application.cs +++ b/tools/common/Application.cs @@ -74,6 +74,7 @@ public partial class Application // The AOT arguments are currently not used for macOS, but they could eventually be used there as well (there's no mmp option to set these yet). public List AotArguments = new List (); public List AotOtherArguments = null; + public bool? AotFloat32 = null; public DlsymOptions DlsymOptions; public List> DlsymAssemblies; @@ -1482,6 +1483,8 @@ public void GetAotArguments (string filename, Abi abi, string outputDir, string processArguments.Add ("-O=gsharedvt"); if (app.AotOtherArguments != null) processArguments.AddRange (app.AotOtherArguments); + if (app.AotFloat32.HasValue) + processArguments.Add (app.AotFloat32.Value ? "-O=float32" : "-O=-float32"); aotArguments = new List (); if (Platform == ApplePlatform.MacCatalyst) { aotArguments.Add ($"--aot=mtriple={arch}-apple-ios{DeploymentTarget}-macabi"); diff --git a/tools/common/Assembly.cs b/tools/common/Assembly.cs index 57e5f78a4053..9b6bfc53ad46 100644 --- a/tools/common/Assembly.cs +++ b/tools/common/Assembly.cs @@ -161,6 +161,15 @@ public void ExtractNativeLinkInfo () return; string resourceBundlePath = Path.ChangeExtension (FullPath, ".resources"); + if (!Directory.Exists (resourceBundlePath)) { + var zipPath = resourceBundlePath + ".zip"; + if (File.Exists (zipPath)) { + var path = Path.Combine (App.Cache.Location, Path.GetFileName (resourceBundlePath)); + if (Driver.RunCommand ("/usr/bin/unzip", "-u", "-o", "-d", path, zipPath) != 0) + throw ErrorHelper.CreateError (1306, Errors.MX1306 /* Could not decompress the file '{0}'. Please review the build log for more information from the native 'unzip' command. */, zipPath); + resourceBundlePath = path; + } + } string manifestPath = Path.Combine (resourceBundlePath, "manifest"); if (File.Exists (manifestPath)) { foreach (NativeReferenceMetadata metadata in ReadManifest (manifestPath)) { diff --git a/tools/common/PathUtils.cs b/tools/common/PathUtils.cs index 6b95f33d376b..3435c7a66f86 100644 --- a/tools/common/PathUtils.cs +++ b/tools/common/PathUtils.cs @@ -211,5 +211,21 @@ public static bool IsSymlink (string file) const int S_IFLNK = 40960; return (buf.st_mode & S_IFLNK) == S_IFLNK; } + + public static bool IsSymlinkOrContainsSymlinks (string directoryOrFile) + { + if (IsSymlink (directoryOrFile)) + return true; + + if (!Directory.Exists (directoryOrFile)) + return false; + + foreach (var entry in Directory.EnumerateFileSystemEntries (directoryOrFile)) { + if (IsSymlinkOrContainsSymlinks (entry)) + return true; + } + + return false; + } } } diff --git a/tools/devops/automation/build-pipeline.yml b/tools/devops/automation/build-pipeline.yml index ef90bb9160ea..beff04e0a069 100644 --- a/tools/devops/automation/build-pipeline.yml +++ b/tools/devops/automation/build-pipeline.yml @@ -133,6 +133,8 @@ resources: endpoint: xamarin variables: +- ${{ if contains(variables['Build.DefinitionName'], 'private') }}: + - template: templates/variables.yml - group: xamops-azdev-secrets - group: Xamarin-Secrets - group: Xamarin Signing diff --git a/tools/devops/automation/post-build-pipeline.yml b/tools/devops/automation/post-build-pipeline.yml index e6a35a706220..d554a1f7e4f4 100644 --- a/tools/devops/automation/post-build-pipeline.yml +++ b/tools/devops/automation/post-build-pipeline.yml @@ -26,6 +26,7 @@ jobs: - group: Publish-Build-Assets steps: - checkout: self + path: s/xamarin-macios clean: true - task: UseDotNet@2 diff --git a/tools/devops/automation/scripts/GitHub.psm1 b/tools/devops/automation/scripts/GitHub.psm1 index 437f466812aa..a67e0336caac 100644 --- a/tools/devops/automation/scripts/GitHub.psm1 +++ b/tools/devops/automation/scripts/GitHub.psm1 @@ -831,6 +831,54 @@ function New-GistWithFiles { return $request.html_url } +<# + .SYNOPSIS + Puse a repository dispatch stating which branch did trigger it. + + .PARAMETER Org + The org of the repository to ping. + + .PARAMETER Repository + The repository to ping. + + .PARAMETER Branch + The branch that triggered the event. +#> +function Push-RepositoryDispatch { + param ( + + [ValidateNotNullOrEmpty ()] + [string] + $Org, + + [ValidateNotNullOrEmpty ()] + [string] + $Repository, + + [ValidateNotNullOrEmpty ()] + [string] + $Branch + ) + + # create the hashtable that will contain all the information of all types + $payload = @{ + event_type = $Branch; + } + + $url = "https://api.github.com/repos/$Org/$Repository/dispatches" + Write-Host $url + $payloadJson = $payload | ConvertTo-Json + + $headers = @{ + Accept = "application/vnd.github.v3+json"; + Authorization = ("token {0}" -f $Env:GITHUB_TOKEN); + } + + $request = Invoke-Request -Request { Invoke-RestMethod -Uri $url -Headers $headers -Method "POST" -Body $payloadJson -ContentType 'application/json' } + Write-Host $request + Write-Host $request.Content +} + # module exports, any other functions are private and should not be used outside the module. Export-ModuleMember -Function Set-GitHubStatus Export-ModuleMember -Function New-GitHubComment @@ -841,3 +889,4 @@ Export-ModuleMember -Function Get-GitHubPRInfo Export-ModuleMember -Function New-GistWithFiles Export-ModuleMember -Function New-GistObjectDefinition Export-ModuleMember -Function New-GistWithContent +Export-ModuleMember -Function Push-RepositoryDispatch diff --git a/tools/devops/automation/templates/build/build.yml b/tools/devops/automation/templates/build/build.yml index 2ad9dfead7a8..3fa5db90b5db 100644 --- a/tools/devops/automation/templates/build/build.yml +++ b/tools/devops/automation/templates/build/build.yml @@ -27,6 +27,7 @@ steps: - checkout: self # https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema#checkout clean: true # Executes: git clean -ffdx && git reset --hard HEAD submodules: recursive + path: s/xamarin-macios - checkout: maccore clean: true @@ -87,6 +88,7 @@ steps: env: BUILD_REVISION: 'jenkins' continueOnError: true + timeoutInMinutes: 60 - bash: | security set-key-partition-list -S apple-tool:,apple: -s -k $OSX_KEYCHAIN_PASS login.keychain @@ -276,6 +278,17 @@ steps: env: RUN_DEVICE_TESTS: '${{ parameters.runDeviceTests }}' +- ${{ if contains(variables['Build.DefinitionName'], 'private') }}: + - bash: | + set -x + set -e + ARGS="--azure-feed \"https://dotnetclimsrc.blob.core.windows.net/dotnet\" -FeedCredential $CREDENTIALS" + echo "##vso[task.setvariable variable=DOTNET_INSTALL_EXTRA_ARGS]$ARGS" + env: + CREDENTIALS: $(dotnetclimsrc-read-sas-token) + displayName: "Configure install extra args" + timeoutInMinutes: 5 + - bash: | set -x set -e diff --git a/tools/devops/automation/templates/build/configure.yml b/tools/devops/automation/templates/build/configure.yml index c51979eb6cc7..aa47945c3d92 100644 --- a/tools/devops/automation/templates/build/configure.yml +++ b/tools/devops/automation/templates/build/configure.yml @@ -12,6 +12,7 @@ steps: clean: true # Executes: git clean -ffdx && git reset --hard HEAD submodules: false persistCredentials: true + path: s/xamarin-macios - pwsh: | Import-Module $Env:SYSTEM_DEFAULTWORKINGDIRECTORY/tools/devops/automation/scripts/GitHub.psm1 diff --git a/tools/devops/automation/templates/build/download-artifacts.yml b/tools/devops/automation/templates/build/download-artifacts.yml index 6e120333e493..86f52fe878e3 100644 --- a/tools/devops/automation/templates/build/download-artifacts.yml +++ b/tools/devops/automation/templates/build/download-artifacts.yml @@ -7,6 +7,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios # download the common artifacts + the api diff - template: ../common/download-artifacts.yml diff --git a/tools/devops/automation/templates/build/publish-html.yml b/tools/devops/automation/templates/build/publish-html.yml index 37a052a54db6..0564498f53ab 100644 --- a/tools/devops/automation/templates/build/publish-html.yml +++ b/tools/devops/automation/templates/build/publish-html.yml @@ -33,6 +33,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios - template: download-artifacts.yml parameters: diff --git a/tools/devops/automation/templates/build/stage.yml b/tools/devops/automation/templates/build/stage.yml index 59726c1559b1..5ca3f838e167 100644 --- a/tools/devops/automation/templates/build/stage.yml +++ b/tools/devops/automation/templates/build/stage.yml @@ -112,7 +112,7 @@ jobs: dependsOn: - configure - build # can start as soon as the packages are available - condition: and(succeeded(), contains (dependencies.build.outputs['configuration.BuildPkgs'], 'True')) # only run when we do have pkgs + condition: and(succeeded(), contains (dependencies.build.outputs['configuration.BuildPkgs'], 'True'), not(contains (variables['Build.DefinitionName'], 'private'))) # only run when we do have pkgs and on public builds variables: Parameters.outputStorageUri: '' diff --git a/tools/devops/automation/templates/build/upload-azure.yml b/tools/devops/automation/templates/build/upload-azure.yml index f43384cde9b7..829b7130db07 100644 --- a/tools/devops/automation/templates/build/upload-azure.yml +++ b/tools/devops/automation/templates/build/upload-azure.yml @@ -7,6 +7,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios # Download the Html Report that was added by the tests job. - task: DownloadPipelineArtifact@2 diff --git a/tools/devops/automation/templates/build/upload-vsdrops.yml b/tools/devops/automation/templates/build/upload-vsdrops.yml index da27f7227e4e..4068cf8624bb 100644 --- a/tools/devops/automation/templates/build/upload-vsdrops.yml +++ b/tools/devops/automation/templates/build/upload-vsdrops.yml @@ -14,6 +14,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios - template: download-artifacts.yml parameters: diff --git a/tools/devops/automation/templates/common/download-artifacts.yml b/tools/devops/automation/templates/common/download-artifacts.yml index a2e57d6b331b..0abe23ddf5be 100644 --- a/tools/devops/automation/templates/common/download-artifacts.yml +++ b/tools/devops/automation/templates/common/download-artifacts.yml @@ -13,6 +13,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios - ${{ if eq(parameters.runTests, true) }}: # Download the Html Report that was added by the tests job. diff --git a/tools/devops/automation/templates/common/publish-html.yml b/tools/devops/automation/templates/common/publish-html.yml index df6f59e2e476..1ea48a9e2809 100644 --- a/tools/devops/automation/templates/common/publish-html.yml +++ b/tools/devops/automation/templates/common/publish-html.yml @@ -32,6 +32,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios - ${{ if eq(parameters.provisioningFailed, 'False') }}: - template: download-artifacts.yml diff --git a/tools/devops/automation/templates/common/upload-vsdrops.yml b/tools/devops/automation/templates/common/upload-vsdrops.yml index b07f9cfdb703..8c05650b04ad 100644 --- a/tools/devops/automation/templates/common/upload-vsdrops.yml +++ b/tools/devops/automation/templates/common/upload-vsdrops.yml @@ -15,6 +15,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios - ${{ if eq(parameters.provisioningFailed, 'False') }}: - template: download-artifacts.yml diff --git a/tools/devops/automation/templates/common/upload-vsts-tests.yml b/tools/devops/automation/templates/common/upload-vsts-tests.yml index 47ac8334c8b4..2000769dd808 100644 --- a/tools/devops/automation/templates/common/upload-vsts-tests.yml +++ b/tools/devops/automation/templates/common/upload-vsts-tests.yml @@ -14,6 +14,7 @@ steps: - checkout: self persistCredentials: true + path: s/xamarin-macios - ${{ if eq(parameters.provisioningFailed, 'False') }}: - template: download-artifacts.yml diff --git a/tools/devops/automation/templates/devices/build.yml b/tools/devops/automation/templates/devices/build.yml index f74998750d5b..43b4bd567c88 100644 --- a/tools/devops/automation/templates/devices/build.yml +++ b/tools/devops/automation/templates/devices/build.yml @@ -46,6 +46,7 @@ parameters: steps: - checkout: self + path: s/xamarin-macios - checkout: maccore persistCredentials: true # hugely important, else there are some scripts that check a single file from maccore that will fail @@ -54,6 +55,7 @@ steps: env: BUILD_REVISION: 'jenkins' continueOnError: true + timeoutInMinutes: 60 - bash: cd $(System.DefaultWorkingDirectory)/xamarin-macios/ && git clean -xdf displayName: 'Clean workspace' diff --git a/tools/devops/automation/templates/governance-checks.yml b/tools/devops/automation/templates/governance-checks.yml index ee20b9199435..5cc036484757 100644 --- a/tools/devops/automation/templates/governance-checks.yml +++ b/tools/devops/automation/templates/governance-checks.yml @@ -1,6 +1,7 @@ steps: - checkout: self + path: s/xamarin-macios - checkout: maccore persistCredentials: true # hugely important, else there are some scripts that check a single file from maccore that will fail diff --git a/tools/devops/automation/templates/mac/build.yml b/tools/devops/automation/templates/mac/build.yml index 0b1bc56b8b1f..40a6f3b554d8 100644 --- a/tools/devops/automation/templates/mac/build.yml +++ b/tools/devops/automation/templates/mac/build.yml @@ -15,6 +15,7 @@ parameters: steps: - checkout: self + path: s/xamarin-macios - checkout: maccore persistCredentials: true # hugely important, else there are some scripts that check a single file from maccore that will fail @@ -65,6 +66,7 @@ steps: env: BUILD_REVISION: 'jenkins' continueOnError: true + timeoutInMinutes: 60 # Use a cmdlet to check if the space available in the devices root system is larger than 50 gb. If there is not # enough space available it: diff --git a/tools/devops/automation/templates/publish-html-result.yml b/tools/devops/automation/templates/publish-html-result.yml index 95cb70c6cceb..f718f235c8bd 100644 --- a/tools/devops/automation/templates/publish-html-result.yml +++ b/tools/devops/automation/templates/publish-html-result.yml @@ -12,6 +12,7 @@ parameters: steps: - checkout: self + path: s/xamarin-macios persistCredentials: true - checkout: macios.ci diff --git a/tools/devops/automation/templates/variables.yml b/tools/devops/automation/templates/variables.yml new file mode 100644 index 000000000000..d7ba27e5753b --- /dev/null +++ b/tools/devops/automation/templates/variables.yml @@ -0,0 +1,4 @@ + variables: + - group: AzureDevOps-Artifact-Feeds-Pats + - group: DotNet-MSRC-Storage + diff --git a/tools/devops/automation/templates/windows/build.yml b/tools/devops/automation/templates/windows/build.yml index fce15b321986..a6399416d112 100644 --- a/tools/devops/automation/templates/windows/build.yml +++ b/tools/devops/automation/templates/windows/build.yml @@ -7,6 +7,7 @@ parameters: steps: - checkout: self + path: s/xamarin-macios - checkout: maccore persistCredentials: true # hugely important, else there are some scripts that check a single file from maccore that will fail diff --git a/tools/devops/build-samples.yml b/tools/devops/build-samples.yml index 18bd1508f2d1..dacde1aa5796 100644 --- a/tools/devops/build-samples.yml +++ b/tools/devops/build-samples.yml @@ -100,6 +100,7 @@ jobs: steps: - checkout: self + path: s/xamarin-macios - checkout: xamarin-macios-data persistCredentials: true - checkout: maccore @@ -173,6 +174,7 @@ jobs: vmImage: '$(macOSVersion)' steps: - checkout: self + path: s/xamarin-macios - checkout: xamarin-macios-data persistCredentials: true diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index 3bccda16330a..23663ba5c83e 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -184,6 +184,10 @@ public static LinkerConfiguration GetInstance (LinkContext context, bool createI case "MonoLibrary": Application.MonoLibraries.Add (value); break; + case "MtouchFloat32": + if (!TryParseOptionalBoolean (value, out Application.AotFloat32)) + throw new InvalidOperationException ($"Unable to parse the {key} value: {value} in {linker_file}"); + break; case "Optimize": user_optimize_flags = value; break; @@ -321,6 +325,26 @@ public static LinkerConfiguration GetInstance (LinkContext context, bool createI Application.Initialize (); } + bool TryParseOptionalBoolean (string input, out bool? value) + { + value = null; + + if (string.IsNullOrEmpty (input)) + return true; + + if (string.Equals (input, "true", StringComparison.OrdinalIgnoreCase)) { + value = true; + return true; + } + + if (string.Equals (input, "false", StringComparison.OrdinalIgnoreCase)) { + value = false; + return true; + } + + return false; + } + AssemblyBuildTarget ParseLinkMode (string value, string variableName) { if (string.Equals (value, "dylib", StringComparison.OrdinalIgnoreCase)) { diff --git a/tools/mtouch/Errors.designer.cs b/tools/mtouch/Errors.designer.cs index 42373e747ad4..83d10a2c5dbf 100644 --- a/tools/mtouch/Errors.designer.cs +++ b/tools/mtouch/Errors.designer.cs @@ -3785,6 +3785,15 @@ public static string MX1009 { } } + /// + /// Looks up a localized string similar to Could not decompress the file '{0}'. Please review the build log for more information from the native 'unzip' command.. + /// + public static string MX1306 { + get { + return ResourceManager.GetString("MX1306", resourceCulture); + } + } + /// /// Looks up a localized string similar to One or more reference(s) to type '{0}' already exists inside '{1}' before linking /// . diff --git a/tools/mtouch/Errors.resx b/tools/mtouch/Errors.resx index f5c7e9dde275..3c80d288731b 100644 --- a/tools/mtouch/Errors.resx +++ b/tools/mtouch/Errors.resx @@ -1015,6 +1015,10 @@ + + Could not decompress the file '{0}'. Please review the build log for more information from the native 'unzip' command. + + The required 'Xamarin.Mac.dll' assembly is missing from the references