Merge pull request #1977 from maxim-lobanov/v-malob/xcode

Rework Xcode installation to use PowerShell and resolve latest version automatically
This commit is contained in:
Maxim Lobanov
2020-11-18 13:46:12 +03:00
committed by GitHub
22 changed files with 453 additions and 319 deletions

View File

@@ -11,4 +11,4 @@ $env:GIT_REDIRECT_STDERR = '2>&1'
git clone $RepoUrl . -b $RepoBranch --single-branch --depth 1 git clone $RepoUrl . -b $RepoBranch --single-branch --depth 1
Write-Host "Latest commit:" Write-Host "Latest commit:"
git log --pretty=format:"Date: %cd; Commit: %H - %s; Author: %an <%ae>" -1 git --no-pager log --pretty=format:"Date: %cd; Commit: %H - %s; Author: %an <%ae>" -1

View File

@@ -85,6 +85,19 @@ function Invoke-RestMethodWithRetry {
Invoke-RestMethod $Url -MaximumRetryCount 10 -RetryIntervalSec 30 Invoke-RestMethod $Url -MaximumRetryCount 10 -RetryIntervalSec 30
} }
function Invoke-ValidateCommand {
param(
[Parameter(Mandatory)]
[string]$Command
)
$output = Invoke-Expression -Command $Command
if ($LASTEXITCODE -ne 0) {
throw "Command '$Command' has finished with exit code $LASTEXITCODE"
}
return $output
}
function Start-DownloadWithRetry function Start-DownloadWithRetry
{ {
Param Param

View File

@@ -8,9 +8,7 @@ function Get-XcodeRootPath {
} }
function Get-DefaultXcodeRootPath { function Get-DefaultXcodeRootPath {
$defaultXcodePath = "/Applications/Xcode.app" return (Get-Item -Path "/Applications/Xcode.app").Target
$defaultXcodeItem = Get-Item -Path $defaultXcodePath
return $defaultXcodeItem.Target
} }
function Get-XcodeToolPath { function Get-XcodeToolPath {
@@ -29,6 +27,21 @@ function Get-XcodeToolPath {
return Join-Path $XcodeRootPath "Contents/Developer/usr/bin" $ToolName 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 { function Switch-Xcode {
param ( param (
[Parameter(ParameterSetName = 'Version')] [Parameter(ParameterSetName = 'Version')]

View File

@@ -0,0 +1,212 @@
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
Invoke-DownloadXcodeArchive -Version $Version
Expand-XcodeXipArchive -DownloadDirectory $xcodeDownloadDirectory -TargetPath $xcodeTargetPath
Get-ChildItem $xcodeDownloadDirectory | Remove-Item -Force
}
function Invoke-DownloadXcodeArchive {
param(
[Parameter(Mandatory)]
[string]$Version
)
$resolvedVersion = Resolve-ExactXcodeVersion -Version $Version
if (-not $resolvedVersion) {
throw "Version '$Version' can't be matched to any available version"
}
# TO-DO: Consider replacing of xcversion with own implementation
Write-Host "Downloading Xcode $resolvedVersion"
Invoke-ValidateCommand "xcversion install '$resolvedVersion' --no-install"
}
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 = & xcversion 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
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
)
$XcodeRootPath = Get-XcodeRootPath -Version $Version
Write-Host "Approving Xcode license for '$XcodeRootPath'..."
$xcodeBuildPath = Get-XcodeToolPath -XcodeRootPath $XcodeRootPath -ToolName "xcodebuild"
Invoke-ValidateCommand "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 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 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

@@ -1,10 +1,14 @@
#!/bin/bash -e -o pipefail #!/bin/bash -e -o pipefail
echo "Enabling safari driver..."
# https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari # https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari
# Safaris executable is located at /usr/bin/safaridriver # Safaris executable is located at /usr/bin/safaridriver
# Configure Safari to Enable WebDriver Support # Configure Safari to Enable WebDriver Support
sudo safaridriver --enable sudo safaridriver --enable
echo "Enabling developer mode..."
sudo /usr/sbin/DevToolsSecurity --enable
# Turn off hibernation and get rid of the sleepimage # Turn off hibernation and get rid of the sleepimage
sudo pmset hibernatemode 0 sudo pmset hibernatemode 0
sudo rm -f /var/vm/sleepimage sudo rm -f /var/vm/sleepimage

View File

@@ -9,7 +9,7 @@ XAMARIN_MAC_VERSIONS=($(get_toolset_value '.xamarin."mac-versions" | reverse | .
XAMARIN_ANDROID_VERSIONS=($(get_toolset_value '.xamarin."android-versions" | reverse | .[]')) XAMARIN_ANDROID_VERSIONS=($(get_toolset_value '.xamarin."android-versions" | reverse | .[]'))
LATEST_SDK_SYMLINK=$(get_toolset_value '.xamarin.bundles[0].symlink') LATEST_SDK_SYMLINK=$(get_toolset_value '.xamarin.bundles[0].symlink')
CURRENT_SDK_SYMLINK=$(get_toolset_value '.xamarin."bundle-default"') CURRENT_SDK_SYMLINK=$(get_toolset_value '.xamarin."bundle-default"')
DEFAULT_XCODE_VERSION=$(get_default_xcode_from_toolset) DEFAULT_XCODE_VERSION=$(get_toolset_value '.xcode.default')
if [ "$CURRENT_SDK_SYMLINK" == "latest" ]; then if [ "$CURRENT_SDK_SYMLINK" == "latest" ]; then
CURRENT_SDK_SYMLINK=$LATEST_SDK_SYMLINK CURRENT_SDK_SYMLINK=$LATEST_SDK_SYMLINK

View File

@@ -1,8 +1,8 @@
#!/bin/bash -e -o pipefail #!/bin/bash -e -o pipefail
source ~/utils/utils.sh source ~/utils/utils.sh
XCODE_LIST=($(get_xcode_list_from_toolset)) XCODE_LIST=($(get_toolset_value '.xcode.versions | reverse | .[].link'))
DEFAULT_XCODE_VERSION=$(get_default_xcode_from_toolset) DEFAULT_XCODE_VERSION=$(get_toolset_value '.xcode.default')
# https://github.com/microsoft/appcenter/issues/847 # https://github.com/microsoft/appcenter/issues/847
# Assets.xcassets : error : CoreData: error: (6922) I/O error for database # Assets.xcassets : error : CoreData: error: (6922) I/O error for database
@@ -15,11 +15,6 @@ do
#add sleep to let CoreSimulatorService to exit #add sleep to let CoreSimulatorService to exit
sleep 3 sleep 3
# Version 12.2_beta installed into 12.2 directory and 12.1_GM_seed in 12.1
pattern="[0-9]{1,2}.*_"
if [[ $XCODE_VERSION =~ $pattern ]] ; then
XCODE_VERSION=$(echo $XCODE_VERSION | cut -d"_" -f 1)
fi
# Select xcode version by default # Select xcode version by default
sudo xcode-select -s "/Applications/Xcode_${XCODE_VERSION}.app/Contents/Developer" sudo xcode-select -s "/Applications/Xcode_${XCODE_VERSION}.app/Contents/Developer"

View File

@@ -1,97 +0,0 @@
#!/bin/bash -e -o pipefail
# The script currently requires 2 external variables to be set: XCODE_INSTALL_USER
# and XCODE_INSTALL_PASSWORD, in order to access the Apple Developer Center
source ~/utils/utils.sh
source ~/utils/xcode-utils.sh
if [ -z $XCODE_INSTALL_USER ] || [ -z $XCODE_INSTALL_PASSWORD ]; then
echo "Required environment variables XCODE_INSTALL_USER and XCODE_INSTALL_PASSWORD are not set"
exit 1
fi
XCODE_LIST=($(get_xcode_list_from_toolset))
LATEST_XCODE_VERSION=$(get_latest_xcode_from_toolset)
DEFAULT_XCODE_VERSION=$(get_default_xcode_from_toolset)
WORK_DIR="${HOME}/Library/Caches/XcodeInstall"
# Update the list of available versions
xcversion update
for XCODE_VERSION in "${XCODE_LIST[@]}"
do
VERSION_TO_INSTALL="$(getXcodeVersionToInstall "$XCODE_VERSION")"
if [[ -z "$VERSION_TO_INSTALL" ]]; then
echo "No versions were found matching $XCODE_VERSION"
exit 1
fi
echo "Downloading Xcode $VERSION_TO_INSTALL ..."
xcversion install "$VERSION_TO_INSTALL" --no-install
echo "Extracting Xcode.app ($VERSION_TO_INSTALL) to ${WORK_DIR} ..."
extractXcodeXip $WORK_DIR "$VERSION_TO_INSTALL"
XCODE_VERSION=$(echo $XCODE_VERSION | cut -d"_" -f 1)
echo "Checking if unpacked Xcode ${XCODE_VERSION} is valid"
validateXcodeIntegrity "$WORK_DIR"
# Move Xcode to /Applications
mv -f "${WORK_DIR}/Xcode.app" "/Applications/Xcode_${XCODE_VERSION}.app"
echo "Accepting license for Xcode ${XCODE_VERSION}..."
approveLicense $XCODE_VERSION
# Creating a symlink for all Xcode 10* and Xcode 9.3, 9.4 to stay backwards compatible with consumers of the Xcode beta version
createBetaSymlink $XCODE_VERSION
createXamarinProvisionatorSymlink "$XCODE_VERSION"
find $WORK_DIR -mindepth 1 -delete
done
echo "Configuring 'runFirstLaunch' for all Xcode versions"
if is_Less_Catalina; then
echo "Install additional packages for Xcode ${LATEST_XCODE_VERSION}"
installAdditionalPackages $LATEST_XCODE_VERSION
fi
for XCODE_VERSION in "${XCODE_LIST[@]}"
do
if [[ $XCODE_VERSION == 8* || $XCODE_VERSION == 9* ]]; then
continue
fi
XCODE_VERSION=$(echo $XCODE_VERSION | cut -d"_" -f 1)
echo "Running 'runFirstLaunch' for Xcode ${XCODE_VERSION}..."
runFirstLaunch $XCODE_VERSION
done
echo "Running 'runFirstLaunch' for default Xcode ${DEFAULT_XCODE_VERSION}..."
runFirstLaunch $DEFAULT_XCODE_VERSION
# Create symlinks for Xcode on Catalina: 11.3 -> 11.3.1, 11.2 -> 11.2.1
if is_Catalina; then
ln -sf /Applications/Xcode_11.2.1.app /Applications/Xcode_11.2.app
ln -sf /Applications/Xcode_11.3.1.app /Applications/Xcode_11.3.app
ln -sf /Applications/Xcode_11.4.1.app /Applications/Xcode_11.4.app
fi
echo "Setting Xcode ${DEFAULT_XCODE_VERSION} as default"
sudo xcode-select -s "/Applications/Xcode_${DEFAULT_XCODE_VERSION}.app/Contents/Developer"
echo "Adding symlink '/Applications/Xcode_${DEFAULT_XCODE_VERSION}.app' -> '/Applications/Xcode.app'"
ln -s "/Applications/Xcode_${DEFAULT_XCODE_VERSION}.app" "/Applications/Xcode.app"
echo "Enabling developer mode"
sudo /usr/sbin/DevToolsSecurity --enable
echo "Setting environment variables 'XCODE_<VERSION>_DEVELOPER_DIR'"
setXcodeDeveloperDirVariables
# Cleanup
echo "Doing cleanup. Emptying ${WORK_DIR}..."
rm -rf "$WORK_DIR"

View File

@@ -0,0 +1,44 @@
# The script currently requires 2 external variables to be set: XCODE_INSTALL_USER
# and XCODE_INSTALL_PASSWORD, in order to access the Apple Developer Center
$ErrorActionPreference = "Stop"
Import-Module "$env:HOME/image-generation/helpers/Common.Helpers.psm1"
Import-Module "$env:HOME/image-generation/helpers/Xcode.Installer.psm1"
if ([string]::IsNullOrEmpty($env:XCODE_INSTALL_USER) -or [string]::IsNullOrEmpty($env:XCODE_INSTALL_PASSWORD)) {
throw "Required environment variables XCODE_INSTALL_USER and XCODE_INSTALL_PASSWORD are not set"
}
$os = Get-OSVersion
$xcodeVersions = Get-ToolsetValue "xcode.versions"
$defaultXcode = Get-ToolsetValue "xcode.default"
[Array]::Reverse($xcodeVersions)
Write-Host "Installing Xcode versions..."
$xcodeVersions | ForEach-Object {
Install-XcodeVersion -Version $_.version -LinkTo $_.link
Confirm-XcodeIntegrity -Version $_.link
Approve-XcodeLicense -Version $_.link
}
Write-Host "Configuring Xcode versions..."
if ($os.IsLessThanCatalina) {
$latestXcodeVersion = $xcodeVersions | Select-Object -Last 1 -ExpandProperty link
Install-XcodeAdditionalPackages -Version $latestXcodeVersion
}
$xcodeVersions | ForEach-Object { Invoke-XcodeRunFirstLaunch -Version $_.link }
Invoke-XcodeRunFirstLaunch -Version $defaultXcode
Write-Host "Configuring Xcode symlinks..."
$xcodeVersions | ForEach-Object {
Build-XcodeSymlinks -Version $_.link -Symlinks $_.symlinks
Build-ProvisionatorSymlink -Version $_.link
}
Write-Host "Setting default Xcode to $defaultXcode"
Switch-Xcode -Version $defaultXcode
New-Item -Path "/Applications/Xcode.app" -ItemType SymbolicLink -Value (Get-XcodeRootPath -Version $defaultXcode) | Out-Null
Write-Host "Setting environment variables 'XCODE_<VERSION>_DEVELOPER_DIR'"
Set-XcodeDeveloperDirEnvironmentVariables -XcodeList $xcodeVersions.link

View File

@@ -92,18 +92,6 @@ get_toolset_value() {
echo "$(jq -r "$query" $toolset_path)" echo "$(jq -r "$query" $toolset_path)"
} }
get_xcode_list_from_toolset() {
echo $(get_toolset_value '.xcode.versions | reverse | .[]')
}
get_latest_xcode_from_toolset() {
echo $(get_toolset_value '.xcode.versions[0]')
}
get_default_xcode_from_toolset() {
echo $(get_toolset_value '.xcode.default')
}
verlte() { verlte() {
sortedVersion=$(echo -e "$1\n$2" | sort -V | head -n1) sortedVersion=$(echo -e "$1\n$2" | sort -V | head -n1)
[ "$1" = "$sortedVersion" ] [ "$1" = "$sortedVersion" ]

View File

@@ -1,92 +0,0 @@
#!/bin/bash -e -o pipefail
createXamarinProvisionatorSymlink() {
local XCODE_VERSION="$1"
local FULL_VERSION=$(echo "${XCODE_VERSION}.0.0" | cut -d'.' -f 1,2,3)
# temporary trick for 12.0.1
if [[ $XCODE_VERSION == "12" ]]; then
FULL_VERSION="12.0.1"
fi
if [ $FULL_VERSION != $XCODE_VERSION ]; then
ln -sf "/Applications/Xcode_${XCODE_VERSION}.app" "/Applications/Xcode_${FULL_VERSION}.app"
fi
}
getXcodeVersionToInstall() {
local XCODE_VERSION="$1"
if [[ $XCODE_VERSION == "12" ]]; then
echo "12.0.1"
elif [[ ! $XCODE_VERSION =~ "_beta" ]]; then
echo "${XCODE_VERSION//_/ }"
else
local XCODE_BETA="${XCODE_VERSION/_/ }"
echo "$(xcversion list | sort -r | grep -m 1 "$XCODE_BETA")"
fi
}
validateXcodeIntegrity() {
local WORKING_DIR="$1"
local XCODE_VERSION="$2"
if echo $XCODE_VERSION | grep "beta"; then
return 0
fi
spctl --assess --raw "${WORKING_DIR}/Xcode.app"
}
approveLicense() {
local XCODE_VERSION="$1"
sudo "/Applications/Xcode_${XCODE_VERSION}.app/Contents/Developer/usr/bin/xcodebuild" -license accept
}
installAdditionalPackages() {
# should be called only for old High Sierra and Mojave
local XCODE_VERSION="$1"
find /Applications/Xcode_${XCODE_VERSION}.app/Contents/Resources/Packages/ -name '*.pkg' | xargs -I '{}' sudo installer -pkg '{}' -target / -allowUntrusted
}
runFirstLaunch() {
local XCODE_VERSION="$1"
sudo "/Applications/Xcode_${XCODE_VERSION}.app/Contents/Developer/usr/bin/xcodebuild" -runFirstLaunch
}
setXcodeDeveloperDirVariables() {
stable_xcode_versions=$(get_xcode_list_from_toolset | tr " " "\n" | grep -v "beta" | grep -v "Release_Candidate")
major_versions=($(echo ${stable_xcode_versions[@]} | tr " " "\n" | cut -d '.' -f 1 | uniq))
for MAJOR_VERSION in "${major_versions[@]}"
do
LATEST_STABLE_VERSION=$(echo "${stable_xcode_versions[*]}" | grep "${MAJOR_VERSION}" | tail -n 1)
LATEST_STABLE_VERSION=$(echo $LATEST_STABLE_VERSION | cut -d"_" -f 1)
echo "export XCODE_${MAJOR_VERSION}_DEVELOPER_DIR=/Applications/Xcode_${LATEST_STABLE_VERSION}.app/Contents/Developer" >> "$HOME/.bashrc"
done
}
extractXcodeXip() {
local WORKING_DIR="$1"
local XCODE_VERSION="$2"
XCODE_XIP="${WORKING_DIR}/Xcode_${XCODE_VERSION// /_}.xip"
pushd $WORKING_DIR
xip -x "${XCODE_XIP}"
popd
if [[ -d "${WORKING_DIR}/Xcode-beta.app" ]]; then
mv -f "${WORKING_DIR}/Xcode-beta.app" "${WORKING_DIR}/Xcode.app"
fi
if [[ ! -d "${WORKING_DIR}/Xcode.app" ]]; then
echo "'Xcode.app' doesn't exist after Xcode XIP extraction"
exit 1
fi
}
createBetaSymlink() {
local XCODE_VERSION=$1
if [[ $XCODE_VERSION =~ 1[01].* ]] || [[ $XCODE_VERSION == "12" ]]; then
ln -sf "/Applications/Xcode_${XCODE_VERSION}.app" "/Applications/Xcode_${XCODE_VERSION}_beta.app"
fi
}

View File

@@ -1,4 +1,5 @@
Import-Module "$PSScriptRoot/../helpers/Common.Helpers.psm1" Import-Module "$PSScriptRoot/../helpers/Common.Helpers.psm1"
Import-Module "$PSScriptRoot/../helpers/Xcode.Helpers.psm1"
$os = Get-OSVersion $os = Get-OSVersion
@@ -7,19 +8,16 @@ function Get-XcodePaths {
return $xcodePaths | Select-Object -ExpandProperty Fullname return $xcodePaths | Select-Object -ExpandProperty Fullname
} }
function Get-XcodeVersionInfo {
[string]$output = Invoke-Expression "xcodebuild -version"
$versionOutputParts = $output.Split(" ")
return @{
Version = [System.Version]::Parse($versionOutputParts[1])
Build = $versionOutputParts[4]
}
}
function Get-XcodeSDKList { function Get-XcodeSDKList {
$versionInfo = Get-XcodeVersionInfo param(
[Parameter(Mandatory)]
[string]$XcodeRootPath
)
$versionInfo = Get-XcodeVersionInfo -XcodeRootPath $XcodeRootPath
$xcodebuildPath = Get-XcodeToolPath -XcodeRootPath $XcodeRootPath -ToolName "xcodebuild"
if ($versionInfo.Version -le [System.Version]::Parse("9.4.1")) { if ($versionInfo.Version -le [System.Version]::Parse("9.4.1")) {
$output = Invoke-Expression "xcodebuild -showsdks" $output = Invoke-Expression "$xcodebuildPath -showsdks"
$sdkList = $output | Where-Object { $_ -Match "-sdk" } $sdkList = $output | Where-Object { $_ -Match "-sdk" }
return $sdkList | ForEach-Object { return $sdkList | ForEach-Object {
@@ -31,7 +29,7 @@ function Get-XcodeSDKList {
} }
} }
[string]$output = Invoke-Expression "xcodebuild -showsdks -json" [string]$output = Invoke-Expression "$xcodebuildPath -showsdks -json"
return $output | ConvertFrom-Json return $output | ConvertFrom-Json
} }
@@ -43,14 +41,14 @@ function Get-XcodeInfoList {
$xcodeRootPath = $_ $xcodeRootPath = $_
Switch-Xcode -XcodeRootPath $xcodeRootPath Switch-Xcode -XcodeRootPath $xcodeRootPath
$versionInfo = Get-XcodeVersionInfo $versionInfo = Get-XcodeVersionInfo -XcodeRootPath $xcodeRootPath
$versionInfo.Path = $xcodeRootPath $versionInfo.Path = $xcodeRootPath
$versionInfo.IsDefault = ($xcodeRootPath -eq $defaultXcodeRootPath) $versionInfo.IsDefault = ($xcodeRootPath -eq $defaultXcodeRootPath)
$versionInfo.IsStable = Test-XcodeStableRelease -XcodeRootPath $xcodeRootPath $versionInfo.IsStable = Test-XcodeStableRelease -XcodeRootPath $xcodeRootPath
$xcodeInfo.Add($xcodeRootPath, [PSCustomObject] @{ $xcodeInfo.Add($xcodeRootPath, [PSCustomObject] @{
VersionInfo = $versionInfo VersionInfo = $versionInfo
SDKInfo = Get-XcodeSDKList SDKInfo = Get-XcodeSDKList -XcodeRootPath $xcodeRootPath
SimulatorsInfo = Get-XcodeSimulatorsInfo SimulatorsInfo = Get-XcodeSimulatorsInfo
}) })
} }
@@ -101,7 +99,7 @@ function Build-XcodeTable {
} }
} }
function Get-XcodeDevicesList { function Build-XcodeDevicesList {
param ( param (
[Parameter(Mandatory)][object] $XcodeInfo, [Parameter(Mandatory)][object] $XcodeInfo,
[Parameter(Mandatory)][object] $Runtime [Parameter(Mandatory)][object] $Runtime
@@ -190,7 +188,7 @@ function Build-XcodeSimulatorsTable {
$xcodeInfo.Values | ForEach-Object { $xcodeInfo.Values | ForEach-Object {
$runtimeFound = $_.SimulatorsInfo.runtimes | Where-Object { $_.identifier -eq $runtime.identifier } | Select-Object -First 1 $runtimeFound = $_.SimulatorsInfo.runtimes | Where-Object { $_.identifier -eq $runtime.identifier } | Select-Object -First 1
if ($runtimeFound) { if ($runtimeFound) {
$devicesToAdd = Get-XcodeDevicesList -XcodeInfo $_ -Runtime $runtimeFound $devicesToAdd = Build-XcodeDevicesList -XcodeInfo $_ -Runtime $runtimeFound
$runtimeDevices += $devicesToAdd | Select-Object -ExpandProperty name $runtimeDevices += $devicesToAdd | Select-Object -ExpandProperty name
$xcodeList += $_.VersionInfo.Version $xcodeList += $_.VersionInfo.Version
} }

View File

@@ -147,12 +147,8 @@
}, },
{ {
"type": "shell", "type": "shell",
"execute_command": "chmod +x {{ .Path }}; {{ .Vars }} {{ .Path }}", "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} pwsh -f {{ .Path }}",
"scripts": [ "script": "./provision/core/xcode.ps1",
"./provision/core/xcode-tools.sh",
"./provision/core/xcode-sims.sh",
"./provision/core/build-xcode-symlinks.sh"
],
"environment_vars": [ "environment_vars": [
"XCODE_INSTALL_USER={{user `xcode_install_user`}}", "XCODE_INSTALL_USER={{user `xcode_install_user`}}",
"XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}" "XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}"
@@ -186,7 +182,9 @@
"./provision/core/firefox.sh", "./provision/core/firefox.sh",
"./provision/core/toolcache-high-sierra.sh", "./provision/core/toolcache-high-sierra.sh",
"./provision/core/pypy.sh", "./provision/core/pypy.sh",
"./provision/core/pipx-packages.sh" "./provision/core/pipx-packages.sh",
"./provision/core/xcode-sims.sh",
"./provision/core/build-xcode-symlinks.sh"
] ]
}, },
{ {

View File

@@ -147,11 +147,8 @@
}, },
{ {
"type": "shell", "type": "shell",
"execute_command": "chmod +x {{ .Path }}; {{ .Vars }} {{ .Path }}", "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} pwsh -f {{ .Path }}",
"scripts": [ "script": "./provision/core/xcode.ps1",
"./provision/core/xcode-tools.sh",
"./provision/core/xcode-sims.sh"
],
"environment_vars": [ "environment_vars": [
"XCODE_INSTALL_USER={{user `xcode_install_user`}}", "XCODE_INSTALL_USER={{user `xcode_install_user`}}",
"XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}" "XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}"
@@ -188,6 +185,7 @@
"./provision/core/edge.sh", "./provision/core/edge.sh",
"./provision/core/firefox.sh", "./provision/core/firefox.sh",
"./provision/core/miniconda.sh", "./provision/core/miniconda.sh",
"./provision/core/xcode-sims.sh",
"./provision/core/xcode-postbuild.sh", "./provision/core/xcode-postbuild.sh",
"./provision/core/toolcache.sh", "./provision/core/toolcache.sh",
"./provision/core/pypy.sh", "./provision/core/pypy.sh",

View File

@@ -148,8 +148,8 @@
}, },
{ {
"type": "shell", "type": "shell",
"execute_command": "chmod +x {{ .Path }}; {{ .Vars }} {{ .Path }}", "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} pwsh -f {{ .Path }}",
"script": "./provision/core/xcode-tools.sh", "script": "./provision/core/xcode.ps1",
"environment_vars": [ "environment_vars": [
"XCODE_INSTALL_USER={{user `xcode_install_user`}}", "XCODE_INSTALL_USER={{user `xcode_install_user`}}",
"XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}" "XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}"

View File

@@ -148,8 +148,8 @@
}, },
{ {
"type": "shell", "type": "shell",
"execute_command": "chmod +x {{ .Path }}; {{ .Vars }} {{ .Path }}", "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} pwsh -f {{ .Path }}",
"script": "./provision/core/xcode-tools.sh", "script": "./provision/core/xcode.ps1",
"environment_vars": [ "environment_vars": [
"XCODE_INSTALL_USER={{user `xcode_install_user`}}", "XCODE_INSTALL_USER={{user `xcode_install_user`}}",
"XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}" "XCODE_INSTALL_PASSWORD={{user `xcode_install_password`}}"

View File

@@ -2,49 +2,60 @@ Import-Module "$PSScriptRoot/../helpers/Common.Helpers.psm1"
Import-Module "$PSScriptRoot/../helpers/Xcode.Helpers.psm1" Import-Module "$PSScriptRoot/../helpers/Xcode.Helpers.psm1"
Import-Module "$PSScriptRoot/../helpers/Tests.Helpers.psm1" Import-Module "$PSScriptRoot/../helpers/Tests.Helpers.psm1"
$XCODE_VERSIONS = Get-ToolsetValue "xcode.versions" $xcodeVersions = Get-ToolsetValue "xcode.versions"
$DEFAULT_XCODE = Get-ToolsetValue "xcode.default" $defaultXcode = Get-ToolsetValue "xcode.default"
$LATEST_XCODE_VERSION = $XCODE_VERSIONS | Select-Object -First 1 $latestXcodeVersion = $xcodeVersions | Select-Object -First 1
$OS = Get-OSVersion $os = Get-OSVersion
Describe "Xcode" { Describe "Xcode" {
It "Default Xcode is $DEFAULT_XCODE" { $testCases = $xcodeVersions | ForEach-Object { @{ XcodeVersion = $_.link; LatestXcodeVersion = $xcodeVersions[0].link; Symlinks = $_.symlinks } }
"xcodebuild -version" | Should -ReturnZeroExitCode
(Get-CommandResult "xcodebuild -version").Output | Should -BeLike "Xcode $DEFAULT_XCODE*"
}
# Cut "_beta" postfix for test cases
$testCases = $XCODE_VERSIONS | ForEach-Object { @{XcodeVersion = $_.Split("_")[0] } }
Context "Versions" {
It "<XcodeVersion>" -TestCases $testCases { It "<XcodeVersion>" -TestCases $testCases {
param ( [string] $XcodeVersion )
$xcodebuildPath = Get-XcodeToolPath -Version $XcodeVersion -ToolName "xcodebuild" $xcodebuildPath = Get-XcodeToolPath -Version $XcodeVersion -ToolName "xcodebuild"
"$xcodebuildPath -version" | Should -ReturnZeroExitCode "$xcodebuildPath -version" | Should -ReturnZeroExitCode
} }
}
Context "Default" {
$defaultXcodeTestCase = @{ DefaultXcode = $defaultXcode }
It "Default Xcode is <DefaultXcode>" -TestCases $defaultXcodeTestCase {
"xcodebuild -version" | Should -ReturnZeroExitCode
(Get-CommandResult "xcodebuild -version").Output | Should -BeLike "Xcode ${DefaultXcode}*"
}
It "Xcode.app points to default Xcode" -TestCases $defaultXcodeTestCase {
$xcodeApp = "/Applications/Xcode.app"
$expectedTarget = Get-XcodeRootPath -Version $DefaultXcode
$xcodeApp | Should -Exist
$expectedTarget | Should -Exist
(Get-Item $xcodeApp).Target | Should -Be $expectedTarget
}
}
Context "Additional tools" {
It "Xcode <XcodeVersion> tools are installed" -TestCases $testCases -Skip:($os.IsHighSierra) { It "Xcode <XcodeVersion> tools are installed" -TestCases $testCases -Skip:($os.IsHighSierra) {
param ( [string] $XcodeVersion )
$TOOLS_NOT_INSTALLED_EXIT_CODE = 69 $TOOLS_NOT_INSTALLED_EXIT_CODE = 69
$xcodebuildPath = Get-XcodeToolPath -Version $XcodeVersion -ToolName "xcodebuild" $xcodebuildPath = Get-XcodeToolPath -Version $XcodeVersion -ToolName "xcodebuild"
$result = Get-CommandResult "$xcodebuildPath -checkFirstLaunchStatus" $result = Get-CommandResult "$xcodebuildPath -checkFirstLaunchStatus"
if ($XcodeVersion -ne $LATEST_XCODE_VERSION) { if ($XcodeVersion -ne $LatestXcodeVersion) {
$result.ExitCode | Should -Not -Be $TOOLS_NOT_INSTALLED_EXIT_CODE $result.ExitCode | Should -Not -Be $TOOLS_NOT_INSTALLED_EXIT_CODE
} else { } else {
$result.ExitCode | Should -BeIn (0, $TOOLS_NOT_INSTALLED_EXIT_CODE) $result.ExitCode | Should -BeIn (0, $TOOLS_NOT_INSTALLED_EXIT_CODE)
} }
} }
}
It "Xcode <XcodeVersion> has correct beta symlink" -TestCases $testCases { Context "Symlinks" {
param ( [string] $XcodeVersion ) It "Xcode <XcodeVersion> has correct symlinks" -TestCases $testCases {
$sourcePath = Get-XcodeRootPath -Version $XcodeVersion
$xcodesWithBetaSymlink = @("12", "9.3", "9.4") $Symlinks | Where-Object { $_ } | ForEach-Object {
$shouldBetaSymlinkExists = $XcodeVersion.StartsWith("10") -or $XcodeVersion.StartsWith("11") -or ($XcodeVersion -in $xcodesWithBetaSymlink) $targetPath = Get-XcodeRootPath -Version $_
$targetPath | Should -Exist
$betaSymlinkPath = Get-XcodeRootPath -Version "${XcodeVersion}_beta" (Get-Item $targetPath).Target | Should -Be $sourcePath
Test-Path $betaSymlinkPath | Should -Be $shouldBetaSymlinkExists }
}
} }
It "/Applications/Xcode* symlinks are valid" { It "/Applications/Xcode* symlinks are valid" {
@@ -54,54 +65,50 @@ Describe "Xcode" {
$_ | Should -Exist $_ | Should -Exist
} }
} }
}
Context "XCODE_DEVELOPER_DIR" { Describe "XCODE_DEVELOPER_DIR variables" {
$stableXcodeVersions = $XCODE_VERSIONS | Where-Object { $_ -notlike "*Release*Candidate*" } | ForEach-Object { $_.Split("_")[0] } | Where-Object { Test-XcodeStableRelease -Version $_ } $exactVersionsList = $xcodeVersions.link | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object {
$majorXcodeVersions = $stableXcodeVersions | ForEach-Object { $_.Split(".")[0] } | Select-Object -Unique $xcodeRootPath = Get-XcodeRootPath -Version $_
$testCases = $majorXcodeVersions | ForEach-Object { $xcodeVersionInfo = Get-XcodeVersionInfo -XcodeRootPath $xcodeRootPath
$majorXcodeVersion = $_
$expectedVersion = $stableXcodeVersions | Where-Object { $_.StartsWith("$majorXcodeVersion") } | Select-Object -First 1
return @{ return @{
MajorXcodeVersion = $majorXcodeVersion RootPath = $xcodeRootPath
ExpectedVersion = $expectedVersion Version = [SemVer]::Parse($xcodeVersionInfo.Version)
}
} }
} | Sort-Object -Property Version -Descending
$majorVersions = $exactVersionsList.Version.Major | Select-Object -Unique
$testCases = $majorVersions | ForEach-Object { @{ MajorVersion = $_; VersionsList = $exactVersionsList } }
It "XCODE_<MajorXcodeVersion>_DEVELOPER_DIR" -TestCases $testCases { It "XCODE_<MajorVersion>_DEVELOPER_DIR" -TestCases $testCases {
param ( $variableName = "XCODE_${MajorVersion}_DEVELOPER_DIR"
[string] $MajorXcodeVersion,
[string] $ExpectedVersion
)
$variableName = "XCODE_${MajorXcodeVersion}_DEVELOPER_DIR"
$actualPath = Get-EnvironmentVariable $variableName $actualPath = Get-EnvironmentVariable $variableName
$expectedPath = Join-Path (Get-XcodeRootPath -Version $ExpectedVersion) "Contents/Developer" $expectedVersion = $VersionsList | Where-Object { $_.Version.Major -eq $MajorVersion } | Select-Object -First 1
$expectedPath = "$($expectedVersion.RootPath)/Contents/Developer"
$actualPath | Should -Exist $actualPath | Should -Exist
$actualPath | Should -Be $expectedPath $actualPath | Should -Be $expectedPath
} }
} }
}
Describe "Xcode simulators" { Describe "Xcode simulators" {
$XCODE_VERSIONS | Where-Object { $_ -notlike "*Release*Candidate*" } | ForEach-Object { $_.Split("_")[0] } | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object { $xcodeVersions.link | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object {
Switch-Xcode -Version $_
Context "$_" { Context "$_" {
It "No duplicates in devices" { $testCase = @{ XcodeVersion = $_ }
It "No duplicates in devices" -TestCases $testCase {
Switch-Xcode -Version $XcodeVersion
[array]$devicesList = @(Get-XcodeDevicesList | Where-Object { $_ }) [array]$devicesList = @(Get-XcodeDevicesList | Where-Object { $_ })
Validate-ArrayWithoutDuplicates $devicesList -Because "Found duplicate device simulators" Validate-ArrayWithoutDuplicates $devicesList -Because "Found duplicate device simulators"
} }
It "No duplicates in pairs" { It "No duplicates in pairs" -TestCases $testCase {
Switch-Xcode -Version $XcodeVersion
[array]$pairsList = @(Get-XcodePairsList | Where-Object { $_ }) [array]$pairsList = @(Get-XcodePairsList | Where-Object { $_ })
Validate-ArrayWithoutDuplicates $pairsList -Because "Found duplicate pairs simulators" Validate-ArrayWithoutDuplicates $pairsList -Because "Found duplicate pairs simulators"
} }
} }
} }
AfterAll { AfterEach {
$DEFAULT_XCODE = Get-ToolsetValue "xcode.default" $defaultXcode = Get-ToolsetValue "xcode.default"
Switch-Xcode -Version $DEFAULT_XCODE Switch-Xcode -Version $defaultXcode
} }
} }

View File

@@ -1,10 +1,27 @@
# Toolset JSON structure # Toolset JSON structure
## Xcode ## Xcode
- `default` - version of Xcode to set as default - `versions` - the array of objects that will present installed Xcode versions
**Example:** `"11.2.1"` - `link` property points to the place where Xcode will be located on image. `/Applications/Xcode_<link>.app`
- `version` points to Xcode version that will be downloaded and installed
- `symlinks` describes the list of aliases where symlinks will be created to
- `default` - version of Xcode to set as default (should be metched with any `link` in `versions` property)
**Example:** `"11.2"`
- `versions` - the array of versions of Xcode to install **Note:**
**Example:** `[ "11.3", "11.2.1", "11.2", "11.1", "11" ]` - If `version` is specified with spaces, it is considered as exact Xcode name like `12.1.1 Release Candidate`.
- If `version` doesn't contain spaces, the latest version will be resolved with the following priority:
- stable version like `12.1`
- release candidate version like `12.1 Release Candidate N` (the latest N will be chosen)
- GM version like `12.1 GM Seed N` (the latest N will be chosen)
- beta version like `12.1 beta N` (the latest N will be chosen)
**Example:**
```
"versions": [
{ "link": "12.2", "version": "12.2.0" },
{ "link": "11.7", "version": "11.7.0", "symlinks": ["11.7_beta"] }
]
```
## Xamarin ## Xamarin
- `vsmac` - version of Visual Studio For Mac to install. - `vsmac` - version of Visual Studio For Mac to install.

View File

@@ -2,7 +2,19 @@
"xcode": { "xcode": {
"default": "10.1", "default": "10.1",
"versions": [ "versions": [
"10.1", "10", "9.4.1", "9.4", "9.3.1", "9.3", "9.2", "9.1", "9", "8.3.3", "8.2.1", "8.1", "8" { "link": "10.1", "version": "10.1.0", "symlinks": ["10.1_beta"] },
{ "link": "10", "version": "10.0.0", "symlinks": ["10_beta"] },
{ "link": "9.4.1", "version": "9.4.1" },
{ "link": "9.4", "version": "9.4.0", "symlinks": ["9.4_beta"] },
{ "link": "9.3.1", "version": "9.3.1" },
{ "link": "9.3", "version": "9.3.0", "symlinks": ["9.3_beta"] },
{ "link": "9.2", "version": "9.2.0" },
{ "link": "9.1", "version": "9.1.0" },
{ "link": "9", "version": "9.0.0" },
{ "link": "8.3.3", "version": "8.3.3" },
{ "link": "8.2.1", "version": "8.2.1" },
{ "link": "8.1", "version": "8.1.0" },
{ "link": "8", "version": "8.0.0" }
] ]
}, },
"xamarin": { "xamarin": {

View File

@@ -2,7 +2,18 @@
"xcode": { "xcode": {
"default": "11.3.1", "default": "11.3.1",
"versions": [ "versions": [
"11.3.1", "11.3", "11.2.1", "11.2", "11.1", "11", "10.3", "10.2.1", "10.2", "10.1", "10", "9.4.1" { "link": "11.3.1", "version": "11.3.1", "symlinks": ["11.3.1_beta"] },
{ "link": "11.3", "version": "11.3.0", "symlinks": ["11.3_beta"] },
{ "link": "11.2.1", "version": "11.2.1", "symlinks": ["11.2.1_beta"] },
{ "link": "11.2", "version": "11.2.0", "symlinks": ["11.2_beta"] },
{ "link": "11.1", "version": "11.1.0", "symlinks": ["11.1_beta"] },
{ "link": "11", "version": "11.0.0", "symlinks": ["11_beta"] },
{ "link": "10.3", "version": "10.3.0", "symlinks": ["10.3_beta"] },
{ "link": "10.2.1", "version": "10.2.1", "symlinks": ["10.2.1_beta"] },
{ "link": "10.2", "version": "10.2.0", "symlinks": ["10.2_beta"] },
{ "link": "10.1", "version": "10.1.0", "symlinks": ["10.1_beta"] },
{ "link": "10", "version": "10.0.0", "symlinks": ["10_beta"] },
{ "link": "9.4.1", "version": "9.4.1" }
] ]
}, },
"xamarin": { "xamarin": {

View File

@@ -2,7 +2,18 @@
"xcode": { "xcode": {
"default": "12", "default": "12",
"versions": [ "versions": [
"12.3_beta", "12.2", "12.1.1_Release_Candidate", "12.1", "12", "11.7", "11.6", "11.5", "11.4.1", "11.3.1", "11.2.1", "10.3" { "link": "12.3", "version": "12.3.0"},
{ "link": "12.2", "version": "12.2.0" },
{ "link": "12.1.1", "version": "12.1.1" },
{ "link": "12.1", "version": "12.1.0" },
{ "link": "12", "version": "12.0.1", "symlinks": ["12_beta"] },
{ "link": "11.7", "version": "11.7.0", "symlinks": ["11.7_beta"] },
{ "link": "11.6", "version": "11.6.0", "symlinks": ["11.6_beta"] },
{ "link": "11.5", "version": "11.5.0", "symlinks": ["11.5_beta"] },
{ "link": "11.4.1", "version": "11.4.1", "symlinks": ["11.4", "11.4.1_beta"] },
{ "link": "11.3.1", "version": "11.3.1", "symlinks": ["11.3", "11.3.1_beta"] },
{ "link": "11.2.1", "version": "11.2.1", "symlinks": ["11.2", "11.2.1_beta"] },
{ "link": "10.3", "version": "10.3", "symlinks": ["10.3_beta"] }
] ]
}, },
"xamarin": { "xamarin": {

View File

@@ -2,7 +2,9 @@
"xcode": { "xcode": {
"default": "11.7", "default": "11.7",
"versions": [ "versions": [
"12.3_beta", "12.2", "11.7" { "link": "12.3", "version": "12.3.0"},
{ "link": "12.2", "version": "12.2.0" },
{ "link": "11.7", "version": "11.7.0", "symlinks": ["11.7_beta"] }
] ]
}, },
"xamarin": { "xamarin": {