[macOS] Implement new directories hierarchy (#8741)

This commit is contained in:
Shamil Mubarakshin
2023-11-15 12:12:28 +01:00
committed by GitHub
parent 5d40b1e213
commit 8d6a01b370
133 changed files with 1713 additions and 1677 deletions

View File

@@ -0,0 +1,206 @@
function Get-CommandResult {
param (
[Parameter(Mandatory=$true)]
[string] $Command,
[switch] $Multiline
)
# Bash trick to suppress and show error output because some commands write to stderr (for example, "python --version")
$stdout = & bash -c "$Command 2>&1"
$exitCode = $LASTEXITCODE
return @{
Output = If ($Multiline -eq $true) { $stdout } else { [string]$stdout }
ExitCode = $exitCode
}
}
# Gets path to the tool, analogue of 'which tool'
function Get-WhichTool($tool) {
return (Get-Command $tool).Path
}
# Gets value of environment variable by the name
function Get-EnvironmentVariable($variable) {
return [System.Environment]::GetEnvironmentVariable($variable)
}
# Returns the object with information about current OS
# It can be used for OS-specific tests
function Get-OSVersion {
$osVersion = [Environment]::OSVersion
$osVersionMajorMinor = $osVersion.Version.ToString(2)
$processorArchitecture = arch
return [PSCustomObject]@{
Version = $osVersion.Version
Platform = $osVersion.Platform
IsArm64 = $processorArchitecture -eq "arm64"
IsBigSur = $osVersion.Version.Major -eq "11"
IsMonterey = $osVersion.Version.Major -eq "12"
IsVentura = $($osVersion.Version.Major -eq "13")
IsVenturaArm64 = $($osVersion.Version.Major -eq "13" -and $processorArchitecture -eq "arm64")
IsVenturaX64 = $($osVersion.Version.Major -eq "13" -and $processorArchitecture -ne "arm64")
IsSonoma = $($osVersion.Version.Major -eq "14")
IsSonomaArm64 = $($osVersion.Version.Major -eq "14" -and $processorArchitecture -eq "arm64")
IsSonomaX64 = $($osVersion.Version.Major -eq "14" -and $processorArchitecture -ne "arm64")
}
}
function Get-ChildItemWithoutSymlinks {
param (
[Parameter(Mandatory)]
[string] $Path,
[string] $Filter
)
$files = Get-ChildItem -Path $Path -Filter $Filter
$files = $files | Where-Object { !$_.LinkType } # cut symlinks
return $files
}
# Get the value of specific toolset node
# Example, invoke `Get-ToolsetValue "xamarin.bundles"` to get value of `$toolsetJson.xamarin.bundles`
function Get-ToolsetValue {
param (
[Parameter(Mandatory = $true)]
[string] $KeyPath
)
$toolsetPath = Join-Path $env:HOME "image-generation" "toolset.json"
$jsonNode = Get-Content -Raw $toolsetPath | ConvertFrom-Json
$pathParts = $KeyPath.Split(".")
# try to walk through all arguments consequentially to resolve specific json node
$pathParts | ForEach-Object {
$jsonNode = $jsonNode.$_
}
return $jsonNode
}
function Get-ToolcachePackages {
$toolcachePath = Join-Path $env:HOME "image-generation" "toolcache.json"
return Get-Content -Raw $toolcachePath | ConvertFrom-Json
}
function Invoke-RestMethodWithRetry {
param (
[Parameter()]
[string]
$Url
)
Invoke-RestMethod $Url -MaximumRetryCount 10 -RetryIntervalSec 30
}
function Invoke-ValidateCommand {
param(
[Parameter(Mandatory)]
[string]$Command,
[Uint] $Timeout = 0
)
if ($Timeout -eq 0)
{
$output = Invoke-Expression -Command $Command
if ($LASTEXITCODE -ne 0) {
throw "Command '$Command' has finished with exit code $LASTEXITCODE"
}
return $output
}
else
{
$job = $command | Start-Job -ScriptBlock {
$output = Invoke-Expression -Command $input
if ($LASTEXITCODE -ne 0) {
throw 'Command failed'
}
return $output
}
$waitObject = $job | Wait-Job -Timeout $Timeout
if(-not $waitObject)
{
throw "Command '$Command' has timed out"
}
if($waitObject.State -eq 'Failed')
{
throw "Command '$Command' has failed"
}
Receive-Job -Job $job
}
}
function Start-DownloadWithRetry {
Param
(
[Parameter(Mandatory)]
[string] $Url,
[string] $Name,
[string] $DownloadPath = "${env:Temp}",
[int] $Retries = 20,
[int] $Interval = 30
)
if ([String]::IsNullOrEmpty($Name)) {
$Name = [IO.Path]::GetFileName($Url)
}
$filePath = Join-Path -Path $DownloadPath -ChildPath $Name
#Default retry logic for the package.
while ($Retries -gt 0)
{
try
{
Write-Host "Downloading package from: $Url to path $filePath ."
(New-Object System.Net.WebClient).DownloadFile($Url, $filePath)
break
}
catch
{
Write-Host "There is an error during package downloading:`n $_"
$Retries--
if ($Retries -eq 0)
{
Write-Host "File can't be downloaded. Please try later or check that file exists by url: $Url"
exit 1
}
Write-Host "Waiting $Interval seconds before retrying. Retries left: $Retries"
Start-Sleep -Seconds $Interval
}
}
return $filePath
}
function Add-EnvironmentVariable {
param
(
[Parameter(Mandatory)] [string] $Name,
[Parameter(Mandatory)] [string] $Value,
[string] $FilePath = "${env:HOME}/.bashrc"
)
$envVar = "export {0}={1}" -f $Name, $Value
Add-Content -Path $FilePath -Value $envVar
}
function isVeertu {
return (Test-Path -Path "/Library/Application Support/Veertu")
}
function Get-Architecture {
$arch = arch
if ($arch -ne "arm64")
{
$arch = "x64"
}
return $arch
}
function Test-CommandExists {
param
(
[Parameter(Mandatory)] [string] $Command
)
[boolean] (Get-Command $Command -ErrorAction 'SilentlyContinue')
}

View File

@@ -0,0 +1,54 @@
function Run-Command {
param (
[Parameter(Mandatory=$true)]
[string] $Command,
[switch] $SuppressStderr
)
# Bash trick to suppress and show error output because some commands write to stderr (for example, "python --version")
$redirectOutputArguments = If ($SuppressStderr) { "2> /dev/null" } Else { "2>&1" }
$stdout = & bash -c "${Command} ${redirectOutputArguments}"
return $stdout
}
function Take-Part {
param (
[Parameter(ValueFromPipeline)]
[string] $toolOutput,
[string] $Delimiter = " ",
[int[]] $Part
)
$parts = $toolOutput.Split($Delimiter, [System.StringSplitOptions]::RemoveEmptyEntries)
$selectedParts = $parts[$Part]
return [string]::Join($Delimiter, $selectedParts)
}
function Get-LinkTarget {
param (
[string] $inputPath
)
$link = Get-Item $inputPath | Select-Object -ExpandProperty Target
if ($link) {
return " -> $link"
}
return ""
}
function Get-PathWithLink {
param (
[string] $inputPath
)
$link = Get-LinkTarget($inputPath)
return "${inputPath}${link}"
}
function Get-BrewPackageVersion {
param (
[string] $CommandName
)
(Get-LinkTarget (Get-Command $CommandName).Source | Out-String) -match "(?<version>(\d+.){2}\d+)" | Out-Null
$packageVersion = $Matches.Version
return $packageVersion
}

View File

@@ -0,0 +1,152 @@
Import-Module "$PSScriptRoot/Common.Helpers.psm1"
# Validates that tool is installed and in PATH
function Validate-ToolExist($tool) {
Get-Command $tool -ErrorAction SilentlyContinue | Should -BeTrue
}
function Validate-ArrayWithoutDuplicates {
param (
[AllowEmptyCollection()]
[Parameter(Mandatory = $true)]
[array] $Items,
[string] $Because
)
$uniqueList = @()
$Items | ForEach-Object {
$uniqueList | Should -Not -Contain $_ -Because $Because
$uniqueList += $_
}
}
function Validate-Url {
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Url
)
$result = $true
try {
$requestResult = Invoke-WebRequest $Url -DisableKeepAlive -UseBasicParsing -Method Head
$result = ($requestResult.StatusCode -eq 200)
} catch {
$result = $false
}
$result | Should -BeTrue -Because "'$Url' should be available, but it is not"
}
function Validate-IdenticalFileContent {
param (
[Parameter(Mandatory)]
[string] $File1,
[Parameter(Mandatory)]
[string] $File2
)
$File1 | Should -Exist -Because "The content of '$File1' should be identical with content of '$File2' but '$File1' doesn't exist"
$File2 | Should -Exist -Because "The content of '$File1' should be identical with content of '$File2' but '$File2' doesn't exist"
$content1 = Get-Content -Raw $File1
$content2 = Get-Content -Raw $File2
$content1 | Should -Be $content2 -Because "The content of '$File1' should be identical with content of '$File2' but they are different"
}
function ShouldReturnZeroExitCode {
Param(
[String] $ActualValue,
[switch] $Negate,
[string] $Because # This parameter is unused by we need it to match Pester asserts signature
)
$result = Get-CommandResult $ActualValue
[bool]$succeeded = $result.ExitCode -eq 0
if ($Negate) { $succeeded = -not $succeeded }
if (-not $succeeded)
{
$commandOutputIndent = " " * 4
$commandOutput = ($result.Output | ForEach-Object { "${commandOutputIndent}${_}" }) -join "`n"
$failureMessage = "Command '${ActualValue}' has finished with exit code ${actualExitCode}`n${commandOutput}"
}
return [PSCustomObject] @{
Succeeded = $succeeded
FailureMessage = $failureMessage
}
}
function ShouldMatchCommandOutput {
Param(
[String] $ActualValue,
[String] $RegularExpression,
[switch] $Negate
)
$output = (Get-CommandResult $ActualValue).Output | Out-String
[bool] $succeeded = $output -cmatch $RegularExpression
if ($Negate) {
$succeeded = -not $succeeded
}
$failureMessage = ''
if (-not $succeeded) {
if ($Negate) {
$failureMessage = "Expected regular expression '$RegularExpression' for '$ActualValue' command to not match '$output', but it did match."
}
else {
$failureMessage = "Expected regular expression '$RegularExpression' for '$ActualValue' command to match '$output', but it did not match."
}
}
return [PSCustomObject] @{
Succeeded = $succeeded
FailureMessage = $failureMessage
}
}
If (Get-Command -Name Add-ShouldOperator -ErrorAction SilentlyContinue) {
Add-ShouldOperator -Name ReturnZeroExitCode -InternalName ShouldReturnZeroExitCode -Test ${function:ShouldReturnZeroExitCode}
Add-ShouldOperator -Name MatchCommandOutput -InternalName ShouldMatchCommandOutput -Test ${function:ShouldMatchCommandOutput}
}
function Invoke-PesterTests {
Param(
[Parameter(Mandatory)][string] $TestFile,
[string] $TestName
)
$testPath = "$HOME/image-generation/tests/${TestFile}.Tests.ps1"
if (-not (Test-Path $testPath)) {
throw "Unable to find test file '$TestFile' on '$testPath'."
}
# Check that Pester module is imported
if (!(Get-Module "Pester")) {
Import-Module Pester
}
$configuration = [PesterConfiguration] @{
Run = @{ Path = $testPath; PassThru = $true }
Output = @{ Verbosity = "Detailed"; RenderMode = "Plaintext" }
}
if ($TestName) {
$configuration.Filter.FullName = $TestName
}
# Switch ErrorActionPreference to make sure that tests will fail on silent errors too
$backupErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = "Stop"
$results = Invoke-Pester -Configuration $configuration
$ErrorActionPreference = $backupErrorActionPreference
# Fail in case if no tests are run
if (-not ($results -and ($results.FailedCount -eq 0) -and ($results.PassedCount -gt 0))) {
$results
throw "Test run has failed"
}
}

