Skip to content

Instantly share code, notes, and snippets.

@NorseGaud
Last active December 19, 2022 20:15
Show Gist options
  • Save NorseGaud/7fbb7d5526abb43a6f81b3c3c8399e98 to your computer and use it in GitHub Desktop.
Save NorseGaud/7fbb7d5526abb43a6f81b3c3c8399e98 to your computer and use it in GitHub Desktop.
Xcode Installer Script, pulling from a remote server that stores the xip files
#!/usr/bin/env bash
set -exo pipefail
# IMPORTANT!!
# SET THESE TWO
XCODE_STORAGE_SERVER_IP="xxx.xxx.xxx.xxx"
XCODE_STORAGE_SERVER_USERNAME=""
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "${SCRIPT_DIR}"
if [[ -z "$(command -v unxip)" ]]; then
sudo mkdir -p /usr/local/bin
pushd /usr/local/bin
sudo curl -O -L https://github.com/saagarjha/unxip/releases/download/v1.1.1/unxip
sudo chmod +x unxip
popd
fi
XCODE_VERSION=
XCODE_DESTINATION="/Applications"
if [[ -z "${SHORT_MACOS_VERSION}" ]]; then
SHORT_MACOS_VERSION="$(sw_vers -productVersion)"
fi
if [[ -d "${XCODE_DESTINATION}/Xcode.app" ]]; then
echo "Xcode.app exists already!"
exit
fi
# Install the latest xcode
function test_version() {
MIN_VERSION="${1}"
MACOS_VERSION="${2}"
MIN_VERSION_MAJOR="$(echo $MIN_MACOS_VERSION | cut -d. -f1)"
MIN_VERSION_MINOR="$(echo $MIN_MACOS_VERSION | cut -d. -f2)"
MIN_VERSION_PATCH="$(echo $MIN_MACOS_VERSION | cut -d. -f3)"
MACOS_VERSION_MAJOR="$(echo $MACOS_VERSION | cut -d. -f1)"
MACOS_VERSION_MINOR="$(echo $MACOS_VERSION | cut -d. -f2)"
MACOS_VERSION_PATCH="$(echo $MACOS_VERSION | cut -d. -f3)"
[[ $MACOS_VERSION_MAJOR -ne $MIN_VERSION_MAJOR ]] && return 1
[[ "${MIN_VERSION}" == "${MACOS_VERSION}" ]] && return 0
[[ ! "${MACOS_VERSION}" =~ \. ]] && return 1
## Support when min version is just a few minor versions less than
[[
$MACOS_VERSION_MAJOR -eq $MIN_VERSION_MAJOR \
&& $MACOS_VERSION_MINOR -ge $MIN_VERSION_MINOR \
&& $MACOS_VERSION_PATCH -ge $MIN_VERSION_PATCH \
]] && return 0
MACOS_VERSION="${MACOS_VERSION%.*}"
test_version "${MIN_VERSION}" "${MACOS_VERSION}" \
&& return 0 \
|| return 1
}
function download_xcode_xip() {
if [[ -n "${1}" ]]; then
XCODE_VERSION="${1}"
else # get latest xcode from server
LATEST_XCODE="$(ssh -o "StrictHostKeyChecking=no" -o BatchMode=yes ${XCODE_STORAGE_SERVER_USERNAME}@$XCODE_STORAGE_SERVER_IP ls -t _xcode-xips/ | head -1)"
XCODE_VERSION="$(echo ${LATEST_XCODE} | cut -d_ -f2 | sed 's/.xip//g')"
fi
ENDING="$(echo $XCODE_VERSION | rev | cut -d. -f1 | rev)"
[ $ENDING -lt 0 ] && return 1
if ssh -o "StrictHostKeyChecking=no" -o BatchMode=yes ${XCODE_STORAGE_SERVER_USERNAME}@$XCODE_STORAGE_SERVER_IP ls _xcode-xips/Xcode_${XCODE_VERSION}.xip; then
pushd ${XCODE_DESTINATION} &>/dev/null
echo "found Xcode_${XCODE_VERSION}.xip on $XCODE_STORAGE_SERVER_IP"
echo "${XCODE_VERSION}" > /Applications/XCODE_VERSION
rsync -e 'ssh -o BatchMode=yes -o StrictHostKeyChecking=no' -avzP ${XCODE_STORAGE_SERVER_USERNAME}@$XCODE_STORAGE_SERVER_IP:_xcode-xips/Xcode_${XCODE_VERSION}.xip ./ && return 0
popd &>/dev/null
return 1
else
if [ "$(echo ${XCODE_VERSION} | grep -o "\." | wc -l | xargs)" -eq 1 ]; then
ENDING=9
NO_ENDING=true
XCODE_VERSION="${XCODE_VERSION}.${ENDING}"
else
if $NO_ENDING; then
XCODE_VERSION="$(echo $XCODE_VERSION | sed 's/.[0-9]$//')"
XCODE_VERSION="${XCODE_VERSION}.$(($ENDING-1))"
fi
fi
fi
[ "$(echo ${XCODE_VERSION} | grep -o "\." | wc -l | xargs)" -eq 0 ] && return 1
download_xcode_xip "${XCODE_VERSION}" \
&& return 0 \
|| return 1
}
##################
# Get list of Xcode versions and their minimum MacOS version so we can match the proper versions to install
set +x
HTML_TABLE="$(echo "$(curl -s https://developer.apple.com/support/xcode/)" | sed -n '/<tbody/,/tbody>/p')"
OUTPUT=()
TR=false
COUNT=0
oldIFS="${IFS}"
IFS=$'\n'
VERSION=()
function join_by { local IFS="$1"; shift; echo "$*"; }
for line in $(echo "${HTML_TABLE}"); do
line=$(echo "${line}" | xargs)
if [[ "<tr>" =~ "${line}" ]]; then
TR=true
continue
fi
if $TR; then
if [ $COUNT -lt 2 ]; then
sanline=$(echo "${line}" | sed 's/[^0-9.]*\([0-9.x]*\).*/\1/')
VERSION+=($sanline)
[ $COUNT -eq 1 ] && OUTPUT+=($(join_by , "${VERSION[@]}"))
fi
((COUNT+=1))
fi
if [[ "</tr>" =~ "${line}" ]]; then
TR=false
VERSION=()
COUNT=0
fi
done
IFS="${oldIFS}"
# echo -n "XCODE, Min MacOS Version"
set -x
MATCH=false
for versions in ${OUTPUT[*]}; do
NO_ENDING=false
XCODE_VERSION=$(echo $versions | cut -d, -f1 | sed 's/\.x$//')
MIN_MACOS_VERSION=$(echo $versions | cut -d, -f2)
if test_version "${MIN_MACOS_VERSION}" "${SHORT_MACOS_VERSION}"; then
MATCH=true
echo "${SHORT_MACOS_VERSION}"
if ! download_xcode_xip "${XCODE_VERSION}"; then
continue
else
echo "downloaded!"
break
fi
fi
done
# Handle if the current MacOS version wasn't found on Apple's page
if ! $MATCH; then
if ! download_xcode_xip; then
echo "failure to download latest Xcode"
exit 1
else
echo "downloaded!"
fi
fi
# XCODE_VERSION is available for you to interpolate onto the Xcode.app if you need to have multiple versions on the same host.
pushd "${XCODE_DESTINATION}"
if ! ls ./*.xip; then
echo "No installer found..."
exit 1
fi
unxip *.xip || xip --expand *.xip
sudo xattr -r -d com.apple.quarantine Xcode.app
popd
sudo /usr/sbin/dseditgroup -o edit -a everyone -t group _developer
sudo xcode-select -s ${XCODE_DESTINATION}/Xcode.app/Contents/Developer
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch
sudo DevToolsSecurity -enable
for PKG in $(/bin/ls ${XCODE_DESTINATION}/Xcode.app/Contents/Resources/Packages/*.pkg); do
sudo /usr/sbin/installer -pkg "$PKG" -target /
done
sudo rm -f "${XCODE_DESTINATION}/*.xip"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment