swift-version.sh 5.4 KB

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