View File

@@ -0,0 +1,308 @@
function Get-XcodeRootPath {
Param (
[Parameter(Mandatory)]
[string] $Version
)
return "/Applications/Xcode_$Version.app"
}
function Get-DefaultXcodeRootPath {
return (Get-Item -Path "/Applications/Xcode.app").Target
}
function Get-XcodeToolPath {
param (
[Parameter(ParameterSetName = 'Version')]
[string] $Version,
[Parameter(ParameterSetName = 'Path')]
[string] $XcodeRootPath,
[string] $ToolName
)
if ($PSCmdlet.ParameterSetName -eq "Version") {
$XcodeRootPath = Get-XcodeRootPath $Version
}
return Join-Path $XcodeRootPath "Contents/Developer/usr/bin" $ToolName
}
function Get-XcodeVersionInfo {
param(
[Parameter(Mandatory)]
[string]$XcodeRootPath
)
$xcodebuildPath = Get-XcodeToolPath -XcodeRootPath $XcodeRootPath -ToolName "xcodebuild"
[string]$output = Invoke-Expression "$xcodebuildPath -version"
$versionOutputParts = $output.Split(" ")
return @{
Version = [System.Version]::Parse($versionOutputParts[1])
Build = $versionOutputParts[4]
}
}
function Switch-Xcode {
param (
[Parameter(ParameterSetName = 'Version')]
[string] $Version,
[Parameter(ParameterSetName = 'Path')]
[string] $XcodeRootPath
)
if ($PSCmdlet.ParameterSetName -eq "Version") {
$XcodeRootPath = Get-XcodeRootPath $Version
}
Write-Verbose "Switching Xcode to '${XcodeRootPath}'"
Invoke-Expression "sudo xcode-select --switch ${XcodeRootPath}"
}
function Test-XcodeStableRelease {
param (
[Parameter(ParameterSetName = 'Version')]
[string] $Version,
[Parameter(ParameterSetName = 'Path')]
[string] $XcodeRootPath
)
if ($PSCmdlet.ParameterSetName -eq "Version") {
$XcodeRootPath = Get-XcodeRootPath $Version
}
$licenseInfoPlistPath = Join-Path $XcodeRootPath "Contents" "Resources" "LicenseInfo.plist"
$releaseType = & defaults read $licenseInfoPlistPath "licenseType"
return -not ($releaseType -match "beta")
}
function Get-XcodeSimulatorsInfo {
param(
[string] $Filter
)
[string]$rawSimulatorsInfo = Invoke-Expression "xcrun simctl list --json"
$jsonSimulatorsInfo = $rawSimulatorsInfo | ConvertFrom-Json
if ($Filter) {
return $jsonSimulatorsInfo | Select-Object -ExpandProperty $Filter
}
return $jsonSimulatorsInfo
}
function Get-XcodeDevicesList {
$result = @()
$runtimes = Get-XcodeSimulatorsInfo -Filter "devices"
$runtimes.PSObject.Properties | ForEach-Object {
$runtimeName = $_.Name
$devices = $_.Value
$devices | Where-Object {
$availability = $_.availability
$isAvailable = $_.isAvailable
return (($availability -eq "(available)") -or ($isAvailable -eq "YES") -or ($isAvailable -eq $true))
} | ForEach-Object {
$deviceName = $_.name
$result += "$runtimeName $deviceName"
}
}
return $result
}
function Get-XcodePairsList {
$result = @()
$runtimes = Get-XcodeSimulatorsInfo -Filter "pairs"
$runtimes.PSObject.Properties | Where-Object {
return $_.Value.state -match "active"
} | ForEach-Object {
$watchName = $_.Value.watch.name
$phoneName = $_.Value.phone.name
$result += "$watchName $phoneName"
}
return $result
}
#Helper function for execution of xcversion due to: https://github.com/fastlane/fastlane/issues/18161
function Invoke-XCVersion {
param(
[Parameter(Mandatory)]
[string] $Arguments,
[Parameter()]
[int] $RetryAttempts = 7,
[Parameter()]
[int] $PauseDurationSecs = 1
)
$Command = "xcversion $Arguments"
Write-Host "Execute [$Command]"
for ($Attempt=1; $Attempt -le $RetryAttempts; $Attempt++) {
Write-Host "Current attempt: [$Attempt]"
$result = Get-CommandResult -Command $Command -Multiline
Write-Host "Exit code: [$($result.ExitCode)]"
Write-Host "Output message: "
$result.Output | ForEach-Object { Write-Host $_ }
if ($result.ExitCode -ne 0) {
Start-Sleep -Seconds $PauseDurationSecs
} else {
return $result.Output
}
}
if ($result.ExitCode -ne 0) {
throw "Command [$Command] has finished with non-zero exit code."
}
}
function Get-BrokenXcodeSimulatorsList {
return @(
# tvOS Simulators
@{
SimulatorName = "Apple TV 4K (at 1080p) (2nd generation)"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-2nd-generation-1080p";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.tvOS-15-0";
XcodeVersion = "13.1"
},
@{
SimulatorName = "Apple TV 4K (at 1080p) (2nd generation)"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-2nd-generation-1080p";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.tvOS-15-2";
XcodeVersion = "13.2.1"
},
@{
SimulatorName = "Apple TV 4K (at 1080p) (2nd generation)"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-2nd-generation-1080p";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.tvOS-15-4";
XcodeVersion = "13.4.1"
},
@{
SimulatorName = "Apple TV 4K (at 1080p) (2nd generation)"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-2nd-generation-1080p";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.tvOS-16-0";
XcodeVersion = "14.2"
},
# watchOS-8-0 Simulators
@{
SimulatorName = "Apple Watch Series 5 - 40mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-40mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-0";
XcodeVersion = "13.1"
},
@{
SimulatorName = "Apple Watch Series 5 - 44mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-44mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-0";
XcodeVersion = "13.1"
},
@{
SimulatorName = "Apple Watch Series 6 - 40mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-40mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-0";
XcodeVersion = "13.1"
},
@{
SimulatorName = "Apple Watch Series 6 - 44mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-44mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-0";
XcodeVersion = "13.1"
},
@{
SimulatorName = "Apple Watch Series 7 - 41mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-41mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-0";
XcodeVersion = "13.1"
},
@{
SimulatorName = "Apple Watch Series 7 - 45mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-45mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-0";
XcodeVersion = "13.1"
},
# watchOS-8-3 Simulators
@{
SimulatorName = "Apple Watch Series 5 - 40mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-40mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-3";
XcodeVersion = "13.2.1"
},
@{
SimulatorName = "Apple Watch Series 5 - 44mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-44mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-3";
XcodeVersion = "13.2.1"
},
@{
SimulatorName = "Apple Watch Series 6 - 40mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-40mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-3";
XcodeVersion = "13.2.1"
},
@{
SimulatorName = "Apple Watch Series 6 - 44mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-44mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-3";
XcodeVersion = "13.2.1"
},
@{
SimulatorName = "Apple Watch Series 7 - 41mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-41mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-3";
XcodeVersion = "13.2.1"
},
@{
SimulatorName = "Apple Watch Series 7 - 45mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-45mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-3";
XcodeVersion = "13.2.1"
},
# watchOS-8-5 Simulators
@{
SimulatorName = "Apple Watch Series 5 - 40mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-40mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-5";
XcodeVersion = "13.4.1"
},
@{
SimulatorName = "Apple Watch Series 5 - 44mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-44mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-5";
XcodeVersion = "13.4.1"
},
@{
SimulatorName = "Apple Watch Series 6 - 40mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-40mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-5";
XcodeVersion = "13.4.1"
},
@{
SimulatorName = "Apple Watch Series 6 - 44mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-44mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-5";
XcodeVersion = "13.4.1"
},
@{
SimulatorName = "Apple Watch Series 7 - 41mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-41mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-5";
XcodeVersion = "13.4.1"
},
@{
SimulatorName = "Apple Watch Series 7 - 45mm"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-45mm";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-8-5";
XcodeVersion = "13.4.1"
},
# watchOS-9-0 Simulators
@{
SimulatorName = "Apple Watch SE (40mm) (2nd generation)"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-40mm-2nd-generation";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-9-0";
XcodeVersion = "14.2"
},
@{
SimulatorName = "Apple Watch SE (44mm) (2nd generation)"
DeviceId = "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-44mm-2nd-generation";
RuntimeId = "com.apple.CoreSimulator.SimRuntime.watchOS-9-0";
XcodeVersion = "14.2"
}
)
}

View File

@@ -0,0 +1,249 @@
Import-Module "$PSScriptRoot/Common.Helpers.psm1"
Import-Module "$PSScriptRoot/Xcode.Helpers.psm1"
function Install-XcodeVersion {
param(
[Parameter(Mandatory)]
[string]$Version,
[Parameter(Mandatory)]
[string]$LinkTo
)
$xcodeDownloadDirectory = "$env:HOME/Library/Caches/XcodeInstall"
$xcodeTargetPath = Get-XcodeRootPath -Version $LinkTo
$xcodeXipDirectory = Invoke-DownloadXcodeArchive -DownloadDirectory $xcodeDownloadDirectory -Version $Version
Expand-XcodeXipArchive -DownloadDirectory $xcodeXipDirectory.FullName -TargetPath $xcodeTargetPath
Remove-Item -Path $xcodeXipDirectory -Force -Recurse
}
function Invoke-DownloadXcodeArchive {
param(
[Parameter(Mandatory)]
[string]$DownloadDirectory,
[Parameter(Mandatory)]
[string]$Version
)
Write-Host "Downloading Xcode $Version"
$tempXipDirectory = New-Item -Path $DownloadDirectory -Name "Xcode$Version" -ItemType "Directory"
$xcodeFileName = 'Xcode-{0}.xip' -f $Version
$xcodeUri = '{0}{1}?{2}'-f ${env:XCODE_INSTALL_STORAGE_URL}, $xcodeFileName, ${env:XCODE_INSTALL_SAS}
Start-DownloadWithRetry -Url $xcodeUri -DownloadPath $tempXipDirectory.FullName -Name $xcodeFileName
return $tempXipDirectory
}
function Resolve-ExactXcodeVersion {
param(
[Parameter(Mandatory)]
[string]$Version
)
# if toolset string contains spaces, consider it as a full name of Xcode
if ($Version -match "\s") {
return $Version
}
$semverVersion = [SemVer]::Parse($Version)
$availableVersions = Get-AvailableXcodeVersions
$satisfiedVersions = $availableVersions | Where-Object { $semverVersion -eq $_.stableSemver }
return $satisfiedVersions | Select-Object -Last 1 -ExpandProperty rawVersion
}
function Get-AvailableXcodeVersions {
$rawVersionsList = Invoke-XCVersion -Arguments "list" | ForEach-Object { $_.Trim() } | Where-Object { $_ -match "^\d" }
$availableVersions = $rawVersionsList | ForEach-Object {
$partStable,$partMajor = $_.Split(" ", 2)
$semver = $stableSemver = [SemVer]::Parse($partStable)
if ($partMajor) {
# Convert 'beta 3' -> 'beta.3', 'Release Candidate' -> 'releasecandidate', 'GM Seed 2' -> 'gmseed.2'
$normalizedLabel = $partMajor.toLower() -replace " (\d)", '.$1' -replace " ([a-z])", '$1'
$semver = [SemVer]::new($stableSemver.Major, $stableSemver.Minor, $stableSemver.Patch, $normalizedLabel)
}
return [PSCustomObject]@{
semver = $semver
rawVersion = $_
stableSemver = $stableSemver
}
}
return $availableVersions | Sort-Object -Property semver
}
function Expand-XcodeXipArchive {
param(
[Parameter(Mandatory)]
[string]$DownloadDirectory,
[Parameter(Mandatory)]
[string]$TargetPath
)
$xcodeXipPath = Get-ChildItem -Path $DownloadDirectory -Filter "Xcode-*.xip" | Select-Object -First 1
Write-Host "Extracting Xcode from '$xcodeXipPath'"
Push-Location $DownloadDirectory
if(Test-CommandExists 'unxip') {
Invoke-ValidateCommand "unxip $xcodeXipPath"
} else {
Invoke-ValidateCommand "xip -x $xcodeXipPath"
}
Pop-Location
if (Test-Path "$DownloadDirectory/Xcode-beta.app") {
Write-Host "Renaming Xcode-beta.app to Xcode.app"
Rename-Item -Path "$DownloadDirectory/Xcode-beta.app" -NewName "Xcode.app"
}
if (-not (Test-Path "$DownloadDirectory/Xcode.app")) {
throw "XIP archive '$xcodeXipPath' doesn't contain 'Xcode.app'"
}
Write-Host "Moving '$DownloadDirectory/Xcode.app' to '$TargetPath'"
Move-Item -Path "$DownloadDirectory/Xcode.app" -Destination $TargetPath
}
function Confirm-XcodeIntegrity {
param(
[Parameter(Mandatory)]
[string]$Version
)
$XcodeRootPath = Get-XcodeRootPath -Version $Version
if (Test-XcodeStableRelease -XcodeRootPath $XcodeRootPath) {
Write-Host "Validating Xcode integrity for '$XcodeRootPath'..."
Invoke-ValidateCommand "spctl --assess --raw $XcodeRootPath"
}
}
function Approve-XcodeLicense {
param(
[Parameter(Mandatory)]
[string]$Version
)
$os = Get-OSVersion
$XcodeRootPath = Get-XcodeRootPath -Version $Version
Write-Host "Approving Xcode license for '$XcodeRootPath'..."
$xcodeBuildPath = Get-XcodeToolPath -XcodeRootPath $XcodeRootPath -ToolName "xcodebuild"
if ($os.IsVentura -or $os.IsSonoma) {
Invoke-ValidateCommand -Command "sudo $xcodeBuildPath -license accept" -Timeout 15
} else {
Invoke-ValidateCommand -Command "sudo $xcodeBuildPath -license accept"
}
}
function Install-XcodeAdditionalPackages {
param(
[Parameter(Mandatory)]
[string]$Version
)
Write-Host "Installing additional packages for Xcode $Version..."
$xcodeRootPath = Get-XcodeRootPath -Version $Version
$packages = Get-ChildItem -Path "$xcodeRootPath/Contents/Resources/Packages" -Filter "*.pkg" -File
$packages | ForEach-Object {
Invoke-ValidateCommand "sudo installer -pkg $($_.FullName) -target / -allowUntrusted"
}
}
function Invoke-XcodeRunFirstLaunch {
param(
[Parameter(Mandatory)]
[string]$Version
)
if ($Version.StartsWith("8") -or $Version.StartsWith("9")) {
return
}
Write-Host "Running 'runFirstLaunch' for Xcode $Version..."
$xcodeRootPath = Get-XcodeToolPath -Version $Version -ToolName "xcodebuild"
Invoke-ValidateCommand "sudo $xcodeRootPath -runFirstLaunch"
}
function Install-AdditionalSimulatorRuntimes {
param(
[Parameter(Mandatory)]
[string]$Version
)
Write-Host "Installing Simulator Runtimes for Xcode $Version ..."
$xcodebuildPath = Get-XcodeToolPath -Version $Version -ToolName "xcodebuild"
Invoke-ValidateCommand "$xcodebuildPath -downloadAllPlatforms" | Out-Null
}
function Build-XcodeSymlinks {
param(
[Parameter(Mandatory)]
[string]$Version,
[string[]]$Symlinks
)
$sourcePath = Get-XcodeRootPath -Version $Version
$Symlinks | Where-Object { $_ } | ForEach-Object {
$targetPath = Get-XcodeRootPath -Version $_
Write-Host "Creating symlink: '$targetPath' -> '$sourcePath'"
New-Item -Path $targetPath -ItemType SymbolicLink -Value $sourcePath | Out-Null
}
}
function Rebuild-XcodeLaunchServicesDb {
param(
[Parameter(Mandatory)]
[string]$Version
)
$xcodePath = Get-XcodeRootPath -Version $Version
$lsregister = '/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister'
Get-ChildItem -Recurse -Filter "*.app" $xcodePath | Foreach-Object { & $lsregister -f $_.FullName}
}
function Build-ProvisionatorSymlink {
param(
[Parameter(Mandatory)]
[string]$Version
)
$sourcePath = Get-XcodeRootPath -Version $Version
$versionInfo = Get-XcodeVersionInfo -XcodeRootPath $sourcePath
$targetVersion = [SemVer]::Parse($versionInfo.Version).ToString()
$targetPath = Get-XcodeRootPath -Version $targetVersion
if ($sourcePath -ne $targetPath) {
Write-Host "Creating symlink: '$targetPath' -> '$sourcePath'"
New-Item -Path $targetPath -ItemType SymbolicLink -Value $sourcePath | Out-Null
}
}
function Set-XcodeDeveloperDirEnvironmentVariables {
param(
[Parameter(Mandatory)]
[string[]]$XcodeList
)
$exactVersionsList = $XcodeList | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object {
$xcodeRootPath = Get-XcodeRootPath -Version $_
$xcodeVersionInfo = Get-XcodeVersionInfo -XcodeRootPath $xcodeRootPath
return @{
RootPath = $xcodeRootPath
Version = [SemVer]::Parse($xcodeVersionInfo.Version)
}
} | Sort-Object -Property Version -Descending
$majorVersions = $exactVersionsList.Version.Major | Select-Object -Unique
$majorVersions | ForEach-Object {
$majorVersion = $_
$latestXcodeVersion = $exactVersionsList | Where-Object { $_.Version.Major -eq $majorVersion } | Select-Object -First 1
$variableName = "XCODE_${_}_DEVELOPER_DIR"
$variableValue = "$($latestXcodeVersion.RootPath)/Contents/Developer"
Write-Host "Set ${variableName}=${variableValue}"
"export ${variableName}=${variableValue}" | Out-File "$env:HOME/.bashrc" -Append
}
}

View File

@@ -0,0 +1,49 @@
# This AppleScript confirms developers in security preferences via macOS UI.
# It uses after VirtualBox installation to add 'Oracle Inc' as identified developer.
# Steps:
# - Close security preferences pop-up (it can be open after VirtualBox installation)
# - Open System Preferences -> Security & Privacy -> General
# - Unlock security preferences with user password (button 'Click the lock to make changes')
# - Click 'Allow' or 'Details…' button to confirm developers
# - Click 'Not now' button on restarting pop-up
# - Close System Preferences
on run argv
set userpassword to item 1 of argv
set secpane to "Security & Privacy"
activate application "System Preferences"
delay 5
tell application "System Events"
tell process "System Preferences"
set frontmost to true
delay 2
click menu item secpane of menu "View" of menu bar 1
delay 5
click button 1 of window 1
delay 5
keystroke userpassword
delay 5
keystroke return
delay 5
click radio button "General" of tab group 1 of window 1
delay 5
if exists of UI element "Details…" of tab group 1 of window 1 then
click button "Details…" of tab group 1 of window 1
delay 5
keystroke return
delay 5
keystroke return
delay 5
end if
if exists of UI element "Allow" of tab group 1 of window 1 then
click button "Allow" of tab group 1 of window 1
delay 5
keystroke return
delay 5
end if
click button 5 of window 1
end tell
end tell
end run

