#!/bin/bash -e set -o pipefail FAIL= PROVISION_DOWNLOAD_DIR=/tmp/x-provisioning # parse command-line arguments while ! test -z $1; do case $1 in --provision-xcode) PROVISION_XCODE=1 shift ;; --provision) # historical reasons :( PROVISION_XCODE=1 PROVISION_XS=1 shift ;; --provision-xamarin-studio) PROVISION_XS=1 shift ;; --provision-mono) PROVISION_MONO=1 shift ;; --provision-all) PROVISION_MONO=1 PROVISION_XS=1 PROVISION_XCODE=1 shift ;; *) echo "Unknown argument: $1" exit 1 ;; esac done # reporting functions function fail () { tput setaf 1 2>/dev/null || true echo " $1" tput sgr0 2>/dev/null || true FAIL=1 } function ok () { echo " $1" } function log () { echo " $1" } # $1: the version to check # $2: the minimum version to check against function is_at_least_version () { ACT_V=$1 MIN_V=$2 if [[ "$ACT_V" == "$MIN_V" ]]; then return 0 fi IFS=. read -a V_ACT <<< "$ACT_V" IFS=. read -a V_MIN <<< "$MIN_V" # get the minimum # of elements AC=${#V_ACT[@]} MC=${#V_MIN[@]} COUNT=$(($AC>$MC?$MC:$AC)) C=0 while (( $C < $COUNT )); do ACT=${V_ACT[$C]} MIN=${V_MIN[$C]} if (( $ACT > $MIN )); then return 0 elif (( "$MIN" > "$ACT" )); then return 1 fi let C++ done if (( $AC == $MC )); then # identical? return 0 fi if (( $AC > $MC )); then # more version fields in actual than min: OK return 0 elif (( $AC == $MC )); then # entire strings aren't equal (first check in function), but each individual field is? return 0 else # more version fields in min than actual (1.0 vs 1.0.1 for instance): not OK return 1 fi } function install_mono () { local MONO_URL=`grep MIN_MONO_URL= Make.config | sed 's/.*=//'` local MIN_MONO_VERSION=`grep MIN_MONO_VERSION= Make.config | sed 's/.*=//'` if test -z $MONO_URL; then fail "No MIN_MONO_URL set in Make.config, cannot provision" return fi mkdir -p $PROVISION_DOWNLOAD_DIR log "Downloading Mono $MIN_MONO_VERSION from $MONO_URL to $PROVISION_DOWNLOAD_DIR..." local MONO_NAME=`basename $MONO_URL` local MONO_PKG=$PROVISION_DOWNLOAD_DIR/$MONO_NAME curl -L $MONO_URL > $MONO_PKG log "Installing Mono $MIN_MONO_VERSION from $MONO_URL..." sudo installer -pkg $MONO_PKG -target / rm -f $MONO_PKG } function install_xamarin_studio () { local XS="/Applications/Xamarin Studio.app" local XS_URL=`grep MIN_XAMARIN_STUDIO_URL= Make.config | sed 's/.*=//'` local MIN_XAMARIN_STUDIO_VERSION=`grep MIN_XAMARIN_STUDIO_VERSION= Make.config | sed 's/.*=//'` if test -z $XS_URL; then fail "No MIN_XAMARIN_STUDIO_URL set in Make.config, cannot provision" return fi mkdir -p $PROVISION_DOWNLOAD_DIR log "Downloading Xamarin Studio $MIN_XAMARIN_STUDIO_VERSION from $XS_URL to $PROVISION_DOWNLOAD_DIR..." local XS_NAME=`basename $XS_URL` local XS_DMG=$PROVISION_DOWNLOAD_DIR/$XS_NAME curl -L $XS_URL > $XS_DMG local XS_MOUNTPOINT=$PROVISION_DOWNLOAD_DIR/$XS_NAME-mount log "Mounting $XS_DMG into $XS_MOUNTPOINT..." hdiutil attach $XS_DMG -mountpoint $XS_MOUNTPOINT -quiet -nobrowse log "Removing previous Xamarin Studio from $XS" sudo rm -Rf "$XS" log "Installing Xamarin Studio $MIN_XAMARIN_STUDIO_VERSION to $XS..." sudo cp -R "$XS_MOUNTPOINT/Xamarin Studio.app" /Applications log "Unmounting $XS_DMG..." hdiutil detach $XS_MOUNTPOINT -quiet XS_ACTUAL_VERSION=`/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$XS/Contents/Info.plist"` ok "Xamarin Studio $XS_ACTUAL_VERSION provisioned" rm -f $XS_DMG } function install_specific_xcode () { local XCODE_URL=`grep XCODE$1_URL= Make.config | sed 's/.*=//'` local XCODE_VERSION=`grep XCODE$1_VERSION= Make.config | sed 's/.*=//'` local XCODE_ROOT=$(dirname `dirname $XCODE_DEVELOPER_ROOT`) if test -z $XCODE_URL; then fail "No XCODE$1_URL set in Make.config, cannot provision" return fi mkdir -p $PROVISION_DOWNLOAD_DIR log "Downloading Xcode $XCODE_VERSION from $XCODE_URL to $PROVISION_DOWNLOAD_DIR..." local XCODE_NAME=`basename $XCODE_URL` local XCODE_DMG=$PROVISION_DOWNLOAD_DIR/$XCODE_NAME curl -L $XCODE_URL > $XCODE_DMG if [[ ${XCODE_DMG: -4} == ".dmg" ]]; then local XCODE_MOUNTPOINT=$PROVISION_DOWNLOAD_DIR/$XCODE_NAME-mount log "Mounting $XCODE_DMG into $XCODE_MOUNTPOINT..." hdiutil attach $XCODE_DMG -mountpoint $XCODE_MOUNTPOINT -quiet -nobrowse log "Removing previous Xcode from $XCODE_ROOT" rm -Rf $XCODE_ROOT log "Installing Xcode $XCODE_VERSION to $XCODE_ROOT..." cp -R $XCODE_MOUNTPOINT/*.app $XCODE_ROOT log "Unmounting $XCODE_DMG..." hdiutil detach $XCODE_MOUNTPOINT -quiet elif [[ ${XCODE_DMG: -4} == ".xip" ]]; then mkdir $PROVISION_DOWNLOAD_DIR/$XCODE_NAME-decompressed pushd . cd $PROVISION_DOWNLOAD_DIR/$XCODE_NAME-decompressed log "Decompressing $XCODE_DMG..." xar -x -f $XCODE_DMG log "Extracting $XCODE_DMG..." # the cpio command spews a lot of "Can't create ..." errors, but they seem to be innocuous gunzip < Content | cpio -i -d log "Installing Xcode $XCODE_VERSION to $XCODE_ROOT..." mv *.app $XCODE_ROOT popd rm -Rf $PROVISION_DOWNLOAD_DIR/$XCODE_NAME-decompressed else fail "Don't know how to install $XCODE_DMG" fi rm -f $XCODE_DMG log "Removing any com.apple.quarantine attributes from the installed Xcode" sudo xattr -d -r com.apple.quarantine $XCODE_ROOT if is_at_least_version $XCODE_VERSION 5.0; then log "Accepting Xcode license" sudo $XCODE_DEVELOPER_ROOT/usr/bin/xcodebuild -license accept fi log "Executing 'sudo xcode-select -s $XCODE_DEVELOPER_ROOT'" sudo xcode-select -s $XCODE_DEVELOPER_ROOT ok "Xcode $XCODE_VERSION provisioned" } function check_specific_xcode () { local XCODE_DEVELOPER_ROOT=`grep XCODE$1_DEVELOPER_ROOT= Make.config | sed 's/.*=//'` local XCODE_VERSION=`grep XCODE$1_VERSION= Make.config | sed 's/.*=//'` local XCODE_ROOT=$(dirname `dirname $XCODE_DEVELOPER_ROOT`) local ENABLE_XAMARIN=$(grep -s ^ENABLE_XAMARIN= Make.config.local configure.inc | sed 's/.*=//') if ! test -d $XCODE_DEVELOPER_ROOT; then if ! test -z $PROVISION_XCODE; then if ! test -z $ENABLE_XAMARIN; then install_specific_xcode $1 else fail "Automatic provisioning of Xcode is only supported for provisioning internal build bots." fail "Please download and install Xcode $XCODE_VERSION here: https://developer.apple.com/downloads/index.action?name=Xcode" fi else fail "You must install Xcode ($XCODE_VERSION) in $XCODE_ROOT. You can download Xcode $XCODE_VERSION here: https://developer.apple.com/downloads/index.action?name=Xcode" fi return else if is_at_least_version $XCODE_VERSION 5.0; then if ! $XCODE_DEVELOPER_ROOT/usr/bin/xcodebuild -license check >/dev/null 2>&1; then if ! test -z $PROVISION_XCODE; then sudo $XCODE_DEVELOPER_ROOT/usr/bin/xcodebuild -license accept else fail "The license for Xcode $XCODE_VERSION has not been accepted. Execute 'sudo $XCODE_DEVELOPER_ROOT/usr/bin/xcodebuild' to review the license and accept it." fi return fi fi fi local XCODE_ACTUAL_VERSION=`/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$XCODE_DEVELOPER_ROOT/../version.plist"` # this is a hard match, having 4.5 when requesting 4.4 is not OK (but 4.4.1 is OK) if [[ ! "x$XCODE_ACTUAL_VERSION" =~ "x$XCODE_VERSION" ]]; then fail "You must install Xcode $XCODE_VERSION in $XCODE_ROOT (found $XCODE_ACTUAL_VERSION). You can download Xcode $XCODE_VERSION here: https://developer.apple.com/downloads/index.action?name=Xcode"; return fi local XCODE_SELECT=$(xcode-select -p) if [[ "x$XCODE_SELECT" != "x$XCODE_DEVELOPER_ROOT" ]]; then if ! test -z $PROVISION_XCODE; then log "Executing 'sudo xcode-select -s $XCODE_DEVELOPER_ROOT'" sudo xcode-select -s $XCODE_DEVELOPER_ROOT else fail "'xcode-select -p' does not point to $XCODE_DEVELOPER_ROOT, it points to $XCODE_SELECT. Execute 'sudo xcode-select -s $XCODE_DEVELOPER_ROOT' to fix." fi fi ok "Found Xcode $XCODE_ACTUAL_VERSION in $XCODE_ROOT" } function check_xcode () { # must have latest Xcode in /Applications/Xcode.app check_specific_xcode local XCODE_DEVELOPER_ROOT=`grep ^XCODE_DEVELOPER_ROOT= Make.config | sed 's/.*=//'` local IOS_SDK_VERSION=`grep ^IOS_SDK_VERSION= Make.config | sed 's/.*=//'` local OSX_SDK_VERSION=`grep ^OSX_SDK_VERSION= Make.config | sed 's/.*=//'` local WATCH_SDK_VERSION=`grep ^WATCH_SDK_VERSION= Make.config | sed 's/.*=//'` local TVOS_SDK_VERSION=`grep ^TVOS_SDK_VERSION= Make.config | sed 's/.*=//'` local D=$XCODE_DEVELOPER_ROOT/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${IOS_SDK_VERSION}.sdk if test ! -d $D -a -z "$FAIL"; then fail "The directory $D does not exist. If you've updated the Xcode location it means you also need to update IOS_SDK_VERSION in Make.config." fi local D=$XCODE_DEVELOPER_ROOT/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${OSX_SDK_VERSION}.sdk if test ! -d $D -a -z "$FAIL"; then fail "The directory $D does not exist. If you've updated the Xcode location it means you also need to update OSX_SDK_VERSION in Make.config." fi local D=$XCODE_DEVELOPER_ROOT/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS${TVOS_SDK_VERSION}.sdk if test ! -d $D -a -z "$FAIL"; then fail "The directory $D does not exist. If you've updated the Xcode location it means you also need to update TVOS_SDK_VERSION in Make.config." fi local D=$XCODE_DEVELOPER_ROOT/Platforms/WatchOS.platform/Developer/SDKs/WatchOS${WATCH_SDK_VERSION}.sdk if test ! -d $D -a -z "$FAIL"; then fail "The directory $D does not exist. If you've updated the Xcode location it means you also need to update WATCH_SDK_VERSION in Make.config." fi } function check_mono () { PKG_CONFIG_PATH=/Library/Frameworks/Mono.framework/Versions/Current/bin/pkg-config if ! /Library/Frameworks/Mono.framework/Commands/mono --version 2>/dev/null >/dev/null; then if ! test -z $PROVISION_MONO; then install_mono else fail "You must install the Mono MDK (http://www.mono-project.com/download/)" return fi elif ! test -e $PKG_CONFIG_PATH; then if ! test -z $PROVISION_MONO; then install_mono else fail "Could not find pkg-config, you must install the Mono MDK (http://www.mono-project.com/download/)" return fi fi MIN_MONO_VERSION=`grep MIN_MONO_VERSION= Make.config | sed 's/.*=//'` MAX_MONO_VERSION=`grep MAX_MONO_VERSION= Make.config | sed 's/.*=//'` ACTUAL_MONO_VERSION=`$PKG_CONFIG_PATH --modversion mono`.`cat /Library/Frameworks/Mono.framework/Home/updateinfo | cut -d' ' -f2 | rev | cut -c-3 | rev | awk '{print(int($0))}'` if ! is_at_least_version $ACTUAL_MONO_VERSION $MIN_MONO_VERSION; then if ! test -z $PROVISION_MONO; then install_mono ACTUAL_MONO_VERSION=`$PKG_CONFIG_PATH --modversion mono` else fail "You must have at least Mono $MIN_MONO_VERSION, found $ACTUAL_MONO_VERSION" return fi elif [[ "$ACTUAL_MONO_VERSION" == "$MAX_MONO_VERSION" ]]; then : # this is ok elif is_at_least_version $ACTUAL_MONO_VERSION $MAX_MONO_VERSION; then if ! test -z $PROVISION_MONO; then install_mono ACTUAL_MONO_VERSION=`$PKG_CONFIG_PATH --modversion mono`.`cat /Library/Frameworks/Mono.framework/Home/updateinfo | cut -d' ' -f2 | rev | cut -c-3 | rev | awk '{print(int($0))}'` else fail "Your mono version is too new, max version is $MAX_MONO_VERSION, found $ACTUAL_MONO_VERSION." fail "You may edit Make.config and change MAX_MONO_VERSION to your actual version to continue the" fail "build (unless you're on a release branch). Once the build completes successfully, please" fail "commit the new MAX_MONO_VERSION value." return fi fi ok "Found Mono $ACTUAL_MONO_VERSION (at least $MIN_MONO_VERSION and not more than $MAX_MONO_VERSION is required)" } function check_autotools () { IFStmp=$IFS IFS=' ' if AUTOCONF_VERSION=($(autoconf --version 2>/dev/null)); then ok "Found ${AUTOCONF_VERSION[0]} (no specific version is required)" else fail "You must install autoconf, read the README.md for instructions" fi if ! LIBTOOL=$(which glibtool 2>/dev/null); then LIBTOOL=$(which libtool) fi if ! LIBTOOL_VERSION=($($LIBTOOL --version 2>/dev/null )); then fail "You must install libtool, read the README.md for instructions" else ok "Found ${LIBTOOL_VERSION[0]} (no specific version is required)" fi if ! AUTOMAKE_VERSION=($(automake --version 2>/dev/null)); then fail "You must install automake, read the README.md for instructions" else ok "Found ${AUTOMAKE_VERSION[0]} (no specific version is required)" fi IFS=$IFS_tmp } function check_xamarin_studio () { XS="/Applications/Xamarin Studio.app" local XS_URL=`grep MIN_XAMARIN_STUDIO_URL= Make.config | sed 's/.*=//'` if ! test -d "$XS"; then if ! test -z $PROVISION_XS; then install_xamarin_studio else fail "You must install Xamarin Studio, from http://www.monodevelop.com/download/" fi return fi MIN_XAMARIN_STUDIO_VERSION=`grep MIN_XAMARIN_STUDIO_VERSION= Make.config | sed 's/.*=//'` MAX_XAMARIN_STUDIO_VERSION=`grep MAX_XAMARIN_STUDIO_VERSION= Make.config | sed 's/.*=//'` XS_ACTUAL_VERSION=`/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$XS/Contents/Info.plist"` if ! is_at_least_version $XS_ACTUAL_VERSION $MIN_XAMARIN_STUDIO_VERSION; then if ! test -z $PROVISION_XS; then install_xamarin_studio XS_ACTUAL_VERSION=`/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$XS/Contents/Info.plist"` else fail "You must have at least Xamarin Studio $MIN_XAMARIN_STUDIO_VERSION (found $XS_ACTUAL_VERSION). Download URL: $XS_URL" fi return elif [[ "$XS_ACTUAL_VERSION" == "$MAX_XAMARIN_STUDIO_VERSION" ]]; then : # this is ok elif is_at_least_version $XS_ACTUAL_VERSION $MAX_XAMARIN_STUDIO_VERSION; then if ! test -z $PROVISION_XS; then install_xamarin_studio XS_ACTUAL_VERSION=`/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$XS/Contents/Info.plist"` else fail "Your Xamarin Studio version is too new, max version is $MAX_XAMARIN_STUDIO_VERSION, found $XS_ACTUAL_VERSION." fail "You may edit Make.config and change MAX_XAMARIN_STUDIO_VERSION to your actual version to continue the" fail "build (unless you're on a release branch). Once the build completes successfully, please" fail "commit the new MAX_XAMARIN_STUDIO_VERSION value." fail "Alternatively you can download an older version from $XS_URL." fi return fi ok "Found Xamarin Studio $XS_ACTUAL_VERSION (at least $MIN_XAMARIN_STUDIO_VERSION and not more than $MAX_XAMARIN_STUDIO_VERSION is required)" } function check_osx_version () { MIN_OSX_BUILD_VERSION=`grep MIN_OSX_BUILD_VERSION= Make.config | sed 's/.*=//'` ACTUAL_OSX_VERSION=$(sw_vers -productVersion) if ! is_at_least_version $ACTUAL_OSX_VERSION $MIN_OSX_BUILD_VERSION; then fail "You must have at least OSX $MIN_OSX_BUILD_VERSION (found $ACTUAL_OSX_VERSION)" return fi ok "Found OSX $ACTUAL_OSX_VERSION (at least $MIN_OSX_BUILD_VERSION is required)" } echo "Checking system..." check_osx_version check_xcode check_autotools check_mono check_xamarin_studio if test -z $FAIL; then echo "System check succeeded" else echo "System check failed" exit 1 fi