Fix Xcode 11.3.1 detection in an Xcode workspace
When using a Tulsi-generated project by itself in Xcode 11.3.1, Xcode
sets XCODE_VERSION_ACTUAL to 1131, which Tulsi parses correctly to get
the version 11.3.1.
But when used in an Xcode workspace, Xcode sets XCODE_VERSION_ACTUAL
to 1130, leading to Tulsi parsing 11.3 as the version, and later
attempts to use a non-existing version of Xcode to build, which results
in an error.
Fix by ignoring XCODE_VERSION_ACTUAL because it's unreliable; instead,
parse Xcode's version.plist to read the 'CFBundleShortVersionString'
entry, which seems to return correct results.
Caveat: this implementation uses plistlib, which has a slightly
different API in python2 and python3. This change uses the python2 API,
and will need to be updated to work with python3 in the future.
PiperOrigin-RevId: 315886285
diff --git a/src/TulsiGenerator/Scripts/bazel_build.py b/src/TulsiGenerator/Scripts/bazel_build.py
index f741b50..0723f7e 100755
--- a/src/TulsiGenerator/Scripts/bazel_build.py
+++ b/src/TulsiGenerator/Scripts/bazel_build.py
@@ -25,6 +25,7 @@
import json
import os
import pipes
+import plistlib
import re
import shutil
import signal
@@ -340,17 +341,39 @@
@staticmethod
def _GetXcodeVersionString():
- """Returns Xcode version info from the environment as a string."""
- reported_version = os.environ['XCODE_VERSION_ACTUAL']
- match = re.match(r'(\d{2})(\d)(\d)$', reported_version)
- if not match:
- _PrintUnbuffered('Warning: Failed to extract Xcode version from %s' % (
- reported_version))
+ """Returns Xcode version info from the Xcode's version.plist.
+
+ Just reading XCODE_VERSION_ACTUAL from the environment seems like
+ a more reasonable implementation, but has shown to be unreliable,
+ at least when using Xcode 11.3.1 and opening the project within an
+ Xcode workspace.
+ """
+ developer_dir = os.environ['DEVELOPER_DIR']
+ app_dir = developer_dir.split('.app')[0] + '.app'
+ version_plist_path = os.path.join(app_dir, 'Contents', 'version.plist')
+ try:
+ # python2 API to plistlib - needs updating if/when Tulsi bumps to python3
+ plist = plistlib.readPlist(version_plist_path)
+ except IOError:
+ _PrintXcodeWarning('Tulsi cannot determine Xcode version, error '
+ 'reading from {}'.format(version_plist_path))
return None
- major_version = int(match.group(1))
- minor_version = int(match.group(2))
- fix_version = int(match.group(3))
- return '%d.%d.%d' % (major_version, minor_version, fix_version)
+ try:
+ # Example: "11.3.1", "11.3", "11.0"
+ key = 'CFBundleShortVersionString'
+ version_string = plist[key]
+ except KeyError:
+ _PrintXcodeWarning('Tulsi cannot determine Xcode version from {}, no '
+ '"{}" key'.format(version_plist_path, key))
+ return None
+
+ # But we need to normalize to major.minor.patch, e.g. 11.3.0 or
+ # 11.0.0, so add one or two ".0" if needed (two just in case
+ # there is ever just a single version number like "12")
+ dots_count = version_string.count('.')
+ dot_zeroes_to_add = 2 - dots_count
+ version_string += '.0' * dot_zeroes_to_add
+ return version_string
@staticmethod
def _ComputeXcodeVersionFlag():