View File

@@ -0,0 +1,5 @@
#!/bin/bash -e -o pipefail
source $HOME/.bashrc
pwsh -Command "Import-Module '$HOME/image-generation/helpers/Tests.Helpers.psm1' -DisableNameChecking
Invoke-PesterTests -TestFile \"$1\" -TestName \"$2\""

View File

@@ -0,0 +1,242 @@
#!/bin/bash -e -o pipefail
download_with_retries() {
# Due to restrictions of bash functions, positional arguments are used here.
# In case if you using latest argument NAME, you should also set value to all previous parameters.
# Example: download_with_retries $ANDROID_SDK_URL "." "android_sdk.zip"
local URL="$1"
local DEST="${2:-.}"
local NAME="${3:-${URL##*/}}"
local COMPRESSED="$4"
if [[ $COMPRESSED == "compressed" ]]; then
local COMMAND="curl $URL -4 -sL --compressed -o '$DEST/$NAME' -w '%{http_code}'"
else
local COMMAND="curl $URL -4 -sL -o '$DEST/$NAME' -w '%{http_code}'"
fi
# Save current errexit state and disable it to prevent unexpected exit on error
if echo $SHELLOPTS | grep '\(^\|:\)errexit\(:\|$\)' > /dev/null;
then
local ERR_EXIT_ENABLED=true
else
local ERR_EXIT_ENABLED=false
fi
set +e
echo "Downloading '$URL' to '${DEST}/${NAME}'..."
retries=20
interval=30
while [ $retries -gt 0 ]; do
((retries--))
test "$ERR_EXIT_ENABLED" = true && set +e
http_code=$(eval $COMMAND)
exit_code=$?
test "$ERR_EXIT_ENABLED" = true && set -e
if [ $http_code -eq 200 ] && [ $exit_code -eq 0 ]; then
echo "Download completed"
return 0
else
echo "Error — Either HTTP response code for '$URL' is wrong - '$http_code' or exit code is not 0 - '$exit_code'. Waiting $interval seconds before the next attempt, $retries attempts left"
sleep 30
fi
done
echo "Could not download $URL"
return 1
}
is_Arm64() {
[ "$(arch)" = "arm64" ]
}
is_Sonoma() {
[ "$OSTYPE" = "darwin23" ]
}
is_SonomaArm64() {
is_Sonoma && is_Arm64
}
is_SonomaX64() {
is_Sonoma && ! is_Arm64
}
is_Ventura() {
[ "$OSTYPE" = "darwin22" ]
}
is_VenturaArm64() {
is_Ventura && is_Arm64
}
is_VenturaX64() {
is_Ventura && ! is_Arm64
}
is_Monterey() {
[ "$OSTYPE" = "darwin21" ]
}
is_BigSur() {
[ "$OSTYPE" = "darwin20" ]
}
is_Veertu() {
[ -d "/Library/Application Support/Veertu" ]
}
get_toolset_path() {
echo "$HOME/image-generation/toolset.json"
}
get_toolset_value() {
local toolset_path=$(get_toolset_path)
local query=$1
echo "$(jq -r "$query" $toolset_path)"
}
verlte() {
sortedVersion=$(echo -e "$1\n$2" | sort -V | head -n1)
[ "$1" = "$sortedVersion" ]
}
brew_cask_install_ignoring_sha256() {
local TOOL_NAME=$1
CASK_DIR="$(brew --repo homebrew/cask)/Casks"
chmod a+w "$CASK_DIR/$TOOL_NAME.rb"
SHA=$(grep "sha256" "$CASK_DIR/$TOOL_NAME.rb" | awk '{print $2}')
sed -i '' "s/$SHA/:no_check/" "$CASK_DIR/$TOOL_NAME.rb"
brew install --cask $TOOL_NAME
pushd $CASK_DIR
git checkout HEAD -- "$TOOL_NAME.rb"
popd
}
get_brew_os_keyword() {
if is_BigSur; then
echo "big_sur"
elif is_Monterey; then
echo "monterey"
elif is_Ventura; then
echo "ventura"
elif is_Sonoma; then
echo "sonoma"
else
echo "null"
fi
}
# brew provides package bottles for different macOS versions
# The 'brew install' command will fail if a package bottle does not exist
# Use the '--build-from-source' option to build from source in this case
brew_smart_install() {
local tool_name=$1
echo "Downloading $tool_name..."
# get deps & cache em
failed=true
for i in {1..10}; do
brew deps $tool_name > /tmp/$tool_name && failed=false || sleep 60
[ "$failed" = false ] && break
done
if [ "$failed" = true ]; then
echo "Failed: brew deps $tool_name"
exit 1;
fi
for dep in $(cat /tmp/$tool_name) $tool_name; do
failed=true
for i in {1..10}; do
brew --cache $dep >/dev/null && failed=false || sleep 60
[ "$failed" = false ] && break
done
if [ "$failed" = true ]; then
echo "Failed: brew --cache $dep"
exit 1;
fi
done
failed=true
for i in {1..10}; do
brew install $tool_name && failed=false || sleep 60
[ "$failed" = false ] && break
done
if [ "$failed" = true ]; then
echo "Failed: brew install $tool_name"
exit 1;
fi
}
configure_system_tccdb () {
local values=$1
local dbPath="/Library/Application Support/com.apple.TCC/TCC.db"
local sqlQuery="INSERT OR IGNORE INTO access VALUES($values);"
sudo sqlite3 "$dbPath" "$sqlQuery"
}
configure_user_tccdb () {
local values=$1
local dbPath="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
local sqlQuery="INSERT OR IGNORE INTO access VALUES($values);"
sqlite3 "$dbPath" "$sqlQuery"
}
get_github_package_download_url() {
local REPO_ORG=$1
local FILTER=$2
local VERSION=$3
local API_PAT=$4
local SEARCH_IN_COUNT="100"
[ -n "$API_PAT" ] && authString=(-H "Authorization: token ${API_PAT}")
failed=true
for i in {1..10}; do
curl "${authString[@]}" -fsSL "https://api.github.com/repos/${REPO_ORG}/releases?per_page=${SEARCH_IN_COUNT}" >/tmp/get_github_package_download_url.json && failed=false || sleep 60
[ "$failed" = false ] && break
done
if [ "$failed" = true ]; then
echo "Failed: get_github_package_download_url"
exit 1;
fi
json=$(cat /tmp/get_github_package_download_url.json)
if [[ "$VERSION" == "latest" ]]; then
tagName=$(echo $json | jq -r '.[] | select((.prerelease==false) and (.assets | length > 0)).tag_name' | sort --unique --version-sort | egrep -v ".*-[a-z]" | tail -1)
else
tagName=$(echo $json | jq -r '.[] | select(.prerelease==false).tag_name' | sort --unique --version-sort | egrep -v ".*-[a-z]" | egrep "\w*${VERSION}" | tail -1)
fi
downloadUrl=$(echo $json | jq -r ".[] | select(.tag_name==\"${tagName}\").assets[].browser_download_url | select(${FILTER})" | head -n 1)
if [ -z "$downloadUrl" ]; then
echo "Failed to parse a download url for the '${tagName}' tag using '${FILTER}' filter"
exit 1
fi
echo $downloadUrl
}
# Close all finder windows because they can interfere with UI tests
close_finder_window() {
osascript -e 'tell application "Finder" to close windows'
}
get_arch() {
arch=$(arch)
if [[ $arch == "arm64" ]]; then
echo "arm64"
else
echo "x64"
fi
}

