swift-version.sh 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #!/usr/bin/env bash
  2. : "${REALM_XCODE_VERSION:=}"
  3. : "${DEVELOPER_DIR:=}"
  4. get_xcode_version() {
  5. "$1" -version 2>/dev/null | sed -ne 's/^Xcode \([^\b ]*\).*/\1/p'
  6. }
  7. is_xcode_version() {
  8. test "$(get_xcode_version "$1")" = "$2"
  9. }
  10. find_xcode_with_version() {
  11. local path required_version
  12. if [ -z "$1" ]; then
  13. echo "find_xcode_with_version requires an Xcode version" >&2
  14. exit 1
  15. fi
  16. required_version=$1
  17. # First check if the currently active one is fine, unless we are in a CI run
  18. if [ -z "$JENKINS_HOME" ] && is_xcode_version xcodebuild "$required_version"; then
  19. xcode-select -p
  20. return 0
  21. fi
  22. # Check the spot where we install it on CI machines
  23. path="/Applications/Xcode-${required_version}.app/Contents/Developer"
  24. if [ -d "$path" ]; then
  25. if is_xcode_version "$path/usr/bin/xcodebuild" "$required_version"; then
  26. echo "$path"
  27. return 0
  28. fi
  29. fi
  30. # Check all of the items in /Applications that look promising per #4534
  31. for path in /Applications/Xcode*.app/Contents/Developer; do
  32. if is_xcode_version "$path/usr/bin/xcodebuild" "$required_version"; then
  33. echo "$path"
  34. return 0
  35. fi
  36. done
  37. # Use Spotlight to see if we can find others installed copies of Xcode
  38. for path in $(/usr/bin/mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'" 2>/dev/null); do
  39. path="$path/Contents/Developer"
  40. if [ ! -d "$path" ]; then
  41. continue
  42. fi
  43. if is_xcode_version "$path/usr/bin/xcodebuild" "$required_version"; then
  44. echo "$path"
  45. return 0
  46. fi
  47. done
  48. echo "No Xcode found with version $required_version" >&2
  49. exit 1
  50. }
  51. test_xcode_for_swift_version() {
  52. if [ -z "$1" ] || [ -z "$2" ]; then
  53. echo "test_xcode_for_swift_version called with empty parameter(s): '$1' or '$2'" >&2
  54. exit 1
  55. fi
  56. local path=$1
  57. local required_version=$2
  58. for swift in "$path"/Toolchains/*.xctoolchain/usr/bin/swift; do
  59. if [ "$(get_swift_version "$swift")" = "$required_version" ]; then
  60. return 0
  61. fi
  62. done
  63. return 1
  64. }
  65. find_xcode_for_swift() {
  66. local path required_version
  67. if [ -z "$1" ]; then
  68. echo "find_xcode_for_swift requires a Swift version" >&2
  69. exit 1
  70. fi
  71. required_version=$1
  72. # First check if the currently active one is fine, unless we are in a CI run
  73. if [ -z "$JENKINS_HOME" ] && test_xcode_for_swift_version "$(xcode-select -p)" "$required_version"; then
  74. DEVELOPER_DIR=$(xcode-select -p)
  75. return 0
  76. fi
  77. # Check all of the items in /Applications that look promising per #4534
  78. for path in /Applications/Xcode*.app/Contents/Developer; do
  79. if test_xcode_for_swift_version "$path" "$required_version"; then
  80. DEVELOPER_DIR=$path
  81. return 0
  82. fi
  83. done
  84. # Use Spotlight to see if we can find others installed copies of Xcode
  85. for path in $(/usr/bin/mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'" 2>/dev/null); do
  86. path="$path/Contents/Developer"
  87. if [ ! -d "$path" ]; then
  88. continue
  89. fi
  90. if test_xcode_for_swift_version "$path" "$required_version"; then
  91. DEVELOPER_DIR=$path
  92. return 0
  93. fi
  94. done
  95. echo "No version of Xcode found that supports Swift $required_version" >&2
  96. exit 1
  97. }
  98. find_default_xcode_version() {
  99. DEVELOPER_DIR="$(xcode-select -p)"
  100. # Verify that DEVELOPER_DIR points to an Xcode installation, rather than the Xcode command-line tools.
  101. if [ -x "$DEVELOPER_DIR/usr/bin/xcodebuild" ]; then
  102. # It's an Xcode installation so we're good to go.
  103. return 0
  104. fi
  105. echo "WARNING: The active Xcode command line tools, as returned by 'xcode-select -p', are not from Xcode." >&2
  106. echo " The newest version of Xcode will be used instead." >&2
  107. # Find the newest version of Xcode available on the system, based on CFBundleVersion.
  108. local xcode_version newest_xcode_version newest_xcode_path
  109. newest_xcode_version=0
  110. for path in $(/usr/bin/mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'" 2>/dev/null); do
  111. xcode_version=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$path/Contents/Info.plist")
  112. if echo "$xcode_version" "$newest_xcode_version" | awk '{exit !( $1 > $2)}'; then
  113. newest_xcode_version="$xcode_version"
  114. newest_xcode_path="$path"
  115. fi
  116. done
  117. if [ -z "$newest_xcode_path" ]; then
  118. echo "No version of Xcode could be found" >&2
  119. exit 1
  120. fi
  121. DEVELOPER_DIR="$newest_xcode_path/Contents/Developer"
  122. }
  123. set_xcode_version() {
  124. if [ -n "$REALM_XCODE_VERSION" ]; then
  125. DEVELOPER_DIR=$(find_xcode_with_version "$REALM_XCODE_VERSION")
  126. elif [ -z "$DEVELOPER_DIR" ]; then
  127. find_default_xcode_version
  128. fi
  129. export DEVELOPER_DIR
  130. # Setting this silences some seemingly spurious warnings
  131. export XCODE_DEVELOPER_DIR_PATH="$DEVELOPER_DIR"
  132. REALM_XCODE_VERSION="$(get_xcode_version "$DEVELOPER_DIR/usr/bin/xcodebuild")"
  133. export REALM_XCODE_VERSION
  134. }
  135. return 2>/dev/null || { # only run if called directly
  136. set_xcode_version
  137. echo "Found Xcode version $REALM_XCODE_VERSION at $DEVELOPER_DIR"
  138. }