View File

@@ -0,0 +1,239 @@
#!/bin/bash -e -o pipefail
source ~/utils/utils.sh
# Xamarin can clean their SDKs while updating to newer versions,
# so we should be able to detect it during image generation
downloadAndInstallPKG() {
local PKG_URL=$1
local PKG_NAME=${PKG_URL##*/}
download_with_retries $PKG_URL
echo "Installing $PKG_NAME..."
sudo installer -pkg "$TMPMOUNT/$PKG_NAME" -target /
}
buildVSMacDownloadUrl() {
echo "https://dl.xamarin.com/VsMac/VisualStudioForMac-${1}.dmg"
}
buildMonoDownloadUrl() {
echo "https://dl.xamarin.com/MonoFrameworkMDK/Macx86/MonoFramework-MDK-${1}.macos10.xamarin.universal.pkg"
}
buildXamariniIOSDownloadUrl() {
echo "https://dl.xamarin.com/MonoTouch/Mac/xamarin.ios-${1}.pkg"
}
buildXamarinMacDownloadUrl() {
echo "https://dl.xamarin.com/XamarinforMac/Mac/xamarin.mac-${1}.pkg"
}
buildXamarinAndroidDownloadUrl() {
echo "https://dl.xamarin.com/MonoforAndroid/Mac/xamarin.android-${1}.pkg"
}
installMono() {
local VERSION=$1
echo "Installing Mono ${VERSION}..."
local MONO_FOLDER_NAME=$(echo $VERSION | cut -d. -f 1,2,3)
local SHORT_VERSION=$(echo $VERSION | cut -d. -f 1,2)
local PKG_URL=$(buildMonoDownloadUrl $VERSION)
downloadAndInstallPKG $PKG_URL
echo "Installing nunit3-console for Mono "$VERSION
installNunitConsole $MONO_FOLDER_NAME
echo "Creating short symlink '${SHORT_VERSION}'"
sudo ln -s ${MONO_VERSIONS_PATH}/${MONO_FOLDER_NAME} ${MONO_VERSIONS_PATH}/${SHORT_VERSION}
echo "Move to backup folder"
sudo mv -v $MONO_VERSIONS_PATH/* $TMPMOUNT_FRAMEWORKS/mono/
}
installXamarinIOS() {
local VERSION=$1
echo "Installing Xamarin.iOS ${VERSION}..."
local SHORT_VERSION=$(echo $VERSION | cut -d. -f 1,2)
local PKG_URL=$(buildXamariniIOSDownloadUrl $VERSION)
downloadAndInstallPKG $PKG_URL
echo "Creating short symlink '${SHORT_VERSION}'"
sudo ln -s ${IOS_VERSIONS_PATH}/${VERSION} ${IOS_VERSIONS_PATH}/${SHORT_VERSION}
echo "Move to backup folder"
sudo mv -v $IOS_VERSIONS_PATH/* $TMPMOUNT_FRAMEWORKS/ios/
}
installXamarinMac() {
local VERSION=$1
echo "Installing Xamarin.Mac ${VERSION}..."
local SHORT_VERSION=$(echo $VERSION | cut -d. -f 1,2)
local PKG_URL=$(buildXamarinMacDownloadUrl $VERSION)
downloadAndInstallPKG $PKG_URL
echo "Creating short symlink '${SHORT_VERSION}'"
sudo ln -s ${MAC_VERSIONS_PATH}/${VERSION} ${MAC_VERSIONS_PATH}/${SHORT_VERSION}
echo "Move to backup folder"
sudo mv -v $MAC_VERSIONS_PATH/* $TMPMOUNT_FRAMEWORKS/mac/
}
installXamarinAndroid() {
local VERSION=$1
echo "Installing Xamarin.Android ${VERSION}..."
local SHORT_VERSION=$(echo $VERSION | cut -d. -f 1,2)
local PKG_URL=$(buildXamarinAndroidDownloadUrl $VERSION)
downloadAndInstallPKG $PKG_URL
if [ "$VERSION" == "9.4.1.0" ]; then
# Fix symlinks for broken Xamarin.Android
fixXamarinAndroidSymlinksInLibDir $VERSION
fi
echo "Creating short symlink '${SHORT_VERSION}'"
sudo ln -s ${ANDROID_VERSIONS_PATH}/${VERSION} ${ANDROID_VERSIONS_PATH}/${SHORT_VERSION}
echo "Move to backup folder"
sudo mv -v $ANDROID_VERSIONS_PATH/* $TMPMOUNT_FRAMEWORKS/android/
}
createBundle() {
local SYMLINK=$1
local MONO_SDK=$2
local IOS_SDK=$3
local MAC_SDK=$4
local ANDROID_SDK=$5
echo "Creating bundle '$SYMLINK' (Mono $MONO_SDK; iOS $IOS_SDK; Mac $MAC_SDK; Android $ANDROID_SDK"
deleteSymlink ${SYMLINK}
sudo ln -s ${MONO_VERSIONS_PATH}/${MONO_SDK} ${MONO_VERSIONS_PATH}/${SYMLINK}
sudo ln -s ${IOS_VERSIONS_PATH}/${IOS_SDK} ${IOS_VERSIONS_PATH}/${SYMLINK}
sudo ln -s ${MAC_VERSIONS_PATH}/${MAC_SDK} ${MAC_VERSIONS_PATH}/${SYMLINK}
sudo ln -s ${ANDROID_VERSIONS_PATH}/${ANDROID_SDK} ${ANDROID_VERSIONS_PATH}/${SYMLINK}
}
createBundleLink() {
local SOURCE=$1
local TARGET=$2
echo "Creating bundle symlink '$SOURCE' -> '$TARGET'"
deleteSymlink ${TARGET}
sudo ln -s ${MONO_VERSIONS_PATH}/$SOURCE ${MONO_VERSIONS_PATH}/$TARGET
sudo ln -s ${IOS_VERSIONS_PATH}/$SOURCE ${IOS_VERSIONS_PATH}/$TARGET
sudo ln -s ${MAC_VERSIONS_PATH}/$SOURCE ${MAC_VERSIONS_PATH}/$TARGET
sudo ln -s ${ANDROID_VERSIONS_PATH}/$SOURCE ${ANDROID_VERSIONS_PATH}/$TARGET
}
# https://github.com/xamarin/xamarin-android/issues/3457
# Recreate missing symlinks in lib for new Xamarin.Android package
# Symlink path /Library/Frameworks/Xamarin.Android.framework/Libraries
# xbuild -> xamarin.android/xbuild
# xbuild-frameworks -> xamarin.android/xbuild-frameworks
fixXamarinAndroidSymlinksInLibDir() {
local XAMARIN_ANDROID_VERSION=$1
local XAMARIN_ANDROID_LIB_PATH="${ANDROID_VERSIONS_PATH}/${XAMARIN_ANDROID_VERSION}/lib"
if [ -d "${XAMARIN_ANDROID_LIB_PATH}" ]; then
pushd "${XAMARIN_ANDROID_LIB_PATH}" > /dev/null
local XAMARIN_ANDROID_XBUILD_DIR="${XAMARIN_ANDROID_LIB_PATH}/xbuild"
if [ ! -d "${XAMARIN_ANDROID_XBUILD_DIR}" ]; then
echo "${XAMARIN_ANDROID_XBUILD_DIR}"
sudo ln -sf xamarin.android/xbuild xbuild
fi
local XAMARIN_ANDROID_XBUILD_FRAMEWORKS_DIR="${XAMARIN_ANDROID_LIB_PATH}/xbuild-frameworks"
if [ ! -d "${XAMARIN_ANDROID_XBUILD_FRAMEWORKS_DIR}" ]; then
echo "${XAMARIN_ANDROID_XBUILD_FRAMEWORKS_DIR}"
sudo ln -sf xamarin.android/xbuild-frameworks xbuild-frameworks
fi
popd > /dev/null
fi
}
installNunitConsole() {
local MONO_VERSION=$1
cat <<EOF > ${TMPMOUNT}/${NUNIT3_CONSOLE_BIN}
#!/bin/bash -e -o pipefail
exec /Library/Frameworks/Mono.framework/Versions/${MONO_VERSION}/bin/mono --debug \$MONO_OPTIONS $NUNIT3_PATH/nunit3-console.exe "\$@"
EOF
sudo chmod +x ${TMPMOUNT}/${NUNIT3_CONSOLE_BIN}
sudo mv ${TMPMOUNT}/${NUNIT3_CONSOLE_BIN} ${MONO_VERSIONS_PATH}/${MONO_VERSION}/Commands/${NUNIT3_CONSOLE_BIN}
}
downloadNUnitConsole() {
echo "Downloading NUnit 3..."
local NUNIT3_LOCATION='https://github.com/nunit/nunit-console/releases/download/3.6.1/NUnit.Console-3.6.1.zip'
local NUNIT_PATH="/Library/Developer/nunit"
NUNIT3_PATH="$NUNIT_PATH/3.6.1"
pushd $TMPMOUNT
sudo mkdir -p $NUNIT3_PATH
download_with_retries $NUNIT3_LOCATION "." "nunit3.zip"
echo "Installing NUnit 3..."
sudo unzip nunit3.zip -d $NUNIT3_PATH
NUNIT3_CONSOLE_BIN=nunit3-console
popd
}
installNuget() {
local MONO_VERSION=$1
local NUGET_VERSION=$2
local NUGET_URL="https://dist.nuget.org/win-x86-commandline/v${NUGET_VERSION}/nuget.exe"
echo "Installing nuget $NUGET_VERSION for Mono $MONO_VERSION"
cd ${MONO_VERSIONS_PATH}/${MONO_VERSION}/lib/mono/nuget
sudo mv nuget.exe nuget_old.exe
pushd $TMPMOUNT
download_with_retries $NUGET_URL "." "nuget.exe"
sudo chmod a+x nuget.exe
sudo mv nuget.exe ${MONO_VERSIONS_PATH}/${MONO_VERSION}/lib/mono/nuget
popd
}
createUWPShim() {
echo "Creating UWP Shim to hack UWP build failure..."
cat <<EOF > ${TMPMOUNT}/Microsoft.Windows.UI.Xaml.CSharp.Targets
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name = "Build"/>
<Target Name = "Rebuild"/>
</Project>
EOF
local UWPTARGET_PATH=/Library/Frameworks/Mono.framework/External/xbuild/Microsoft/WindowsXaml
sudo mkdir -p $UWPTARGET_PATH/v11.0/
sudo cp ${TMPMOUNT}/Microsoft.Windows.UI.Xaml.CSharp.Targets $UWPTARGET_PATH/v11.0/
sudo mkdir -p $UWPTARGET_PATH/v12.0/
sudo cp ${TMPMOUNT}/Microsoft.Windows.UI.Xaml.CSharp.Targets $UWPTARGET_PATH/v12.0/
sudo mkdir -p $UWPTARGET_PATH/v14.0/
sudo cp ${TMPMOUNT}/Microsoft.Windows.UI.Xaml.CSharp.Targets $UWPTARGET_PATH/v14.0/
sudo mkdir -p $UWPTARGET_PATH/v15.0/
sudo cp ${TMPMOUNT}/Microsoft.Windows.UI.Xaml.CSharp.Targets $UWPTARGET_PATH/v15.0/
sudo mkdir -p $UWPTARGET_PATH/v16.0/
sudo cp ${TMPMOUNT}/Microsoft.Windows.UI.Xaml.CSharp.Targets $UWPTARGET_PATH/v16.0/
}
createBackupFolders() {
mkdir -p $TMPMOUNT_FRAMEWORKS/mono
mkdir -p $TMPMOUNT_FRAMEWORKS/ios
mkdir -p $TMPMOUNT_FRAMEWORKS/mac
mkdir -p $TMPMOUNT_FRAMEWORKS/android
}
deleteSymlink() {
sudo rm -f ${MONO_VERSIONS_PATH}/${1}
sudo rm -f ${IOS_VERSIONS_PATH}/${1}
sudo rm -f ${MAC_VERSIONS_PATH}/${1}
sudo rm -f ${ANDROID_VERSIONS_PATH}/${1}
}